Botched Challenge 6

This commit is contained in:
Miroslav Vasilev 2024-11-02 23:37:12 +02:00
parent 12e4ff4060
commit 2eb6717724
5 changed files with 276 additions and 80 deletions

View file

@ -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)
}

View file

@ -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
}
}

170
set1/challenge_6.go Normal file
View file

@ -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
}

View file

@ -1,64 +1 @@
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

View file

@ -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)
}