aes.newcipher 会 panic,原因是密钥长度必须严格为16/24/32字节,否则抛 crypto/aes: invalid key size;cbc需手动pkcs#7填充和随机iv,gcm需防nonce重用,解密乱码须分层排查密钥、iv/nonce及填充或tag截断问题。

aes.NewCipher 会 panic?那不是密钥长度错了,就是你没校验字节长度。Go 的 AES 实现不接受“差不多”,只认 16 / 24 / 32 字节密钥,少一个、多一个都直接崩溃。
密钥长度必须严格为 16 / 24 / 32 字节
常见错误是把字符串字面量直接转 []byte,比如 []byte("mykey123")(8 字节)或 []byte("password-123456789012345678901234")(33 字节)。Go 不会帮你截断或补零,而是直接抛 crypto/aes: invalid key size。
正确做法:
- 从环境变量读取后,用
sha256.Sum256([]byte(raw)).[0:32]派生并固定截取 - 硬编码测试时,显式写满 16 字节:
[]byte("1234567890123456")(别带空格、换行) - 检查长度用
len([]byte(key)),不是len(key)(后者对含中文或 emoji 的字符串会误判)
CBC 模式下必须手动 PKCS#7 填充 + 随机 IV
cipher.NewCBCEncrypter 不会自动填充,明文长度不是 16 的倍数时,CryptBlocks 会 panic:crypto/cipher: input not full block。ECB 虽然省事,但相同明文块永远生成相同密文块,等同于没加密。
安全操作要点:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 填充必须用 PKCS#7:缺
n字节就补n个\x0n;原文刚好 16 倍数时,仍补 16 个\x10 - IV 必须每次加密随机生成 16 字节:
iv := make([]byte, aes.BlockSize); io.ReadFull(rand.Reader, iv) - IV 不保密,但必须和密文一起传输——典型做法是
append(iv, ciphertext...),解密时先切前 16 字节 - 绝不能用
key[:16]或固定字符串当 IV,否则相同明文加密结果恒定
GCM 模式更推荐,但 nonce 重用等于密钥泄露
cipher.NewGCM 返回 AEAD 接口,自动处理认证与加密,无需手动填充、无需额外 HMAC。但它对 nonce(类似 IV)极度敏感:同一密钥下重复使用 nonce,攻击者可直接恢复密钥。
实操建议:
- nonce 长度设 12 字节(Go 默认),用
rand.Read生成,和密文一起存(如append(nonce, ciphertext...)) - 不要自己拼接时间戳或计数器——哪怕概率低,也绝不容许重用
- 解密失败时,
Open方法返回 error,不是乱码;这是 GCM 的关键优势:能明确区分“密钥错”和“密文篡改”
解密后得到乱码?先查这三处
Go 的 AES 解密不会主动 panic,错密钥、错 IV、错填充都会产出看似“成功”的乱码,排查必须分层:
- 确认密钥完全一致:
len(k) == 32且每个字节值相等(注意 base64 编码/解码是否出错) - 确认 IV 或 nonce 是从密文开头正确切出的——CBC 切前 16 字节,GCM 切前 12 字节
- CBC 解密后必须调用 PKCS#7 去填充函数,并校验末尾字节值是否在 1–16 范围内;值为 17 或负数,说明密文被截断或密钥根本不对
最易忽略的是:GCM 模式下,Seal 输出的密文包含认证标签(tag),长度比明文长 16 字节;若手动截断或错切,Open 必然失败——这个长度差,不看文档很容易漏。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










