2024-10-28 00:05:33 +02:00
|
|
|
package cryptopals_test
|
|
|
|
|
|
|
|
import (
|
2024-10-29 19:21:13 +02:00
|
|
|
"bufio"
|
|
|
|
"math"
|
|
|
|
"os"
|
2024-10-28 00:05:33 +02:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"mvvasilev.dev/cryptopals/set1"
|
|
|
|
)
|
|
|
|
|
|
|
|
const Challenge1HexValue = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"
|
|
|
|
|
|
|
|
func Test_Challenge1(t *testing.T) {
|
|
|
|
const expected = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"
|
|
|
|
|
|
|
|
value, success := set1.HexToBase64(Challenge1HexValue)
|
|
|
|
|
|
|
|
if !success || value != expected {
|
|
|
|
t.Fatal("Set 1, Challenge 1 has failed")
|
|
|
|
}
|
|
|
|
}
|
2024-10-28 17:54:51 +02:00
|
|
|
|
|
|
|
func Test_Challenge2(t *testing.T) {
|
|
|
|
const expected = "746865206b696420646f6e277420706c6179"
|
|
|
|
|
|
|
|
const content = "1c0111001f010100061a024b53535009181c"
|
|
|
|
const password = "686974207468652062756c6c277320657965"
|
|
|
|
|
|
|
|
value := set1.XORHexString(content, password)
|
|
|
|
|
|
|
|
if value != expected {
|
|
|
|
t.Fatal(("Set 1, Challenge 2 has failed"))
|
|
|
|
}
|
|
|
|
}
|
2024-10-28 22:15:03 +02:00
|
|
|
|
|
|
|
func Test_Challenge3(t *testing.T) {
|
|
|
|
const encodedString = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"
|
|
|
|
|
2024-11-02 23:37:12 +02:00
|
|
|
score, key, bytes := set1.BruteForceXORSingleCharacterHexEncodedBlock([]byte(encodedString))
|
2024-10-28 22:15:03 +02:00
|
|
|
|
2024-11-02 23:37:12 +02:00
|
|
|
t.Logf("Result: '%s' with score %d and key %v", string(bytes), score, key)
|
2024-10-29 19:21:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func Test_Challenge4(t *testing.T) {
|
|
|
|
|
|
|
|
file, err := os.Open("./res/set-1-challenge-4.txt")
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2024-10-28 22:15:03 +02:00
|
|
|
|
2024-10-29 19:21:13 +02:00
|
|
|
defer file.Close()
|
2024-10-28 22:15:03 +02:00
|
|
|
|
2024-10-29 19:21:13 +02:00
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
|
|
|
|
bestScore := math.MinInt32
|
|
|
|
bestResult := ""
|
2024-11-02 23:37:12 +02:00
|
|
|
bestKey := byte(0)
|
2024-10-29 19:21:13 +02:00
|
|
|
|
|
|
|
for scanner.Scan() {
|
|
|
|
original := scanner.Text()
|
2024-11-02 23:37:12 +02:00
|
|
|
score, key, result := set1.BruteForceXORSingleCharacterHexEncodedBlock([]byte(original))
|
2024-10-29 19:21:13 +02:00
|
|
|
|
|
|
|
if score > bestScore {
|
|
|
|
bestScore = score
|
|
|
|
bestResult = string(result)
|
2024-11-02 23:37:12 +02:00
|
|
|
bestKey = key
|
2024-10-28 22:15:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-02 23:37:12 +02:00
|
|
|
t.Logf("Result: '%s' with score %d with key %v", bestResult, bestScore, bestKey)
|
2024-10-29 19:21:13 +02:00
|
|
|
|
2024-10-28 22:15:03 +02:00
|
|
|
}
|
2024-10-29 20:36:04 +02:00
|
|
|
|
|
|
|
func Test_Challenge5(t *testing.T) {
|
|
|
|
const key = "ICE"
|
|
|
|
|
|
|
|
originalText := "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"
|
|
|
|
|
|
|
|
expectedCypher := "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f"
|
|
|
|
|
|
|
|
result := string(set1.ConvertToHex(set1.XOREncryptText(originalText, key)))
|
|
|
|
|
|
|
|
if result != expectedCypher {
|
|
|
|
t.Fatalf("Result '%s' is not the same as expected '%s'", result, expectedCypher)
|
|
|
|
}
|
|
|
|
}
|
2024-11-02 23:37:12 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|