public void Challenge6_BreakRepeatingKeyXor() { var data = Utils.GetResourceBase64("RepeatingKeyXor.txt"); var keySizes = Enumerable.Range(2, 40); // this is slightly different than the approach described in the challenge. We // convolve the data against itself and look for the lowest "energy" step. This // is likely where the repeating keys overlap and the plaintext pattern emerges. var convolvedKeySizes = keySizes.ToDictionary(keySize => keySize, keySize => { var padding = Enumerable.Repeat((byte)0, keySize).ToArray(); return(Utils.Hamming(padding.Concat(data), data.Concat(padding))); }).OrderBy(pair => pair.Value); var topKeySizes = convolvedKeySizes.Select(pair => pair.Key).Take(1); // distribute data into bins that align with first key byte, second key byte, etc. var transposedBlocks = topKeySizes.Select( keySize => Enumerable.Range(0, keySize) .Select(keyOffset => data.Where((x, i) => i % keySize == keyOffset).ToArray())); var keySizeKeyErrors = transposedBlocks.Select(pair => pair.Select(k => { byte key; double error; var result = SingleByteXorCracker.Crack(k, out error, out key); return(new { Result = result, Key = key, Error = error }); })); var possibleKeys = keySizeKeyErrors.Select(k => k.Select(r => r.Key).ToArray()); var plaintexts = possibleKeys.ToDictionary(key => key, key => { var transform = new XorCryptoTransform(key); var stream = new MemoryStream(data); using (var cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Read)) { using (var reader = new StreamReader(cryptoStream)) return(reader.ReadToEnd()); } }); var actual = plaintexts.First().Value; var expected = Utils.GetResourceText("Set1PlainText.txt"); Assert.AreEqual(expected, actual); }
public void Challenge5Prep_RoundtripXor() { const string plaintext = "We have nothing to fear but fear itself"; var transform = new XorCryptoTransform(Encoding.ASCII.GetBytes("the key!")); var stream = new MemoryStream(); using (var writerStream = new CryptoStream(stream, transform, CryptoStreamMode.Write)) using (var writer = new StreamWriter(writerStream, Encoding.ASCII, 4096, true)) writer.Write(plaintext); var cipherStream = new MemoryStream(stream.ToArray()); using (var readerStream = new CryptoStream(cipherStream, transform, CryptoStreamMode.Read)) using (var reader = new StreamReader(readerStream)) Assert.AreEqual(plaintext, reader.ReadToEnd()); }
public void Challenge5Prep_RoundtripXor() { const string plaintext = "We have nothing to fear but fear itself"; var transform = new XorCryptoTransform(Encoding.ASCII.GetBytes("the key!")); var stream = new MemoryStream(); using (var writerStream = new CryptoStream(stream, transform, CryptoStreamMode.Write)) using (var writer = new StreamWriter(writerStream, Encoding.ASCII, 4096, true)) writer.Write(plaintext); var cipherStream = new MemoryStream(stream.ToArray()); using (var readerStream = new CryptoStream(cipherStream, transform, CryptoStreamMode.Read)) using (var reader = new StreamReader(readerStream)) Assert.AreEqual(plaintext, reader.ReadToEnd()); }
public void Challenge5_RepeatingKeyXor() { var key = Encoding.ASCII.GetBytes("ICE"); const string plaintext = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"; var transform = new XorCryptoTransform(key); var stream = new MemoryStream(); using (var cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { using (var writer = new StreamWriter(cryptoStream)) writer.Write(plaintext); } var expected = Utils.HexToByteArray( "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f"); var actual = stream.ToArray(); Assert.IsTrue(expected.SequenceEqual(actual)); }
public void Challenge5_RepeatingKeyXor() { var key = Encoding.ASCII.GetBytes("ICE"); const string plaintext = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"; var transform = new XorCryptoTransform(key); var stream = new MemoryStream(); using (var cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { using (var writer = new StreamWriter(cryptoStream)) writer.Write(plaintext); } var expected = Utils.HexToByteArray( "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f"); var actual = stream.ToArray(); Assert.IsTrue(expected.SequenceEqual(actual)); }
public void Challenge6_BreakRepeatingKeyXor() { var data = Utils.GetResourceBase64("RepeatingKeyXor.txt"); var keySizes = Enumerable.Range(2, 40); // this is slightly different than the approach described in the challenge. We // convolve the data against itself and look for the lowest "energy" step. This // is likely where the repeating keys overlap and the plaintext pattern emerges. var convolvedKeySizes = keySizes.ToDictionary(keySize => keySize, keySize => { var padding = Enumerable.Repeat((byte) 0, keySize).ToArray(); return Utils.Hamming(padding.Concat(data), data.Concat(padding)); }).OrderBy(pair => pair.Value); var topKeySizes = convolvedKeySizes.Select(pair => pair.Key).Take(1); // distribute data into bins that align with first key byte, second key byte, etc. var transposedBlocks = topKeySizes.Select( keySize => Enumerable.Range(0, keySize) .Select(keyOffset => data.Where((x, i) => i % keySize == keyOffset).ToArray())); var keySizeKeyErrors = transposedBlocks.Select(pair => pair.Select(k => { byte key; double error; var result = SingleByteXorCracker.Crack(k, out error, out key); return new { Result = result, Key = key, Error = error }; })); var possibleKeys = keySizeKeyErrors.Select(k => k.Select(r => r.Key).ToArray()); var plaintexts = possibleKeys.ToDictionary(key => key, key => { var transform = new XorCryptoTransform(key); var stream = new MemoryStream(data); using (var cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Read)) { using (var reader = new StreamReader(cryptoStream)) return reader.ReadToEnd(); } }); var actual = plaintexts.First().Value; var expected = Utils.GetResourceText("Set1PlainText.txt"); Assert.AreEqual(expected, actual); }