func BreakXorRepeating(ciphertext []byte, keysizes []int) ([]byte, error) { if len(ciphertext) == 0 { return nil, errors.New("empty ciphertext") } if len(keysizes) == 0 { return nil, errors.New("no keysizes given") } var bestScore = 0.0 var plaintext []byte for _, size := range keysizes { split, _ := bytes.SplitIntoBlocks(ciphertext, size) transposed, err := blocks.Transpose(split) if err != nil { return nil, err } key := make([]byte, size) for i, block := range transposed { popular, _ := bytes.Popular(block, 1) key[i] = popular[0] } decrypted, _ := bytes.XorRepeatingKey(ciphertext, key) score := utils.EnglishScore(string(decrypted)) if score > bestScore { plaintext = decrypted bestScore = score } } return plaintext, nil }
// Detect single-character XOR func c4() (actual, expected Result) { expected = string([]byte{110, 79, 87, 0, 84, 72, 65, 84, 0, 84, 72, 69, 0, 80, 65, 82, 84, 89, 0, 73, 83, 0, 74, 85, 77, 80, 73, 78, 71, 42}) input, err := ioutil.ReadFile("input/4.txt") if err != nil { panic(err) } lines := strings.Split(string(input), "\n") var bestScore = 0.0 var plaintext string // Find the most popular byte in each line for i := 0; i < len(lines)-1; i++ { line, err := hex.DecodeString(lines[i]) if err != nil { log.Println(err) continue } key, err := bytes.Popular(line, 1) if err != nil { log.Println(err) continue } decrypted, err := bytes.XorRepeatingKey(line, key) if err != nil { log.Println(err) continue } // Score each string for how likely it is English decryptedStr := string(decrypted) score := utils.EnglishScore(decryptedStr) if score > bestScore { bestScore = score plaintext = decryptedStr } } return plaintext, expected }