1 回答

TA贡献1880条经验 获得超4个赞
在线工具结果的密文,如果是明文:
aaaaaaaaaaaa{"key1": "value1", "key2": "value2"}
用 PKCS#7 填充,发布的密钥和 IV 是 UTF8 编码的。由于明文的大小(48 字节)已经是块大小(AES 为 16 字节)的整数倍,因此根据PKCS#7 填充规则填充一个完整的块,从而产生 64 字节的明文和密文。
从问题中不清楚使用的是哪种在线工具,但可以使用任何可靠的加密工具(例如 CyberChef,s。这个在线计算。CyberChef 默认为 AES/CBC 应用 PKCS#7 填充。
发布的代码会产生不同的密文,因为:
没有应用 PKCS#7 填充。这使得密文短了一个块(即最后一个块ccd202bac41937be75731f23796f1516丢失了)。
aes.BlockSize + len(plaintext)
为密文分配了字节大小。这导致分配的大小字节太大aes.BlockSize
(即密文末尾包含 16 个 0x00 值)。
因此,要使 Go 代码生成与在线工具相同的密文,1. 必须添加 PKCS#7 填充,并且 2.len(plaintext)
必须为密文分配仅字节的大小。
以下代码是一个可能的实现(对于 PKCS#7 ,使用pkcs7pad填充):
import (
...
"github.com/zenazn/pkcs7pad"
)
...
key := []byte("b8ae2fe8669c0401fb289e6ab6247924")
iv := []byte("e0332fc2a9743e4f")
plaintext := []byte("aaaaaaaaaaaa{\"key1\": \"value1\", \"key2\": \"value2\"}")
plaintext = pkcs7pad.Pad(plaintext, aes.BlockSize) // 1. pad the plaintext with PKCS#7
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(plaintext)) // 2. allocate len(plaintext)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, plaintext)
fmt.Printf("%x\n", ciphertext) // caf8fe667f4087e1b67d8c9c57fcb1f56b368cafb4bfecbda1e481661ab7b93d87703fb140368d3034d5187c53861c74ccd202bac41937be75731f23796f1516
请注意,由于 PKCS#7 填充,a不再需要显式填充。
上述代码中使用的静态IV 是一个漏洞,因为它会导致密钥/IV 对的重用,这是不安全的。因此,在实践中,通常会为每次加密生成一个随机 IV。IV 不是秘密的,是解密所必需的,并且通常与密文连接在一起。在解密端,将IV和密文分开,用于解密。
由于 IV 的大小对应于块大小,aes.BlockSize + len(plaintext)因此必须为密文分配一个大小,它等于原始代码中的大小。可能这不是偶然的,而是在设计时考虑了随机 IV,但后来没有实现。一个后续的实现是:
import (
...
"crypto/rand"
"io"
"github.com/zenazn/pkcs7pad"
)
...
key := []byte("b8ae2fe8669c0401fb289e6ab6247924")
plaintext := []byte("{\"key1\": \"value1\", \"key2\": \"value2\"}")
plaintext = pkcs7pad.Pad(plaintext, aes.BlockSize)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
_, err = io.ReadFull(rand.Reader, iv) // create a random IV
if err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
fmt.Printf("%x\n", ciphertext)
输出的前 16 个字节对应于(随机)IV,其余对应于实际密文。
- 1 回答
- 0 关注
- 308 浏览
添加回答
举报