3v4l.org

run code in 300+ PHP versions simultaneously
<?php declare(strict_types=1); namespace ParagonIE\BlogExampleCode; /** * Class RSAPKCS1v15 * @package ParagonIE\BlogExampleCode * * @ref https://paragonie.com/blog/2018/04/protecting-rsa-based-protocols-against-adaptive-chosen-ciphertext-attacks */ class RSAPKCS1v15 { /** * @param string $message * @param string $publicKey * * @return array<int, string> * @throws \Exception */ public static function encrypt(string $message, string $publicKey): array { $key = \random_bytes(32); $C = ''; \openssl_public_encrypt($key, $C, $publicKey); $iv = \random_bytes(16); $cipher = \openssl_encrypt( $message, 'aes-256-ctr', $key, OPENSSL_RAW_DATA, $iv ); $mac = \hash_hmac('sha256', $iv . $cipher, $key, true); $D = $mac . $iv . $cipher; return [bin2hex($C), bin2hex($D)]; } /** * @param string $CHex * @param string $DHex * @param string $privateKey * * @return string * @throws \Exception */ public static function decrypt(string $CHex, string $DHex, string $privateKey): string { $kPrime = \random_bytes(32); $C = \hex2bin($CHex); $D = \hex2bin($DHex); $k = ''; $return = @\openssl_private_decrypt($C, $k, $privateKey); // Do a constant-time swap: $key = self::cswap32($k, (string) $kPrime, $return ); $mac = mb_substr($D, 0, 32, '8bit'); $iv = mb_substr($D, 32, 16, '8bit'); $cipher = mb_substr($D, 48, null, '8bit'); $recalc = \hash_hmac('sha256', $iv . $cipher, $key, true); if (!\hash_equals($recalc, $mac)) { throw new \Exception('Invalid MAC'); } return \openssl_decrypt( $cipher, 'aes-256-ctr', $key, OPENSSL_RAW_DATA, $iv ); } /** * @param string $A * @param string $B * @param bool $success * * @return string */ public static function cswap32(string $A, string $B, bool $success): string { $A .= \str_repeat("\x00", 32); $B .= \str_repeat("\x00", 32); /** @var int $mask 0 if $success is true, otherwise 255 */ $mask = (((int) $success) - 1) & 0xff; $C = ''; for ($i = 0; $i < 32; ++$i) { $C .= self::intToChr( (self::chrToInt($A[$i]) ^ self::chrToInt($B[$i])) & $mask ); } return (string) mb_substr($A ^ $C, 0, 32, '8bit'); } /** * @param string $chr * * @return int */ public static function chrToInt(string $chr): int { $chunk = \unpack('C', $chr); return (int) ($chunk[1]); } /** * @param int $int * * @return string */ public static function intToChr(int $int): string { return \pack('C', $int); } } $private_key = '-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyaTgTt53ph3p5GHgwoGWwz5hRfWXSQA08NCOwe0FEgALWos9 GCjNFCd723nCHxBtN1qd74MSh/uN88JPIbwxKheDp4kxo4YMN5trPaF0e9G6Bj1N 02HnanxFLW+gmLbgYO/SZYfWF/M8yLBcu5Y1Ot0ZxDDDXS9wIQTtBE0ne3YbxgZJ AZTU5XqyQ1DxdzYyC5lF6yBaR5UQtCYTnXAApVRuUI2Sd6L1E2vl9bSBumZ5IpNx kRnAwIMjeTJB/0AIELh0mE5vwdihOCbdV6alUyhKC1+1w/FW6HWcp/JG1kKC8DPI idZ78Bbqv9YFzkAbNni5eSBOsXVBKG78Zsc8owIDAQABAoIBAF22jLDa34yKdns3 qfd7to+C3D5hRzAcMn6Azvf9qc+VybEI6RnjTHxDZWK5EajSP4/sQ15e8ivUk0Jo WdJ53feL+hnQvwsab28gghSghrxM2kGwGA1XgO+SVawqJt8SjvE+Q+//01ZKK0Oy A0cDJjX3L9RoPUN/moMeAPFw0hqkFEhm72GSVCEY1eY+cOXmL3icxnsnlUD//SS9 q33RxF2y5oiW1edqcRqhW/7L1yYMbxHFUcxWh8WUwjn1AAhoCOUzF8ZB+0X/PPh+ 1nYoq6xwqL0ZKDwrQ8SDhW/rNDLeO9gic5rl7EetRQRbFvsZ40AdsX2wU+lWFUkB 42AjuoECgYEA5z/CXqDFfZ8MXCPAOeui8y5HNDtu30aR+HOXsBDnRI8huXsGND04 FfmXR7nkghr08fFVDmE4PeKUk810YJb+IAJo8wrOZ0682n6yEMO58omqKin+iIUV rPXLSLo5CChrqw2J4vgzolzPw3N5I8FJdLomb9FkrV84H+IviPIylyECgYEA3znw AG29QX6ATEfFpGVOcogorHCntd4niaWCq5ne5sFL+EwLeVc1zD9yj1axcDelICDZ xCZynU7kDnrQcFkT0bjH/gC8Jk3v7XT9l1UDDqC1b7rm/X5wFIZ/rmNa1rVZhL1o /tKx5tvM2syJ1q95v7NdygFIEIW+qbIKbc6Wz0MCgYBsUZdQD+qx/xAhELX364I2 epTryHMUrs+tGygQVrqdiJX5dcDgM1TUJkdQV6jLsKjPs4Vt6OgZRMrnuLMsk02R 3M8gGQ25ok4f4nyyEZxGGWnVujn55KzUiYWhGWmhgp18UCkoYa59/Q9ss+gocV9h B9j9Q43vD80QUjiF4z0DQQKBgC7XQX1VibkMim93QAnXGDcAS0ij+w02qKVBjcHk b9mMBhz8GAxGOIu7ZJafYmxhwMyVGB0I1FQeEczYCJUKnBYN6Clsjg6bnBT/z5bJ x/Jx1qCzX3Uh6vLjpjc5sf4L39Tyye1u2NXQmZPwB5x9BdcsFConSq/s4K1LJtUT 3KFxAoGBANGcQ8nObi3m4wROyKrkCWcWxFFMnpwxv0pW727Hn9wuaOs4UbesCnwm pcMTfzGUDuzYXCtAq2pJl64HG6wsdkWmjBTJEpm6b9ibOBN3qFV2zQ0HyyKlMWxI uVSj9gOo61hF7UH9XB6R4HRdlpBOuIbgAWZ46dkj9/HM9ovdP0Iy -----END RSA PRIVATE KEY-----'; $public_key = '-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyaTgTt53ph3p5GHgwoGW wz5hRfWXSQA08NCOwe0FEgALWos9GCjNFCd723nCHxBtN1qd74MSh/uN88JPIbwx KheDp4kxo4YMN5trPaF0e9G6Bj1N02HnanxFLW+gmLbgYO/SZYfWF/M8yLBcu5Y1 Ot0ZxDDDXS9wIQTtBE0ne3YbxgZJAZTU5XqyQ1DxdzYyC5lF6yBaR5UQtCYTnXAA pVRuUI2Sd6L1E2vl9bSBumZ5IpNxkRnAwIMjeTJB/0AIELh0mE5vwdihOCbdV6al UyhKC1+1w/FW6HWcp/JG1kKC8DPIidZ78Bbqv9YFzkAbNni5eSBOsXVBKG78Zsc8 owIDAQAB -----END PUBLIC KEY-----'; $in = 'This is a test message!'; list ($C, $D) = RSAPKCS1v15::encrypt($in, $public_key); $start = $end = microtime(true); $out = RSAPKCS1v15::decrypt($C, $D, $private_key); $end = microtime(true); var_dump($in, $out); var_dump($end - $start); // Flip the bits in one character of C to force an error $Corig = $D; $C = hex2bin($C); $C[0] = RSAPKCS1v15::intToChr( RSAPKCS1v15::chrToInt($C[0]) ^ 0xff ); $C = bin2hex($C); $start = $end = microtime(true); try { $out = RSAPKCS1v15::decrypt($C, $D, $private_key); } catch (\Exception $ex) { $end = microtime(true); var_dump($end - $start); if ($ex->getMessage() === 'Invalid MAC') { echo 'Got the expected error message. No RSA hints given.', PHP_EOL; } } $C = $Corig; // Flip the bits in one character of D to force an error $Dorig = $D; $D = hex2bin($D); $D[0] = RSAPKCS1v15::intToChr( RSAPKCS1v15::chrToInt($D[0]) ^ 0xff ); $D = bin2hex($D); $start = $end = microtime(true); try { $out = RSAPKCS1v15::decrypt($C, $D, $private_key); } catch (\Exception $ex) { $end = microtime(true); var_dump($end - $start); if ($ex->getMessage() === 'Invalid MAC') { echo 'Got the expected error message. No RSA hints given.', PHP_EOL; } } $D = $Dorig;
Output for 7.1.25, 7.2.0 - 7.2.13, 7.3.0 - 7.3.1
Fatal error: Uncaught Error: Call to undefined function openssl_public_encrypt() in /in/mStdU:24 Stack trace: #0 /in/mStdU(158): ParagonIE\BlogExampleCode\RSAPKCS1v15::encrypt('This is a test ...', '-----BEGIN PUBL...') #1 {main} thrown in /in/mStdU on line 24
Process exited with code 255.
Output for 7.1.16
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0032830238342285) float(0.0026600360870361) Got the expected error message. No RSA hints given. float(0.0031459331512451) Got the expected error message. No RSA hints given.
Output for 7.1.15
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0048320293426514) float(0.00017404556274414) Got the expected error message. No RSA hints given. float(0.0043079853057861) Got the expected error message. No RSA hints given.
Output for 7.1.14
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0030999183654785) float(0.003777027130127) Got the expected error message. No RSA hints given. float(0.0031981468200684) Got the expected error message. No RSA hints given.
Output for 7.1.13
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0025229454040527) float(0.0026600360870361) Got the expected error message. No RSA hints given. float(0.0027389526367188) Got the expected error message. No RSA hints given.
Output for 7.1.12
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0043368339538574) float(0.0024948120117188) Got the expected error message. No RSA hints given. float(0.003040075302124) Got the expected error message. No RSA hints given.
Output for 7.1.11
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0026729106903076) float(0.0024979114532471) Got the expected error message. No RSA hints given. float(0.0025629997253418) Got the expected error message. No RSA hints given.
Output for 7.1.10
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0029020309448242) float(0.0031530857086182) Got the expected error message. No RSA hints given. float(0.0027079582214355) Got the expected error message. No RSA hints given.
Output for 7.1.9
string(23) "This is a test message!" string(23) "This is a test message!" float(0.004763126373291) float(0.00013113021850586) Got the expected error message. No RSA hints given. float(0.0028338432312012) Got the expected error message. No RSA hints given.
Output for 7.1.8
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0028150081634521) float(0.00015807151794434) Got the expected error message. No RSA hints given. float(0.0026578903198242) Got the expected error message. No RSA hints given.
Output for 7.1.7
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0025091171264648) float(0.0025680065155029) Got the expected error message. No RSA hints given. float(0.0027878284454346) Got the expected error message. No RSA hints given.
Output for 7.1.6
string(23) "This is a test message!" string(23) "This is a test message!" float(0.003187894821167) float(0.0032470226287842) Got the expected error message. No RSA hints given. float(0.0033648014068604) Got the expected error message. No RSA hints given.
Output for 7.1.5
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0025570392608643) float(0.0024330615997314) Got the expected error message. No RSA hints given. float(0.0025479793548584) Got the expected error message. No RSA hints given.
Output for 7.1.4
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0039000511169434) float(0.0026779174804688) Got the expected error message. No RSA hints given. float(0.0028598308563232) Got the expected error message. No RSA hints given.
Output for 7.1.3
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0028669834136963) float(0.00013303756713867) Got the expected error message. No RSA hints given. float(0.0029561519622803) Got the expected error message. No RSA hints given.
Output for 7.1.2
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0028679370880127) float(0.0027518272399902) Got the expected error message. No RSA hints given. float(0.0026628971099854) Got the expected error message. No RSA hints given.
Output for 7.1.1
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0043799877166748) float(0.0041408538818359) Got the expected error message. No RSA hints given. float(0.0042548179626465) Got the expected error message. No RSA hints given.
Output for 7.1.0
string(23) "This is a test message!" string(23) "This is a test message!" float(0.0030279159545898) float(0.00016593933105469) Got the expected error message. No RSA hints given. float(0.0027408599853516) Got the expected error message. No RSA hints given.

preferences:
75.99 ms | 402 KiB | 39 Q