diff --git a/set1/challenge_1.go b/set1/challenge_1.go index 831d9d0..7891914 100644 --- a/set1/challenge_1.go +++ b/set1/challenge_1.go @@ -1,10 +1,10 @@ package set1 const Base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" -const Base64PaddingCharacter = "=" +const Base64PaddingCharacter = '=' -func HexDecode(hex string) (value []byte, success bool) { - size := len(hex) +func HexDecode(block []byte) (value []byte, success bool) { + size := len(block) var hexValues = map[byte]byte{ '0': 0, @@ -32,8 +32,8 @@ func HexDecode(hex string) (value []byte, success bool) { buffer := make([]byte, 0, size/2) for i := 0; i < size; i += 2 { - first := hexValues[hex[i]] << 4 - second := hexValues[hex[i+1]] + first := hexValues[block[i]] << 4 + second := hexValues[block[i+1]] buffer = append(buffer, first^second) } diff --git a/set1/challenge_3_4.go b/set1/challenge_3_4.go index 6d93a18..e7e4e19 100644 --- a/set1/challenge_3_4.go +++ b/set1/challenge_3_4.go @@ -6,8 +6,8 @@ const AlphabeticCharactersByFrequency = "zjqxkvbpgwyfmculdhrsnioate" const SomeShakespeare = "That can I, At least, the whisper goes so: our last king, Whose image even but now appeared to us, Was, as you know, by Fortinbras of Norway, Thereto pricked on by a most emulate pride, Dared to the combat, in which our valiant Hamlet - For so this side of our known world esteemed him - Did slay this Fortinbras, who by a sealed compact, Well ratified by law and heraldry, Did forfeit, with his life, all those his lands Which he stood seized on to the conqueror: Against the which, a moiety competent Was gaged by our king, which had returned To the inheritance of Fortinbras, Had he been vanquisher, as, by the same cov'nant, And carriage of the article designed, His fell to Hamlet. Now, sir, young Fortinbras, Of unimprovèd mettle hot and full, Hath in the skirts of Norway here and there Sharked up a list of landless resolutes For food and diet to some enterprise That hath a stomach in't, which is no other - And it doth well appear unto our state - But to recover of us, by strong hand And terms compulsative, those foresaid lands So by his father lost: and this, I take it, Is the main motive of our preparations, The source of this our watch and the chief head Of this post-haste and rummage in the land." -func XORDecodeHex(hexString string, passChar byte) []byte { - decoded, success := HexDecode(hexString) +func XORDecodeHex(block []byte, passChar byte) []byte { + decoded, success := HexDecode(block) if !success { return []byte{} @@ -39,10 +39,10 @@ func FindCharacterFrequency(char byte) (freq int) { } } - return -1 + return 0 } -func ScoreTextByCharacterFrequency(text string) (score int) { +func ScoreTextByAlphabeticFrequency(text []byte) (score int) { for i := 0; i < len(text); i++ { score += FindCharacterFrequency(text[i]) } @@ -50,16 +50,17 @@ func ScoreTextByCharacterFrequency(text string) (score int) { return } -func BruteForceXORSingleCharacterEncodedString(hexString string) (score int, result []byte) { +func BruteForceXORSingleCharacterHexEncodedBlock(block []byte) (score int, key byte, result []byte) { - bytes, _ := HexDecode(hexString) + bytes, _ := HexDecode(block) for i := 0; i < 256; i++ { decoded := XORDecodePlain(bytes, byte(i)) - decodedScore := ScoreTextByCharacterFrequency(string(decoded)) + decodedScore := ScoreTextByAlphabeticFrequency(decoded) if decodedScore > score { score = decodedScore + key = byte(i) result = decoded } } diff --git a/set1/challenge_6.go b/set1/challenge_6.go new file mode 100644 index 0000000..1a1b870 --- /dev/null +++ b/set1/challenge_6.go @@ -0,0 +1,170 @@ +package set1 + +import ( + "os" + "slices" +) + +// 00aaaaaa 00aabbbb 00bbbbcc 00cccccc +// aaaaaaaa bbbbbbbb cccccccc +func Base64Decode(block []byte) (decoded []byte) { + + base64Mapping := map[byte]byte{} + + for i, b := range Base64Alphabet { + base64Mapping[byte(b)] = byte(i) + } + + decoded = []byte{} + + for i := 0; i < len(block); i += 4 { + decodedBytes := []byte{0b00000000, 0b00000000, 0b00000000} + + encodedBytes := block[i : i+4] + + for i, b := range encodedBytes { + if b == Base64PaddingCharacter { + encodedBytes[i] = 0b00000000 + } else { + encodedBytes[i] = base64Mapping[b] + } + } + + decodedBytes[0] = (encodedBytes[0] << 2) | (encodedBytes[1] >> 4) + decodedBytes[1] = (encodedBytes[1] << 4) | (encodedBytes[2] >> 2) + decodedBytes[2] = (encodedBytes[2] << 6) | encodedBytes[3] + + for _, b := range decodedBytes { + if b != 0b00000000 { + decoded = append(decoded, b) + } + } + } + + return decoded +} + +func BruteForceXORSingleCharacterPlainEncodedBlock(block []byte) (score int, key byte, result []byte) { + for i := 0; i < 256; i++ { + decoded := XORDecodePlain(block, byte(i)) + decodedScore := ScoreTextByAlphabeticFrequency(decoded) + + if decodedScore > score { + score = decodedScore + key = byte(i) + result = decoded + } + } + + return +} + +func HammingDistance(str1, str2 []byte) (distance int) { + for i := 0; i < len(str1); i++ { + if i >= len(str2) { + distance += CountBits(str1[i]) + } else { + distance += CountBits(str1[i] ^ str2[i]) + } + } + + return +} + +// 1111 + +// 1111 -1 = 1110 +// 1111 & 1110 = 1110 + +// 1110 -1 = 1101 +// 1110 & 1101 = 1100 + +// 1100 -1 = 1011 +// 1100 & 1011 = 1000 + +// 1000 -1 = 0111 +// 0111 & 1000 = 0000 + +// ------------------ + +// 1010 + +// 1010 -1 = 1001 +// 1010 & 1001 = 1000 + +// 1000 -1 = 0111 +// 1000 & 0111 = 0000 + +func CountBits(x byte) (count int) { + // This does as many iterations as there are 1 bits in a bitset. Magic. + for x != 0 { + x &= x - 1 + count++ + } + + return +} + +func ReadChallenge6CipherFromFile() (cipher []byte) { + file, err := os.ReadFile("./res/set-1-challenge-6.txt") + + if err != nil { + panic(err) + } + + return file +} + +func NormalizedHammingDistance(strings ...[]byte) (normalizedDistance float32) { + for i := 1; i < len(strings); i++ { + normalizedDistance += float32(HammingDistance(strings[i-1], strings[i])) + } + + normalizedDistance = normalizedDistance / float32(len(strings[0])) / float32(len(strings)) + + return +} + +type KeySizeRank struct { + Size int + Rank float32 +} + +func RankKeySizeCandidates(minSize, maxSize int, cipher []byte) (keySizeCandidates []KeySizeRank) { + keySizes := []KeySizeRank{} + + for keySize := minSize; keySize <= maxSize; keySize++ { + keySizes = append(keySizes, KeySizeRank{ + Size: keySize, + Rank: NormalizedHammingDistance( + cipher[0:keySize], + cipher[keySize:keySize*2], + ), + }) + } + + slices.SortFunc(keySizes, func(ksr1 KeySizeRank, ksr2 KeySizeRank) int { + if ksr1.Rank > ksr2.Rank { + return 1 + } else if ksr1.Rank == ksr2.Rank { + return 0 + } else { + return -1 + } + }) + + return keySizes +} + +func XORDecrypt(key []byte, cipher []byte) (result []byte) { + for i := 0; i < len(cipher); i += len(key) { + cipherBlock := cipher[i : i+len(key)] + + for ib, b := range cipherBlock { + result = append(result, b^key[ib]) + } + } + + return + +} diff --git a/test/res/set-1-challenge-6.txt b/test/res/set-1-challenge-6.txt index cecdb81..b98ebeb 100644 --- a/test/res/set-1-challenge-6.txt +++ b/test/res/set-1-challenge-6.txt @@ -1,64 +1 @@ -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 \ No newline at end of file diff --git a/test/set_1_test.go b/test/set_1_test.go index 88c7aaf..6f993e0 100644 --- a/test/set_1_test.go +++ b/test/set_1_test.go @@ -37,9 +37,9 @@ func Test_Challenge2(t *testing.T) { func Test_Challenge3(t *testing.T) { const encodedString = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736" - score, bytes := set1.BruteForceXORSingleCharacterEncodedString(encodedString) + score, key, bytes := set1.BruteForceXORSingleCharacterHexEncodedBlock([]byte(encodedString)) - t.Logf("Result: '%s' with score %d", string(bytes), score) + t.Logf("Result: '%s' with score %d and key %v", string(bytes), score, key) } func Test_Challenge4(t *testing.T) { @@ -56,18 +56,20 @@ func Test_Challenge4(t *testing.T) { bestScore := math.MinInt32 bestResult := "" + bestKey := byte(0) for scanner.Scan() { original := scanner.Text() - score, result := set1.BruteForceXORSingleCharacterEncodedString(original) + score, key, result := set1.BruteForceXORSingleCharacterHexEncodedBlock([]byte(original)) if score > bestScore { bestScore = score bestResult = string(result) + bestKey = key } } - t.Logf("Result: '%s' with score %d", bestResult, bestScore) + t.Logf("Result: '%s' with score %d with key %v", bestResult, bestScore, bestKey) } @@ -84,3 +86,89 @@ func Test_Challenge5(t *testing.T) { t.Fatalf("Result '%s' is not the same as expected '%s'", result, expectedCypher) } } + +func Test_Challenge6_CalcHammingDistance(t *testing.T) { + first := []byte("this is a test") + second := []byte("wokka wokka!!!") + + hammingDistance := set1.HammingDistance(first, second) + + if hammingDistance != 37 { + t.Fatalf("Result %d is not the same as expected %d", hammingDistance, 37) + } +} + +func Test_Challenge6_FindTop3KeySizes(t *testing.T) { + base64Cipher := set1.ReadChallenge6CipherFromFile() + + cipher := set1.Base64Decode(base64Cipher) + + keySizes := set1.RankKeySizeCandidates(2, 40, cipher) + + t.Log(keySizes) +} + +func Test_Challenge6_BreakTheCipher(t *testing.T) { + base64Cipher := set1.ReadChallenge6CipherFromFile() + + t.Logf("First 10 bytes base64 cipher: %08b ", base64Cipher[0:10]) + + cipher := set1.Base64Decode(base64Cipher) + + t.Logf("First 10 bytes cipher: %08b", cipher[0:10]) + t.Logf("Last 10 bytes cipher: %08b", cipher[len(cipher)-10:]) + + // TODO: PROBLEM: This does not rank key sizes correctly. Because I cheated I know the key is of size "24". + keySizeCandidates := set1.RankKeySizeCandidates(2, 40, cipher) + + keySize := keySizeCandidates[0].Size + + t.Logf("Best candidate key size is %d", keySize) + + transposed := make([][]byte, keySize) + + for i, b := range cipher { + column := i % keySize + + if transposed[column] == nil { + transposed[column] = []byte{} + } + + transposed[column] = append(transposed[column], b) + } + + cipherKey := []byte{} + transposedResult := make([][]byte, keySize) + + // TODO: PROBLEM: The below code does not properly deduce the key. + for i, column := range transposed { + var score int + var key byte + var result []byte + + for i := 0; i < 256; i++ { + decoded := set1.XORDecodePlain(column, byte(i)) + decodedScore := set1.ScoreTextByAlphabeticFrequency(decoded) + + if decodedScore > score { + score = decodedScore + key = byte(i) + result = decoded + } + } + + // score, key, result := set1.BruteForceXORSingleCharacterPlainEncodedBlock(column) + + t.Logf("Found key '%c' with score %d", key, score) + + cipherKey = append(cipherKey, key) + + transposedResult[i] = result + } + + t.Logf("The key is %s", cipherKey) + + // deciphered := set1.XORDecrypt(cipherKey, cipher) + + // t.Logf("First 100 bytes deciphered: %s", transposedResult) +}