3v4l.org

run code in 300+ PHP versions simultaneously
<?php define('ENCRYPTION_KEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282'); // Encrypt Function function mc_encrypt($encrypt, $key){ //$encrypt = serialize($encrypt); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM); $key = pack('H*', $key); $mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32)); $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv); $encoded = base64_encode($passcrypt).'|'.base64_encode($iv); return $encoded; } // Decrypt Function function mc_decrypt($decrypt, $key){ $decrypt = explode('|', $decrypt.'|'); $decoded = base64_decode($decrypt[0]); $iv = base64_decode($decrypt[1]); if(strlen($iv)!==mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; } $key = pack('H*', $key); //$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv)); $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv); $mac = substr($decrypted, -64); $decrypted = substr($decrypted, 0, -64); $calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32)); // if($calcmac!==$mac){ return false; } // Simulate the timing side channel with 1-byte granularity. if($calcmac!==$mac){ if ($calcmac[0] == $mac[0]) { return 1; } else { return 0; } } //$decrypted = unserialize($decrypted); return $decrypted; } /* * Attack code. By Taylor Hornby (@DefuseSec), June 08, 2015. */ // The message we want to decrypt. $message = "Cryptography is harder than you think! You can't assemble it like Lego!"; // Encrypt the message. $ciphertext = mc_encrypt($message, ENCRYPTION_KEY); // From here on, all we're allowed to do is (1) Get known plaintexts, and (2) // Use the (simulated) timing oracle. // We're going to get the first byte of each decrypted block, so split the // target ciphertext into blocks. $ct_parts = explode('|', $ciphertext); $ct_blocks = str_split(base64_decode($ct_parts[0]), 32); // Add the IV in front. We need it later and having it in index zero makes the // code below more conveinient. array_unshift($ct_blocks, base64_decode($ct_parts[1])); // Remove the MAC blocks off the end (we don't care what they decrypt to). $ct_blocks = array_slice($ct_blocks, 0, -2); // This array will hold our known plaintexts. We want one known plaintext for // each byte value \x00 though \xFF. The respective plaintext should be a single // block that decrypts to a block having that value as its first byte (BEFORE // the CBC mode XOR). $firstbytes = array(); // Just keep getting known plaintexts until we have all the byte values. while (count($firstbytes) < 256) { // We're choosing the plaintext here, but that's not necessary. The contents // don't matter, as long as we know what the first byte is. $kp = mc_encrypt(str_repeat("a", 32), ENCRYPTION_KEY); // Break the ciphertext apart. $parts = explode('|', $kp); $iv = base64_decode($parts[1]); $ct = substr(base64_decode($parts[0]), 0, 32); // We know the decrypted result after the CBC-mode XOR is "a", so the value // just after decryption but before the CBC-mode XOR is this: $firstbyte = ord($iv[0]) ^ ord("a"); // Remember this block as decrypting to block that starts with that byte. // We might have already found one for this byte value, if that's the case // we just overwrite it. $firstbytes[$firstbyte] = $ct; } // Loop over all of the ciphertext blocks we want to decrypt the first byte of. // (Note: Index 0 is the IV, as we set above). for ($i = 1; $i < count($ct_blocks); $i++) { $ct_block = $ct_blocks[$i]; // We'll use zero IVs for our oracle queries. We could use anything really. $zero_block = str_repeat("\x00", 32); // Some padding to be the last (of two) blocks of the MAC. $p = mcrypt_create_iv(32, MCRYPT_DEV_URANDOM); // Find a collision in the first byte of the computed MAC and "included MAC". $r = mcrypt_create_iv(32, MCRYPT_DEV_URANDOM); $ct = base64_encode($r . $ct_block . $p) . "|" . base64_encode($zero_block); while (mc_decrypt($ct, ENCRYPTION_KEY) !== 1) { $r = mcrypt_create_iv(32, MCRYPT_DEV_URANDOM); $ct = base64_encode($r . $ct_block . $p) . "|" . base64_encode($zero_block); } // In the above, the "computed MAC" is the MAC of whatever $r decrypts to // with a null IV. The "included MAC" is the first byte of the decrypted // value of $ct_block (before the CBC-XOR) XORed with $r[0]. // So a collision means two things: // 1. Decrypting $ct_block with $r as an "IV" makes the first byte a hex // digit, and // 2. That hex digit is the same as the one that the MAC of whatever $r // decrypts to starts with. // If only we could find out what that hex digit is... then we could find // out what the first byte of the decrypted $ct_block is. Let's use our // known plaintexts to do just that... // Try decrypting with our known-first-byte blocks in place of $ct_block. for ($first_byte = 0; $first_byte <= 255; $first_byte++) { $ct = base64_encode($r . $firstbytes[$first_byte] . $p) . "|" . base64_encode($zero_block); if (($res = mc_decrypt($ct, ENCRYPTION_KEY)) === 1) { // The computed MAC value won't have changed, and we know the first // byte still matches so that means the first byte (after decryption // but before XOR) of our known plaintext block is the same as the // first byte (after decryption but before XOR) of $ct_block. // We know what that byte is! So let's XOR it with the first byte of // the previous block in the whole ciphertext we're working on to // get the proper (after CBC-XOR) decryption. $iv_decrypted_byte = ord($ct_blocks[$i-1][0]) ^ $first_byte; echo "Block $i's first byte is: " . chr($iv_decrypted_byte) . "\n"; break; } } }

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.60.0090.00616.75
8.3.50.0060.00918.18
8.3.40.0030.01218.81
8.3.30.0110.01118.65
8.3.20.0040.00420.20
8.3.10.0090.00023.56
8.3.00.0060.00319.13
8.2.180.0150.00025.92
8.2.170.0150.00322.96
8.2.160.0120.00320.33
8.2.150.0110.00724.18
8.2.140.0030.00524.66
8.2.130.0030.00617.75
8.2.120.0080.00026.35
8.2.110.0030.00722.08
8.2.100.0080.00318.09
8.2.90.0080.00019.21
8.2.80.0000.00817.97
8.2.70.0030.00517.50
8.2.60.0040.00417.92
8.2.50.0030.00618.07
8.2.40.0000.00719.37
8.2.30.0000.00720.75
8.2.20.0030.00617.80
8.2.10.0040.00418.21
8.2.00.0060.00318.10
8.1.280.0030.01725.92
8.1.270.0070.00323.91
8.1.260.0050.00328.09
8.1.250.0100.00028.09
8.1.240.0070.01122.20
8.1.230.0080.00419.21
8.1.220.0060.00317.89
8.1.210.0040.00418.77
8.1.200.0030.00617.60
8.1.190.0040.00417.35
8.1.180.0030.00518.10
8.1.170.0000.00818.90
8.1.160.0040.00421.95
8.1.150.0040.00418.82
8.1.140.0000.00817.38
8.1.130.0030.00317.81
8.1.120.0000.00817.41
8.1.110.0040.00417.55
8.1.100.0090.00317.52
8.1.90.0000.00717.50
8.1.80.0000.00717.56
8.1.70.0040.00417.47
8.1.60.0050.00317.60
8.1.50.0030.00617.49
8.1.40.0030.00517.55
8.1.30.0000.00817.72
8.1.20.0030.00617.68
8.1.10.0000.00817.50
8.1.00.0040.00417.48
8.0.300.0050.00318.77
8.0.290.0040.00416.75
8.0.280.0030.00318.62
8.0.270.0040.00416.86
8.0.260.0030.00317.37
8.0.250.0000.00717.15
8.0.240.0070.00016.97
8.0.230.0030.00317.05
8.0.220.0030.00317.00
8.0.210.0040.00416.91
8.0.200.0000.00717.08
8.0.190.0040.00416.96
8.0.180.0050.00216.99
8.0.170.0020.00516.94
8.0.160.0030.00617.00
8.0.150.0000.00816.96
8.0.140.0040.00416.84
8.0.130.0000.00613.48
8.0.120.0000.00816.82
8.0.110.0030.00616.93
8.0.100.0080.00016.91
8.0.90.0000.00716.97
8.0.80.0070.01317.02
8.0.70.0000.00816.86
8.0.60.0080.00017.04
8.0.50.0000.00817.06
8.0.30.0060.01017.09
8.0.20.0110.00817.40
8.0.10.0040.00417.11
8.0.00.0080.00916.97
7.4.330.0000.00516.91
7.4.320.0000.00616.64
7.4.300.0030.00316.66
7.4.290.0000.00716.67
7.4.280.0060.00316.59
7.4.270.0000.00716.66
7.4.260.0000.00916.64
7.4.250.0070.00316.46
7.4.240.0020.00516.62
7.4.230.0070.00016.75
7.4.220.0110.01316.71
7.4.210.0090.00616.56
7.4.200.0000.00716.52
7.4.160.0120.00416.67
7.4.150.0100.00717.40
7.4.140.0120.00617.86
7.4.130.0080.01116.66
7.4.120.0110.00916.63
7.4.110.0120.01116.68
7.4.100.0110.00716.37
7.4.90.0100.00716.71
7.4.80.0040.01819.39
7.4.70.0110.00816.65
7.4.60.0140.00516.64
7.4.50.0100.00616.54
7.4.40.0160.00416.44
7.4.30.0060.01116.63
7.4.00.0140.00314.80
7.3.330.0000.00613.20
7.3.320.0050.00013.38
7.3.310.0050.00216.21
7.3.300.0040.00416.21
7.3.290.0030.00316.30
7.3.280.0100.00616.37
7.3.270.0090.00917.40
7.3.260.0130.00416.63
7.3.250.0040.01516.47
7.3.240.0100.00916.46
7.3.230.0110.00716.39
7.3.210.0000.01716.46
7.3.200.0050.01116.47
7.3.190.0040.01316.50
7.3.180.0070.01416.51
7.3.170.0090.01316.40
7.3.160.0100.00716.48
7.2.330.0070.01016.73
7.2.320.0150.00616.36
7.2.310.0160.00716.71
7.2.300.0070.01016.55
7.2.290.0090.00916.40
7.2.60.0070.01016.73
7.2.00.0100.00319.42
7.1.200.0030.00915.79
7.1.100.0000.01118.25
7.1.70.0000.00717.06
7.1.60.0110.01119.36
7.1.50.0040.01817.04
7.1.00.0030.07322.28
7.0.200.0070.00016.64
7.0.60.0230.06320.01
7.0.50.0370.22018.16
7.0.40.1270.32320.23
7.0.30.0530.27320.13
7.0.20.0730.26020.16
7.0.10.0600.33320.13
7.0.00.0430.29720.14
5.6.280.0000.04021.07
5.6.210.0100.08020.73
5.6.200.0170.22318.27
5.6.190.0400.30720.66
5.6.180.0400.17020.46
5.6.170.0430.20020.51
5.6.160.0400.26720.62
5.6.150.0800.40318.27
5.6.140.0200.26018.34
5.6.130.0100.33318.35
5.6.120.0230.26721.14
5.6.110.0530.29021.25
5.6.100.0730.28321.21
5.6.90.0230.16321.13
5.6.80.0470.31320.68
5.5.350.0400.06720.46
5.5.340.0300.20718.11
5.5.330.0200.28320.32
5.5.320.0900.31720.42
5.5.310.0470.28720.36
5.5.300.0400.30318.11
5.5.290.0630.24718.17
5.5.280.0300.36320.92
5.5.270.0370.23020.96
5.5.260.0330.32320.91
5.5.250.0470.27320.64
5.5.240.0470.23720.30

preferences:
56.4 ms | 400 KiB | 5 Q