Go的aes.NewCipher panic“invalid key size”是因为AES仅支持16/24/32字节密钥,字符串直接作密钥易长度不符;应哈希截取或用scrypt/pbkdf2派生;解密时需避免src/dst重叠,并正确处理PKCS#7填充。

Go 的 aes.NewCipher 为什么总 panic “invalid key size”
因为 AES 只接受 128/192/256 位密钥(即 16/24/32 字节),传入的 key 长度必须严格匹配。常见错误是直接用字符串当密钥——比如 "my-secret" 长度是 9,既不是 16 也不是 24 或 32。
实操建议:
- 用
sha256.Sum256或md5.Sum128对原始密钥哈希后截取对应长度(如 AES-256 就取前 32 字节) - 更稳妥的做法是走标准密钥派生:
scrypt.Key或pbkdf2.Key,尤其当密钥来自用户口令时 - 硬编码密钥调试可以临时用
[]byte{0x00, 0x01, ..., 0x1F}(32 个字节)快速验证流程是否通
解密时 cipher.NewCBCDecrypter 报 “crypto/cipher: invalid buffer overlap”
这是 Go 标准库对内存安全的强制检查:解密目标切片(dst)不能和源切片(src)有重叠,哪怕只是尾部对齐也不行。典型场景是原地解密——把密文切片传给 crypter.Crypt 同时又让它写回同一块内存。
正确做法:
- 分配新切片:
plaintext := make([]byte, len(ciphertext)),再调用crypter.Crypt(plaintext, ciphertext) - 如果必须复用内存,先
copy密文到临时缓冲区,再解密到目标位置 - CBC 模式下,密文长度必须是块大小(16 字节)的整数倍,否则会 panic;记得提前校验
len(ciphertext)%aes.BlockSize == 0
解密后数据末尾一堆 \x07 或乱码,是不是算法错了
大概率是 PKCS#7 填充没正确去除。AES-CBC 本身不处理填充,Go 的 cipher 包只做块加解密,填充/去填需要自己实现或借助第三方库(如 golang.org/x/crypto/pkcs7)。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
关键点:
- 解密后最后一个字节就是填充长度
n,需检查最后n字节是否都等于n,且n ≤ aes.BlockSize - 别直接
bytes.TrimRight(plain, "\x07")—— 这会误删原文末尾真正的\x07 - 推荐用
pkcs7.Unpad,它会做完整校验,失败返回 error,比手撕安全得多 - 如果加密端用的是 ZeroPadding 或 ANSI X.923,Go 标准库不支持,必须手动对齐逻辑
从 Java/Python 解密过来的 AES 数据总失败,怎么对齐参数
跨语言 AES 失败几乎全是参数不一致导致的,重点盯这三项:
- 密钥和 IV 必须完全二进制一致——Base64、hex、UTF-8 字符串编码方式要统一。Java 的
SecretKeySpec默认按字节用,Python 的pycryptodome也默认 raw bytes,Go 里就别用string转[]byte去碰运气 - CBC 模式下 IV 必须和加密时完全相同,且长度固定为
aes.BlockSize(16 字节)。常见坑:Java 加密时用了随机 IV 但没随密文一起传输 - 字符编码陷阱:如果原始明文是 UTF-8 字符串,加密前必须明确
[]byte("hello"),而不是unsafe.String或其他编码转换
最省事的调试方式:用已知明文 + 固定密钥 + 固定 IV,在各语言里分别加密,比对密文十六进制输出是否一字不差。
IV 和密钥长度、填充方式、模式选择这些地方,错一个字节就全盘失败,没有模糊匹配余地。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










