3v4l.org

run code in 300+ PHP versions simultaneously
<?php /** * http://stackoverflow.com/questions/9262109/php-simplest-two-way-encryption/30189841#30189841 * * This is not safe to use */ class UnsafeCrypto { const METHOD = 'aes-256-ctr'; /** * Encrypts (but does not authenticate) a message * * @param string $message - plaintext message * @param string $key - encryption key (raw binary expected) * @param boolean $encode - set to TRUE to return a base64-encoded * @return string (raw binary) */ public static function encrypt($message, $key, $encode = false) { $nonceSize = openssl_cipher_iv_length(self::METHOD); $nonce = openssl_random_pseudo_bytes($nonceSize); $ciphertext = openssl_encrypt( $message, self::METHOD, $key, OPENSSL_RAW_DATA, $nonce ); // Now let's pack the IV and the ciphertext together // Naively, we can just concatenate if ($encode) { return base64_encode($nonce.$ciphertext); } return $nonce.$ciphertext; } /** * Decrypts (but does not verify) a message * * @param string $message - ciphertext message * @param string $key - encryption key (raw binary expected) * @param boolean $encoded - are we expecting an encoded string? * @return string */ public static function decrypt($message, $key, $encoded = false) { if ($encoded) { $message = base64_decode($message, true); if ($message === false) { throw new Exception('Encryption failure'); } } $nonceSize = openssl_cipher_iv_length(self::METHOD); $nonce = mb_substr($message, 0, $nonceSize, '8bit'); $ciphertext = mb_substr($message, $nonceSize, null, '8bit'); $plaintext = openssl_decrypt( $ciphertext, self::METHOD, $key, OPENSSL_RAW_DATA, $nonce ); return $plaintext; } } class SaferCrypto extends UnsafeCrypto { const HASH_ALGO = 'sha256'; /** * Encrypts then MACs a message * * @param string $message - plaintext message * @param string $key - encryption key (raw binary expected) * @param boolean $encode - set to TRUE to return a base64-encoded string * @return string (raw binary) */ public static function encrypt($message, $key, $encode = false) { list($encKey, $authKey) = self::splitKeys($key); // Pass to UnsafeCrypto::encrypt $ciphertext = parent::encrypt($message, $encKey); // Calculate a MAC of the IV and ciphertext $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true); if ($encode) { return base64_encode($mac.$ciphertext); } // Prepend MAC to the ciphertext and return to caller return $mac.$ciphertext; } /** * Decrypts a message (after verifying integrity) * * @param string $message - ciphertext message * @param string $key - encryption key (raw binary expected) * @param boolean $encoded - are we expecting an encoded string? * @return string (raw binary) */ public static function decrypt($message, $key, $encoded = false) { list($encKey, $authKey) = self::splitKeys($key); if ($encoded) { $message = base64_decode($message, true); if ($message === false) { throw new Exception('Encryption failure'); } } // Hash Size -- in case HASH_ALGO is changed $hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit'); $mac = mb_substr($message, 0, $hs, '8bit'); $ciphertext = mb_substr($message, $hs, null, '8bit'); $calculated = hash_hmac( self::HASH_ALGO, $ciphertext, $authKey, true ); if (!self::hashEquals($mac, $calculated)) { throw new Exception('Encryption failure'); } // Pass to UnsafeCrypto::decrypt $plaintext = parent::decrypt($ciphertext, $encKey); return $plaintext; } /** * Splits a key into two separate keys; one for encryption * and the other for authenticaiton * * @param string $masterKey (raw binary) * @return array (two raw binary strings) */ protected static function splitKeys($masterKey) { // You really want to implement HKDF here instead! return [ hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true), hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true) ]; } /** * Compare two strings without leaking timing information * * @param string $a * @param string $b * @return boolean */ protected static function hashEquals($a, $b) { if (function_exists('hash_equals')) { return hash_equals($a, $b); } $nonce = openssl_random_pseudo_bytes(32); return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce); } } $message = 'vcOi2ox7X7S1ADTztcNa33a1Egxeob/BxK1hEluB73yFCWumuxrHAlnWd4WxfRgLbY6iFCKA5OY1uYYs8P7HFk9lRppGu829UP4BE6iEIwoEUva5nYDq94xnxSfwP+SNRBCSfvZNW2suCnqA33sEynL1rBvcyu4YrSME4qP66gU=|CTqfGZNts83xSibdA9Q63xGXMxXZIJe53htzZ5pJIBo='; $key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'); $encrypted = SaferCrypto::encrypt($message, $key, true); $decrypted = SaferCrypto::decrypt($message, $key, true); var_dump($encrypted, $decrypted);
Output for 7.1.25, 7.2.0 - 7.2.33, 7.3.0 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.28, 8.2.0 - 8.2.18, 8.3.0 - 8.3.4, 8.3.6
Fatal error: Uncaught Error: Call to undefined function openssl_cipher_iv_length() in /in/r7Ms8:21 Stack trace: #0 /in/r7Ms8(89): UnsafeCrypto::encrypt('vcOi2ox7X7S1ADT...', '\x0E\xAE\x8C\x94\x9FI\xEE\x93\xD3\x89\x9F\t\xBAs\x00...') #1 /in/r7Ms8(179): SaferCrypto::encrypt('vcOi2ox7X7S1ADT...', '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\v\f\r\x0E...', true) #2 {main} thrown in /in/r7Ms8 on line 21
Process exited with code 255.
Output for 8.3.5
Warning: PHP Startup: Unable to load dynamic library 'sodium.so' (tried: /usr/lib/php/8.3.5/modules/sodium.so (libsodium.so.23: cannot open shared object file: No such file or directory), /usr/lib/php/8.3.5/modules/sodium.so.so (/usr/lib/php/8.3.5/modules/sodium.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0 Fatal error: Uncaught Error: Call to undefined function openssl_cipher_iv_length() in /in/r7Ms8:21 Stack trace: #0 /in/r7Ms8(89): UnsafeCrypto::encrypt('vcOi2ox7X7S1ADT...', '\x0E\xAE\x8C\x94\x9FI\xEE\x93\xD3\x89\x9F\t\xBAs\x00...') #1 /in/r7Ms8(179): SaferCrypto::encrypt('vcOi2ox7X7S1ADT...', '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\v\f\r\x0E...', true) #2 {main} thrown in /in/r7Ms8 on line 21
Process exited with code 255.
Output for 7.0.0 - 7.0.20, 7.1.0 - 7.1.7
Fatal error: Uncaught Exception: Encryption failure in /in/r7Ms8:115 Stack trace: #0 /in/r7Ms8(180): SaferCrypto::decrypt(false, '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\v\f\r\x0E...', true) #1 {main} thrown in /in/r7Ms8 on line 115
Process exited with code 255.
Output for 5.4.29 - 5.4.45, 5.5.24 - 5.5.35, 5.6.7 - 5.6.28
Fatal error: Uncaught exception 'Exception' with message 'Encryption failure' in /in/r7Ms8:115 Stack trace: #0 /in/r7Ms8(180): SaferCrypto::decrypt('vcOi2ox7X7S1ADT...', '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\v\f\r\x0E...', true) #1 {main} thrown in /in/r7Ms8 on line 115
Process exited with code 255.
Output for 5.4.27 - 5.4.28
Fatal error: Uncaught exception 'Exception' with message 'Encryption failure' in /in/r7Ms8:115 Stack trace: #0 /in/r7Ms8(180): SaferCrypto::decrypt('vcOi2ox7X7S1ADT...', '\x00\x01\x02\x03\x04\x05\x03\x04\x05\x03\x04\x05\x03\x04\x05\x03\x04\x05\x03\x04\x05true) #1 {main} thrown in /in/r7Ms8 on line 115
Process exited with code 255.
Output for 5.4.15 - 5.4.26
Fatal error: Uncaught exception 'Exception' with message 'Encryption failure' in /in/r7Ms8:115 Stack trace: #0 /in/r7Ms8(180): SaferCrypto::decrypt('vcOi2ox7X7S1ADT...', '???????????????...', true) #1 {main} thrown in /in/r7Ms8 on line 115
Process exited with code 255.
Output for 5.4.0 - 5.4.14
Fatal error: Call to undefined function openssl_cipher_iv_length() in /in/r7Ms8 on line 21
Process exited with code 255.

preferences:
210.46 ms | 401 KiB | 242 Q