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";
    }
}
 $scores = scoreHammedKeySizeRange($data, 2, 40, 10000);
 // 10k sample limit to reduce time taken
 print "Top scoring key sizes:\n";
 $i = 0;
 foreach ($scores as $k => $v) {
     print "{$k} - {$v}\n";
     if (++$i === 3) {
         break;
     }
 }
 $potentialKeys = [];
 print "\nSolving keys based on English Language scoring:\n";
 $i = 0;
 foreach ($scores as $k => $v) {
     $blocks = str_split($data, $k);
     $blocks = transposeBlocks($blocks);
     list($topScores, $topChars) = scoreSingleByteXORStrings($blocks, $englishLanguageWeights);
     $potentialKeys[$k] = implode(array_map('chr', $topChars));
     print "{$k}: {$potentialKeys[$k]}\n";
     if (++$i === 3) {
         break;
     }
 }
 print "\nDecrypted data with solved keys:\n";
 $i = 0;
 foreach ($scores as $k => $v) {
     $decrypted = $data ^ str_repeat($potentialKeys[$k], ceil($dataLen / strlen($potentialKeys[$k])));
     print "{$k}: {$decrypted}\n\n\n";
     if (++$i === 3) {
         break;
     }