require_once '../01-basics/06-break-repeating-key-xor.php';
require_once '18-implement-ctr-the-stream-cipher-mode.php';
$plaintexts = array_map('base64_decode', file('20-data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
$key = getRandomBytes(16);
$ciphertexts = array_map('encryptAES128CTR', $plaintexts, array_fill(0, count($plaintexts), $key));
$cipherLens = array_map('strlen', $ciphertexts);
// challenge text says use a common length, but we can recover more if we don't
// this is because after transposition there's still enough data to statistically recover more
/*
$minLength = min($cipherLens);
$truncated = array_map('str_split', $ciphertexts, array_fill(0, count($plaintexts), $minLength));
$truncated = array_column($truncated, 0);
*/
$truncated = $ciphertexts;
// some copy/paste/tweak from challenge 6
print "\nSolving keys based on English Language scoring:\n";
$blocks = transposeBlocks($ciphertexts);
$englishLanguageWeights['/'] = 0;
list($topScores, $topChars) = scoreSingleByteXORStrings($blocks, $englishLanguageWeights, 20);
$potentialKey = implode(array_map('chr', $topChars));
foreach ($truncated as $k => $ciphertext) {
    $recovered = $ciphertext ^ $potentialKey;
    print "{$k}: {$recovered}\n";
}
print "\n\nSome texts will not be fully recovered.\nThis is expected for simple automatic statistical recovery.\n\n\n";
foreach ($truncated as $k => $ciphertext) {
    $recovered = $ciphertext ^ $potentialKey;
    if ($recovered !== $plaintexts[$k]) {
        print "Cracked : {$recovered}\nOriginal: {$plaintexts[$k]}\n\n";
    }
}
function scoreSingleByteXORStrings(array $strings, array $weights, $penalty = 0)
{
    $topScores = [];
    $topChars = [];
    foreach ($strings as $pos => $string) {
        $scores = scoreSingleByteXOR($string, $weights, $penalty);
        arsort($scores);
        $topScores[$pos] = current($scores);
        $topChars[$pos] = key($scores);
    }
    return [$topScores, $topChars];
}
// don't output if we're included into another script.
if (!debug_backtrace()) {
    $encrypted = array_map('hex2bin', file('04-data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
    list($topScores, $topChars) = scoreSingleByteXORStrings($encrypted, $englishLanguageWeights);
    arsort($topScores);
    print "Highest scoring strings indexes and characters:\n";
    $i = 0;
    foreach ($topScores as $k => $v) {
        $c = $topChars[$k];
        print "{$k} - {$c} - {$v}\n";
        if (++$i === 3) {
            break;
        }
    }
    print "\nDecrypted strings:\n";
    $i = 0;
    foreach ($topScores as $k => $v) {
        $encryptedLen = strlen($encrypted[$k]);
        $decypted = $encrypted[$k] ^ str_repeat(chr($topChars[$k]), $encryptedLen);