加密前必须补位,否则 Encrypt 会 panic;需用 PKCS#7 补位并验证移除,IV 必须随机且每次不同,密钥长度仅支持 16/24/32 字节,解密时须校验补位合法性。

加密前必须补位,否则 Encrypt 会 panic
Go 标准库的 crypto/aes 要求明文长度必须是块大小(16 字节)的整数倍。直接传入任意长度字符串调用 aes.NewCipher 后的 cipher.NewCBCEncrypter 会触发 panic: crypto/cipher: input not full blocks。
常见做法是使用 PKCS#7 补位(注意不是 PKCS#5,二者在 AES 场景下等价,但实现要一致):
- 补位字节数 =
16 - len(data)%16,若整除则补 16 字节 - 每个补位字节值等于补位长度(如补 3 字节,则填
\x03\x03\x03) - 解密后必须验证并移除补位,不能只截取原始长度(因为原始字符串可能含末尾
\x00)
iv 必须随机且每次加密不同,但不需要保密
CBC 模式依赖初始化向量 iv 打乱模式,重复使用同一 iv + 同一密钥会导致相同明文产生相同密文,严重削弱安全性。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 生成:用
crypto/rand.Read(iv)填充 16 字节切片 - 传输:把
iv拼在密文前(如iv + ciphertext),解密时先拆出前 16 字节 - 不要硬编码
iv,也不要复用iv—— 即使密钥变了也不行
密钥长度只能是 16 / 24 / 32 字节,对应 AES-128 / AES-192 / AES-256
Go 的 aes.NewCipher 仅接受这三种长度。传入 32 字节密钥却误以为是“字符串长度”而截断,或用 md5.Sum(16 字节)当 AES-256 密钥,都会导致 panic: crypto/aes: invalid key size。
安全建议:
- 避免直接用用户密码当密钥;应通过
crypto/sha256或golang.org/x/crypto/pbkdf2衍生密钥 - 若必须从字符串生成密钥,至少用
sha256.Sum256取前 32 字节(AES-256) - 密钥切片需显式转换为
[]byte,不能直接传string
解密失败时别只检查 error,要验证补位合法性
解密后得到的字节切片可能看似正常,但若 iv 错、密钥错、或密文被篡改,PKCS#7 补位可能非法(如末字节为 \x0F 但只剩 2 字节),此时直接 data[:len(data)-pad] 会 panic 或返回垃圾数据。
正确做法:
- 取最后一个字节
pad := int(data[len(data)-1]) - 检查
pad > 0 && pad <= 16 && len(data) >= pad - 再遍历最后
pad字节是否都等于byte(pad) - 全部通过才裁剪,否则返回错误(不是忽略)
实际中,哪怕只是 iv 传错一个字节,解密后补位校验几乎必失败 —— 这正是设计目的:让错误暴露得早、明显。


















