*
 * One of them has been encrypted with ECB.
 *
 * Detect it.
 *
 * Remember that the problem with ECB is that it is stateless and deterministic; the same 16 byte plaintext block will always produce the same 16 byte ciphertext.
 */
function repeatedBlockCount($data)
{
    $dataLen = strlen($data);
    $repetitions = 0;
    for ($i = 0; $i < $dataLen; $i += 16) {
        $block = substr($data, $i, 16);
        $repetition = strpos($data, $block, $i + 16);
        if ($repetition && $repetition % 16 === 0) {
            $repetitions++;
        }
    }
    return $repetitions;
}
// don't output if we're included into another script.
if (!debug_backtrace()) {
    $data = array_map('hex2bin', file('08-data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
    foreach ($data as $k => $encrypted) {
        $repetitions = repeatedBlockCount($encrypted);
        if ($repetitions) {
            $line = $k + 1;
            print "String at on line {$line} has repeated blocks (probable ECB)\n";
        }
    }
}
 */
require_once '../utils/random-bytes.php';
require_once '../01-basics/07-aes-in-ecb-mode.php';
require_once '10-implement-cbc-mode.php';
function randomlyEncryptECBorCBC($data)
{
    $key = getRandomBytes(16);
    $pad1 = getRandomBytes(rand(5, 10));
    $pad2 = getRandomBytes(rand(5, 10));
    if (rand(0, 1)) {
        return encryptAES128CBC("{$pad1}{$data}{$pad2}", $key, getRandomBytes(16));
    }
    return encryptAES128ECB("{$pad1}{$data}{$pad2}", $key);
}
// don't output if we're included into another script.
if (!debug_backtrace()) {
    require_once '../01-basics/08-detect-aes-in-ecb-mode.php';
    // so the trick is to feed the black box something that will trigger ECBs weakness regardless of padding
    // this means we need at least 3 blocks of repeated data (with padding this reduces to 2 blocks)
    $plaintext = str_repeat('a', 48);
    print "Running 5000 samples\n";
    $ecb = 0;
    for ($i = 0; $i < 5000; $i++) {
        $ciphertext = randomlyEncryptECBorCBC($plaintext);
        if (repeatedBlockCount($ciphertext)) {
            $ecb++;
        }
    }
    print "{$ecb} samples detected as ECB mode\n";
    print $ecb && round(5000 / $ecb) === 2.0 ? "Success!\n\n" : "Failure :(\n\n";
}