我正在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/提供了一种简单的方法来测试它。有什么建议可以解决这个问题以及我如何解决它?
由于 史蒂夫
答案 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的代码很好,所以是的,其他实现可能是错误的。