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 }
/* CBC padding oracle * Write a CBC padding oracle that decrypts a ciphertext and detects * if the plaintext is padded properly with PKCS#7. Choose a random line * from 17.txt, encrypt it, then decrypt it using the oracle. */ func c17() (actual, expected Result) { input, _ := ioutil.ReadFile("input/17.txt") strs := strings.Split(string(input), "\n") str := strs[r.Intn(10)] decodedStr, _ := base64.StdEncoding.DecodeString(str) if crypto.GlobalAesKey == nil { crypto.GlobalAesKey = crypto.NewAesKey() } key := crypto.GlobalAesKey iv, _ := bytes.Random(aes.BlockSize) ciphertext, err := crypto.CbcEncrypt([]byte(decodedStr), key, iv) if err != nil { log.Fatal(err) } blocks, err := bytes.SplitIntoBlocks(ciphertext, aes.BlockSize) if err != nil { log.Fatal(err) } var plaintext []byte for n := 0; n < len(blocks); n++ { block := blocks[n] controlled := make([]byte, aes.BlockSize) plaintextBlock := make([]byte, aes.BlockSize) intermediate := make([]byte, aes.BlockSize) prevBlock := make([]byte, aes.BlockSize) if n == 0 { prevBlock = iv } else { prevBlock = blocks[n-1] } for i := aes.BlockSize - 1; i >= 0; i-- { paddingLen := aes.BlockSize - i paddingByte := byte(paddingLen) // Set the last paddingLen bytes of controlled to so that when decrypted, // each will be a valid padding byte. for j := 0; j < paddingLen; j++ { controlled[i+j] = paddingByte ^ intermediate[i+j] } for b := 0; b <= 256; b++ { controlled[i] = byte(b) controlled := append(controlled, block...) valid, _ := crypto.CbcPaddingOracle(controlled, iv) if valid { // The padding is valid and we control the ith byte of the // block XORed with the intermediate state. XOR is an inverse // operation so finding the ith byte of the intermediate state // is as simple as: intermediate[i] = paddingByte ^ controlled[i] break } } plaintextBlock[i] = prevBlock[i] ^ intermediate[i] } plaintext = append(plaintext, plaintextBlock...) } decrypted, _ := crypto.CbcDecrypt(ciphertext, key, iv) return string(plaintext), string(decrypted) }