douju9272 2014-08-23 13:15
浏览 63


I am developing a client-side app in Go that relies on AES CFB. The server-side is written in C. My problem is that Go's AES CFB implementation appears to differ from many others (including OpenSSL). I wrote this to test my theory:-

package main

import (

func encrypt_aes_cfb(plain, key, iv []byte) (encrypted []byte) {
  block, err := aes.NewCipher(key)
  if err != nil {
  encrypted = make([]byte, len(plain))
  stream := cipher.NewCFBEncrypter(block, iv)
  stream.XORKeyStream(encrypted, plain)

func decrypt_aes_cfb(encrypted, key, iv []byte) (plain []byte) {
  block, err := aes.NewCipher(key)
  if err != nil {
  plain = make([]byte, len(encrypted))
  stream := cipher.NewCFBDecrypter(block, iv)
  stream.XORKeyStream(plain, encrypted)

func main() {
  plain := []byte("Hello world.....")
  key := []byte("01234567890123456789012345678901")
  iv := []byte("0123456789012345")
  enc := encrypt_aes_cfb(plain, key, iv)
  dec := decrypt_aes_cfb(enc, key, iv)
  fmt.Println("Key: ", hex.EncodeToString(key))
  fmt.Println("IV:  ", hex.EncodeToString(iv))
  fmt.Println("Enc: ", hex.EncodeToString(enc))
  fmt.Println("In:  ", hex.EncodeToString(plain))
  fmt.Println("Out: ", hex.EncodeToString(dec))

When this is run, it appears to work perfectly, however, if the encrypted bytes are pasted into another AES implementation and decrypted using the same key and IV, the plaintext is corrupted (except for the first Byte). provides a simple means to test this. Any suggestions why this might be happening and how I can resolve it?

Thanks Steve

  • 写回答

2条回答 默认 最新

  • douhu2370 2014-08-23 14:43

    I investigated this with the following inputs because I was unsure of the bit/byte order for both inputs and outputs :

    Key:  00000000000000000000000000000000
    IV:   00000000000000000000000000000000
    Enc:  66
    In:   00
    Out:  00

    Which matches the tool you provided, and then this :

    Key:  00000000000000000000000000000000
    IV:   00000000000000000000000000000000
    Enc:  66e94b
    In:   000000
    Out:  000000

    Which doesn't match the tool :


    The first byte matches, which indicates there may be a feedback issue.

    So I checked the Go package's code and I think there is a bug here :

    func (x *cfb) XORKeyStream(dst, src []byte) {
        for len(src) > 0 {
            if x.outUsed == len(x.out) {
                x.outUsed = 0
            if x.decrypt {
                // We can precompute a larger segment of the
                // keystream on decryption. This will allow
                // larger batches for xor, and we should be
                // able to match CTR/OFB performance.
                copy([x.outUsed:], src)
            n := xorBytes(dst, src, x.out[x.outUsed:])
            if !x.decrypt {
                copy([x.outUsed:], dst) // BUG? `dst` should be `src`
            dst = dst[n:]
            src = src[n:]
            x.outUsed += n


    After a second look at CFB mode it seems that Go's code is fine, so yeah it may be the other implementations are wrong.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
  • doudou7361 2014-08-25 18:22

    (Firstly, an obligatory warning: CFB mode is a sign of homegrown crypto. Unless you're implementing OpenPGP you should be using an AE mode like AES-GCM or NaCl's secretbox. If you're forced to use CFB mode, I hope that you're authenticating ciphertexts with an HMAC at least.)

    With that aside, CFB mode in Go is there for OpenPGP support. (OpenPGP uses both a tweaked CFB mode called OCFB, and standard CFB mode in different places.) The Go OpenPGP code appears to interoperate with other implementations at least.

    Nick is correct that test vectors are missing in the Go crypto package. The testing was coming from the OpenPGP code, but packages should stand alone and so I'll add tests to crypto/cipher with the test vectors from section F.3.13 of [1].

    My best guess for the source of any differences is that CFB is parameterised by a chunk size. This is generally a power of two number of bits up to the block size of the underlying cipher. If the chunk size isn't specified then it's generally taken to be the cipher block size, which is what the Go code does. See [1], section 6.3. A more friendly explanation is given by [2].

    Small chunk sizes were used in the dark ages (the late 90s) when people worried about things like cipher resync in the face of ciphertext loss. If another implementation is using CFB1 or CFB8 then it'll be very different from Go's CFB mode and many others. (Go's code does not support smaller chunk sizes.)






  • ¥15 matlab+波形匹配算法
  • ¥15 转录组分析做聚类树图时癌旁组被分到了癌组
  • ¥15 大一Python字典
  • ¥15 multisim电路设计(相关搜索:设计报告)
  • ¥15 PC-lint Plus
  • ¥15 gpl24676注释
  • ¥15 php5.3内存泄露
  • ¥15 DigSilent如何复制复合模型到自己案例?
  • ¥15 求日版华为b610s-77a 官方公版固件,有偿
  • ¥15 关于#java#的问题,请各位专家解答!(相关搜索:java程序)