getData(); // In the config data is encoded stored to avoid corruption. $this->hmacKey = base64_decode($vars['SecurityHmacKey']); // Equivalent of "hex2bin" for PHP < 5.4. $this->encryptionKey = pack('H*', $vars['SecurityEncryptionKey']); } /** * Creates signature. * * @param string $string String. * @param boolean $raw_output Return raw signature version. * @param string|null $key_override Override key. * * @return string */ public function createSignature($string, $raw_output = false, $key_override = null) { return hash_hmac(self::HASHING_ALGORITHM, $string, $this->_getHmacKey($key_override), $raw_output); } /** * Returns HMAC key. * * @param string|null $key_override Key override. * * @return string * @throws InvalidArgumentException When HMAC key is empty. */ private function _getHmacKey($key_override = null) { $key = $this->doGetHmacKey($key_override); if ( empty($key) ) { throw new InvalidArgumentException('The HMAC key is empty.'); } if ( mb_strlen($key, '8bit') === self::HASHING_KEY_LENGTH ) { return $key; } return $this->deriveKey($key, self::HASHING_KEY_LENGTH); } /** * Returns HMAC key. * * @param string|null $key_override Key override. * * @return string */ protected function doGetHmacKey($key_override = null) { return isset($key_override) ? $key_override : $this->hmacKey; } /** * Returns encryption key. * * @param string|null $key_override Key override. * * @return string * @throws InvalidArgumentException When encryption key is empty. */ private function _getEncryptionKey($key_override = null) { $key = $this->doGetEncryptionKey($key_override); if ( empty($key) ) { throw new InvalidArgumentException('The encryption key is empty.'); } if ( mb_strlen($key, '8bit') === self::ENCRYPTION_KEY_LENGTH ) { return $key; } return $this->deriveKey($key, self::ENCRYPTION_KEY_LENGTH); } /** * Returns encryption key. * * @param string|null $key_override Key override. * * @return string */ protected function doGetEncryptionKey($key_override = null) { return isset($key_override) ? $key_override : $this->encryptionKey; } /** * Derives given key. * * @param string $key Key. * @param integer $length Length. * * @return string */ final public function deriveKey($key, $length) { $salt = SecurityGenerator::generateBytes(16, true); return hash_pbkdf2(self::HASHING_ALGORITHM, $key, $salt, 80000, $length, true); } /** * Encrypts a plain text. * * @param string $plaintext Plain text. * @param string|null $key_override Key override. * * @return string */ final public function encrypt($plaintext, $key_override = null) { $iv_size = openssl_cipher_iv_length(self::ENCRYPTION_METHOD); $iv = openssl_random_pseudo_bytes($iv_size); $ciphertext = openssl_encrypt( $plaintext, self::ENCRYPTION_METHOD, $this->_getEncryptionKey($key_override), OPENSSL_RAW_DATA, $iv ); // Note: We cover the IV in our HMAC. $hmac = $this->createSignature($iv . $ciphertext, true); return base64_encode($hmac . $iv . $ciphertext); } /** * Decrypts a cipher text. * * @param string $ciphertext Cipher text. * @param string|null $key_override Key override. * * @return string|false * @throws LogicException When signature verification has failed. */ final public function decrypt($ciphertext, $key_override = null) { $iv_size = openssl_cipher_iv_length(self::ENCRYPTION_METHOD); $decoded = base64_decode($ciphertext); $hmac = mb_substr($decoded, 0, self::HASHING_KEY_LENGTH, '8bit'); $iv = mb_substr($decoded, self::HASHING_KEY_LENGTH, $iv_size, '8bit'); $ciphertext = mb_substr($decoded, self::HASHING_KEY_LENGTH + $iv_size, null, '8bit'); $calculated = $this->createSignature($iv . $ciphertext, true); if ( !hash_equals($hmac, $calculated) ) { throw new LogicException('Signature verification of ciphertext failed.'); } return openssl_decrypt( $ciphertext, self::ENCRYPTION_METHOD, $this->_getEncryptionKey($key_override), OPENSSL_RAW_DATA, $iv ); } /** * Determines if used cipher is available. * * @return boolean */ final public function cipherAvailable() { return in_array(self::ENCRYPTION_METHOD, openssl_get_cipher_methods(), true); } }