package ixee.cryptopals.test import com.ixee.IxeeSpec class Set1Spec extends IxeeSpec { import ixee.cryptopals.utils.ConversionUtils._ import ixee.cryptopals.utils.ByteUtils._ import ixee.cryptopals.utils.StreamUtils._ import ixee.cryptopals.solvers._ "Set1" - { "Challenge 1: converts from a hex string to base64" in { hexStr2Base64String( "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d" ) mustBe( "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t" ) } "Challenge 2: xor's two equal-length buffers" in { val a = hexStr2Bytes( "1c0111001f010100061a024b53535009181c" ) val b = hexStr2Bytes( "686974207468652062756c6c277320657965" ) (a xor b).hex mustBe "746865206b696420646f6e277420706c6179" } "Challenge 3: single-byte xor cipher" in { XorDecrypt.findBestSingleByteKey( hexStr2Bytes( "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736" ) ) mustBe 88.toByte } "Challenge 4: detecting single-byte xor" - { "Decrypts and reports the line of the single-byte xor" in { Challenge4.run("./data/4.txt") mustBe (("Now that the party is jumping\n", 170)) } } "Challenge 5: repeating-key xor" in { val sourceText = """|Burning 'em, if you ain't quick and nimble |I go crazy when I hear a cymbal""".stripMargin val key = "ICE" val ciphertext = sourceText.asBytes.to[Stream] xor key.asBytes.to[Stream].continually ciphertext.hex mustBe( Seq( "0b3637272a2b2e63622c2e69", "692a23693a2a3c6324202d62", "3d63343c2a26226324272765", "272a282b2f20430a652e2c65", "2a3124333a653e2b2027630c", "692b20283165286326302e27", "282f" ).mkString("") ) } "Challenge 6: break repeating-key xor" - { "hamming distance should be computed correctly" in { val textA = "this is a test" val textB = "wokka wokka!!!" hammingDistance(textA, textB) mustBe 37 } "prioritizes likely key sizes" in { val sourceText = """|the quick brown fox jumps over the lazy dog |This code is going to turn out to be surprisingly useful later on. |Breaking repeating-key XOR ("Vigenere") statistically is obviously | an academic exercise, a "Crypto 101" thing. But more people "know | how" to break it than can actually break it, and a similar | technique breaks something much more important.""".stripMargin.replace("\n", "") val key = "ICE IS REALLY NICE" val ciphertext = sourceText.asByteStream xor key.asByteStream.continually val expectedKeySize = XorDecrypt.inferKeySize(ciphertext) expectedKeySize mustBe key.length } "cracks multi-byte keys" in { val sourceText = """|the quick brown fox jumps over the lazy dog |This code is going to turn out to be surprisingly useful later on. |Breaking repeating-key XOR statistically is obviously | an academic exercise, a "Crypto 101" thing. But more people "know | how" to break it than can actually break it, and a similar | technique breaks something much more important.""".stripMargin.replace("\n", "") val key = "ICE IS REALLY NICE" val ciphertext = sourceText.asByteStream xor key.asByteStream.continually XorDecrypt.findBestMultiByteKey(ciphertext).take(key.length).asAscii mustBe key XorDecrypt.crackForMultiByteKey(ciphertext) mustBe sourceText } "cracks the challenge text" in { Challenge6.run mustBe Challenge6.expectation } } "Challenge 7: AES/ECB mode" in { Challenge7.run mustBe Challenge6.expectation } "Challenge 8: Detect ECB" in { Challenge8.run mustBe 133 } } }