rijndael($text, $key, $operation); } /** * Encrypt a value using AES-256. * * *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes. * Any trailing null bytes will be removed on decryption due to how PHP pads messages * with nulls prior to encryption. * * @param string $plain The value to encrypt. * @param string $key The 256 bit/32 byte key to use as a cipher key. * @param string|null $hmacSalt The salt to use for the HMAC process. Leave null to use Security.salt. * @return string Encrypted data. * @throws \InvalidArgumentException On invalid data or key. */ public static function encrypt($plain, $key, $hmacSalt = null) { self::_checkKey($key, 'encrypt()'); if ($hmacSalt === null) { $hmacSalt = static::$_salt; } // Generate the encryption and hmac key. $key = mb_substr(hash('sha256', $key . $hmacSalt), 0, 32, '8bit'); $crypto = static::engine(); $ciphertext = $crypto->encrypt($plain, $key); $hmac = hash_hmac('sha256', $ciphertext, $key); return $hmac . $ciphertext; } /** * Check the encryption key for proper length. * * @param string $key Key to check. * @param string $method The method the key is being checked for. * @return void * @throws \InvalidArgumentException When key length is not 256 bit/32 bytes */ protected static function _checkKey($key, $method) { if (mb_strlen($key, '8bit') < 32) { throw new InvalidArgumentException( sprintf('Invalid key for %s, key must be at least 256 bits (32 bytes) long.', $method) ); } } /** * Decrypt a value using AES-256. * * @param string $cipher The ciphertext to decrypt. * @param string $key The 256 bit/32 byte key to use as a cipher key. * @param string|null $hmacSalt The salt to use for the HMAC process. Leave null to use Security.salt. * @return string|false Decrypted data. Any trailing null bytes will be removed. * @throws \InvalidArgumentException On invalid data or key. */ public static function decrypt($cipher, $key, $hmacSalt = null) { self::_checkKey($key, 'decrypt()'); if (empty($cipher)) { throw new InvalidArgumentException('The data to decrypt cannot be empty.'); } if ($hmacSalt === null) { $hmacSalt = static::$_salt; } // Generate the encryption and hmac key. $key = mb_substr(hash('sha256', $key . $hmacSalt), 0, 32, '8bit'); // Split out hmac for comparison $macSize = 64; $hmac = mb_substr($cipher, 0, $macSize, '8bit'); $cipher = mb_substr($cipher, $macSize, null, '8bit'); $compareHmac = hash_hmac('sha256', $cipher, $key); if (!static::constantEquals($hmac, $compareHmac)) { return false; } $crypto = static::engine(); return $crypto->decrypt($cipher, $key); } /** * A timing attack resistant comparison that prefers native PHP implementations. * * @param string $original The original value. * @param string $compare The comparison value. * @return bool * @see https://github.com/resonantcore/php-future/ * @since 3.6.2 */ public static function constantEquals($original, $compare) { if (!is_string($original) || !is_string($compare)) { return false; } if (function_exists('hash_equals')) { return hash_equals($original, $compare); } $originalLength = mb_strlen($original, '8bit'); $compareLength = mb_strlen($compare, '8bit'); if ($originalLength !== $compareLength) { return false; } $result = 0; for ($i = 0; $i < $originalLength; $i++) { $result |= (ord($original[$i]) ^ ord($compare[$i])); } return $result === 0; } /** * Gets the HMAC salt to be used for encryption/decryption * routines. * * @return string The currently configured salt */ public static function getSalt() { if (static::$_salt === null) { throw new RuntimeException( 'Salt not set. Use Security::setSalt() to set one, ideally in `config/bootstrap.php`.' ); } return static::$_salt; } /** * Sets the HMAC salt to be used for encryption/decryption * routines. * * @param string $salt The salt to use for encryption routines. * @return void */ public static function setSalt($salt) { static::$_salt = (string)$salt; } /** * Gets or sets the HMAC salt to be used for encryption/decryption * routines. * * @deprecated 3.5.0 Use getSalt()/setSalt() instead. * @param string|null $salt The salt to use for encryption routines. If null returns current salt. * @return string The currently configured salt */ public static function salt($salt = null) { deprecationWarning( 'Security::salt() is deprecated. ' . 'Use Security::getSalt()/setSalt() instead.' ); if ($salt === null) { return static::$_salt; } return static::$_salt = (string)$salt; } }