aes.NewCipher仅支持16、24、32字节密钥,传入非法长度(如字符串字面量转[]byte)会panic;需用SHA256、PBKDF2或crypto/rand生成合规密钥,IV/nonce须每次随机且唯一,填充用PKCS#7,比较用subtle.ConstantTimeCompare。

Go 的 aes.NewCipher 为什么总 panic “invalid key size”
因为 aes.NewCipher 只接受 16、24 或 32 字节的密钥,对应 AES-128、AES-192、AES-256。传入长度不对的 []byte(比如从字符串直接 []byte("mykey"))就会 panic。
常见错误现象:panic: crypto/aes: invalid key size 5 —— 说明你用了 5 字节的 key。
- 密钥必须严格按标准长度:用
sha256.Sum256或hmac.SHA256摘要后截取,或用crypto/rand.Read生成原始密钥 - 别用字符串字面量直接转
[]byte,ASCII 字符串长度 ≠ 密钥长度需求 - 如果你只有口令(password),必须用
pbkdf2.Key或scrypt.Key衍生,不能直接当 AES key 用
用 cipher.BlockMode 加密时,IV 长度和填充怎么配
AES 是分组密码,cipher.BlockMode(如 cipher.NewCBCEncrypter)要求 IV 长度 = 分组大小 = 16 字节。它不处理填充,填充得自己来。
使用场景:HTTP API 请求体加密、本地配置文件加密等需要可预测结构的场合。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- IV 必须每次加密都随机生成(用
crypto/rand.Read),且和密文一起传输/存储 —— 它不保密,但绝不能复用 - PKCS#7 填充最常用:明文末尾补 N 个字节,值都是 N;解密后检查末字节并裁掉。别用“补 0”这种不可逆方式
- GCM 模式不用手动填 IV 和填充,但
cipher.NewGCM返回的是cipher.AEAD,接口完全不同,别混用
cipher.AEAD.Seal 和 Open 的 nonce 参数到底该怎么给
AEAD(如 GCM)用 nonce 代替传统 IV,但它更敏感:**重复使用同一 key + nonce 组合会直接导致密钥泄露**。
性能影响:GCM 比 CBC 快,硬件加速友好;但 nonce 管理不当比 CBC 更危险。
- nonce 长度由具体 AEAD 决定:
aes.NewGCM要求 12 字节(推荐),也可设 8–13 字节,但需确保唯一性 - 安全做法:用 12 字节随机 nonce(
crypto/rand.Read),每次加密都新生成,附在密文前(如append(nonce, sealed...)) - 别用计数器当 nonce 并存错地方 —— 如果服务重启丢状态,计数器回滚就完蛋
- 解密时先切出 nonce,再传给
Open;切错了长度或内容,Open直接返回nil, cipher.ErrInvalidLength
为什么用 bytes.Equal 校验解密结果会引入时序攻击
这不是 AES 特有,但常在验证解密是否成功时踩坑:比如先解密,再用 bytes.Equal(decrypted, expected) 判断是否正确,攻击者可通过响应时间差异反推密文或 key。
容易被忽略的地方:哪怕只是日志里打一句 if !bytes.Equal(...) { log.Println("auth fail") },只要执行路径依赖密文内容,就可能暴露信息。
- 永远用
crypto/subtle.ConstantTimeCompare替代bytes.Equal做密文/认证标签比较 - AEAD 的
Open已内置恒定时间校验,只要它返回nil就可信;不要在Open后再做额外内容比对 - 如果必须校验明文结构(比如 JSON schema),应在解密后用恒定时间逻辑,或干脆不校验——让上层协议处理

















