3v4l.org

run code in 300+ PHP versions simultaneously
<?php declare(strict_types=1); namespace ParagonIE\BlogExampleCode; /** * Implements encryption RSA with PKCS1v1.5 padding * using the Anti-BB'98 dance. * * @ref https://paragonie.com/b/_8qH-xPuGPUoSSsc */ class RSAPKCS1v15 { public static function encrypt(string $message, string $publicKey): array { $key = \random_bytes(32); $C = ''; // This defaults to PKCS1v1.5: \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)]; } public static function decrypt(string $CHex, string $DHex, string $privateKey): string { $kPrime = \random_bytes(32); $C = \hex2bin($CHex); $D = \hex2bin($DHex); $k = ''; $success = \openssl_private_decrypt($C, $k, $privateKey); // Do a constant-time swap: $key = self::cswap32($k, (string) $kPrime, $success); $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 ); } /** * Branch-less, timing safe version of * $A = ($switch === 0 ? $A : $B); * * @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'); } public static function chrToInt(string $chr): int { $chunk = \unpack('C', $chr); return (int) ($chunk[1]); } 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;

preferences:
37.11 ms | 402 KiB | 5 Q