去AES CFB兼容性

时间:2014-08-23 13:15:12

标签: go cryptography aes

我正在Go中开发一个依赖于AES CFB的客户端应用程序。服务器端用C语言编写。我的问题是Go的AES CFB实现似乎与许多其他实现(包括OpenSSL)不同。我写这篇文章来测试我的理论: -

package main

import (
  "fmt"
  "encoding/hex"
  "crypto/cipher"
  "crypto/aes"
)

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

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

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

当它运行时,它似乎完美地工作,但是,如果加密的字节被粘贴到另一个AES实现并使用相同的密钥和IV解密,则明文被破坏(第一个字节除外)。 http://aes.online-domain-tools.com/提供了一种简单的方法来测试它。有什么建议可以解决这个问题以及我如何解决它?

由于 史蒂夫

2 个答案:

答案 0 :(得分:4)

(首先,强制警告:CFB模式是本土加密的标志。除非您正在实施OpenPGP,否则您应该使用AE模式,如AES-GCM或NaCl的保密箱。如果您&#39 ;被迫使用CFB模式,我希望你至少用HMAC认证密文。)

除此之外,Go中的CFB模式可用于支持OpenPGP。 (OpenPGP在不同的地方使用称为OCFB,标准CFB模式的调整CFB模式。)Go OpenPGP代码似乎至少与其他实现互操作。

Nick认为Go crypto包中缺少测试向量是正确的。测试来自OpenPGP代码,但是软件包应该是独立的,因此我将使用[1]的F.3.13部分中的测试向量向crypto/cipher添加测试。

我对任何差异来源的最佳猜测是CFB由块大小参数化。这通常是两个位的功率,直到底层密码的块大小。如果没有指定块大小,那么它通常被认为是密码块大小,这是Go代码所做的。见[1],第6.3节。 [2]给出了一个更友好的解释。

在黑暗时代(90年代后期)使用小块大小,当人们在密文丢失时担心密码重新同步等问题。如果另一个实现使用CFB1或CFB8,那么它将与Go的CFB模式和许多其他模式非常不同。 (Go的代码不支持较小的块大小。)

[1] http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf

[2] http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29

答案 1 :(得分:2)

我用以下输入对此进行了调查,因为我不确定输入和输出的位/字节顺序:

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

http://play.golang.org/p/wl2y1EE6lK

哪个与您提供的工具相匹配,然后是:

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

http://play.golang.org/p/DNC42m2oU5

哪个匹配该工具:

6616f9

http://aes.online-domain-tools.com/link/63687gDNzymApefh/

第一个字节匹配,表示可能存在反馈问题。

所以我检查了Go包的代码,我认为有一个错误here

func (x *cfb) XORKeyStream(dst, src []byte) {
    for len(src) > 0 {
        if x.outUsed == len(x.out) {
            x.b.Encrypt(x.out, x.next)
            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.next[x.outUsed:], src)
        }
        n := xorBytes(dst, src, x.out[x.outUsed:])
        if !x.decrypt {
            copy(x.next[x.outUsed:], dst) // BUG? `dst` should be `src`
        }
        dst = dst[n:]
        src = src[n:]
        x.outUsed += n
    }
}

<击>

修改

在第二次看CFB模式之后,似乎Go的代码很好,所以是的,其他实现可能是错误的。