Challenge 3: Single-byte XOR cipher
Problem
The hex encoded string:
1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736
... has been XOR'd against a single character. Find the key, decrypt the message.You can do this by hand. But don't: write code to do it for you.How? Devise some method for "scoring" a piece of English plaintext. Character frequency is a good metric. Evaluate each output and choose the one with the best score.
Solution
Resource
This is the frequency of letters in the English language. It is used to score the plaintexts.
byte('E'): 12.02,byte('T'): 9.10,byte('A'): 8.12,byte('O'): 7.68,byte('I'): 7.31,byte('N'): 6.95,byte('S'): 6.28,byte('R'): 6.02,byte('H'): 5.92,byte('D'): 4.32,byte('L'): 3.98,byte('U'): 2.88,byte('C'): 2.71,byte('M'): 2.61,byte('F'): 2.30,byte('Y'): 2.11,byte('W'): 2.09,byte('G'): 2.03,byte('P'): 1.82,byte('B'): 1.49,byte('V'): 1.11,byte('K'): 0.69,byte('X'): 0.17,byte('Q'): 0.11,byte('J'): 0.10,byte('Z'): 0.07,
byte(' '): 8,
byte("a") :08.167,byte("b") :01.492,byte("c") :02.782,byte("d") :04.253,byte("e") :12.702,byte("f") :02.228,byte("g") :02.015,byte("h") :06.094,byte("i") :06.966,byte("j") :00.153,byte("k") :00.772,byte("l") :04.025,byte("m") :02.406,byte("n") :06.749,byte("o") :07.507,byte("p") :01.929,byte("q") :00.095,byte("r") :05.987,byte("s") :06.327,byte("t") :09.056,byte("u") :02.758,byte("v") :00.978,byte("w") :02.360,byte("x") :00.150,byte("y") :01.974,byte("z") :00.074,
Decoded
Code
package challenge3
import ( "fmt"
c1 "cryptopals/Set1/challenge1")
/*XORed against a single string, find the character1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736*/
func charFreq(char byte) float64 { wm := map[byte]float64{ byte('E'): 12.02, byte('T'): 9.10, byte('A'): 8.12, byte('O'): 7.68, byte('I'): 7.31, byte('N'): 6.95, byte('S'): 6.28, byte('R'): 6.02, byte('H'): 5.92, byte('D'): 4.32, byte('L'): 3.98, byte('U'): 2.88, byte('C'): 2.71, byte('M'): 2.61, byte('F'): 2.30, byte('Y'): 2.11, byte('W'): 2.09, byte('G'): 2.03, byte('P'): 1.82, byte('B'): 1.49, byte('V'): 1.11, byte('K'): 0.69, byte('X'): 0.17, byte('Q'): 0.11, byte('J'): 0.10, byte('Z'): 0.07, byte(' '): 8, byte('a'): 8.167, byte('b'): 01.492, byte('c'): 02.782, byte('d'): 04.253, byte('e'): 12.702, byte('f'): 02.228, byte('g'): 02.015, byte('h'): 06.094, byte('i'): 06.966, byte('j'): 00.153, byte('k'): 00.772, byte('l'): 04.025, byte('m'): 02.406, byte('n'): 06.749, byte('o'): 07.507, byte('p'): 01.929, byte('q'): 00.095, byte('r'): 05.987, byte('s'): 06.327, byte('t'): 9.056, byte('u'): 02.758, byte('v'): 00.978, byte('w'): 02.360, byte('x'): 00.150, byte('y'): 01.974, byte('z'): 00.074, } return wm[char]}
func Challenge3() { input1 := []byte("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736")
raw := c1.DecodeHex(input1) fmt.Printf("Raw string:%s\n", raw)
answer, score := SingleXorCipher(raw) fmt.Printf("Answer:%s\nScore:%f", answer, score)}
func SingleXorCipher(raw []byte) ([]byte, float64) { var answer []byte var score float64 for i := 0; i < 256; i++ { tempAns := make([]byte, len(raw)) var tempSc float64 for j := 0; j < len(raw); j++ { c := raw[j] ^ byte(i) tempSc += charFreq(c) tempAns[j] = c } if tempSc > score { answer = tempAns score = tempSc } tempSc = 0 } return answer, score}