不是必须补足16字节块,但ECB/CBC模式要求明文长度为块大小整数倍,否则cipher.BlockMode.Encrypt会panic;需用PKCS#7填充并正确去填。

Go 里用 aes.Encrypt 前必须补足 16 字节块?
不是必须,但 aes.NewCipher 底层只接受 128 位(16 字节)密钥,且 ECB/CBC 模式要求明文长度是块大小整数倍。你直接传入任意长度的 []byte 给 cipher.BlockMode.Encrypt 会 panic:crypto/cipher: input not full block。
常见错误是把原始文件内容直接喂给加密函数,没做填充。实际得用 PKCS#7(对 AES 就是 PKCS#5)补位:
- 计算缺多少字节:
pad := 16 - len(src)%16 - 补
pad个字节,每个值都是byte(pad) - 解密后要校验末尾字节是否合法,再截掉——别直接切掉最后 16 字节
为什么 gobuffalo/packr 不适合打包密钥,而该用 go:embed?
密钥硬编码进二进制时,packr 是为资源文件设计的,运行时解压路径不可控,还可能被反编译提取出明文密钥;go:embed 把文件内容编译进只读数据段,至少比字符串字面量稍安全点(虽然仍不防内存 dump)。
更关键的是:密钥不该写死。但若真要 demo 级简单实现:
立即学习“go语言免费学习笔记(深入)”;
- 放一个
key.bin文件,内容正好 32 字节(AES-256) - 代码里用
//go:embed key.bin+embed.FS读取 - 绝对不要用
os.ReadFile("key.bin")——部署时容易漏掉或路径错
文件加密时用 CBC 还是 GCM?选错会导致验证失败
CBC 只提供机密性,不防篡改;GCM 同时提供加密+认证,但 Go 的 cipher.AEAD 接口要求 nonce 长度固定(GCM 是 12 字节),且 nonce 绝对不能复用。
实操建议:
- 用
crypto/aes.NewCipher+cipher.NewGCM,别手撸 CBC+HMAC - 每次加密生成新
nonce(rand.Read(make([]byte, 12))),写在密文开头(12 字节) - 解密时先读前 12 字节当 nonce,剩下的全传给
aead.Open;如果返回nil错误,说明密文被改过或密钥错 - 别用时间戳/计数器当 nonce——没随机性就等于没安全
os.OpenFile 加密大文件卡住?因为没流式处理
一次性读整个文件到内存(io.ReadAll)会爆内存,尤其几百 MB 的日志或视频。AES 本身支持分块加解密,但 Go 的 cipher.Stream(如 CFB、OFB)不带认证,GCM 又不支持流式。
折中方案是分片处理:
- 用
bufio.NewReader+ 固定 buffer(比如 64KB)读源文件 - 每块单独调用
aead.Seal(注意每块要用不同 nonce!可基于块序号派生) - 密文头部写入版本号、块大小、总块数,方便解密时还原
- 别用
io.Copy直接对接加密 writer——GCM 的Seal必须整块调用
真正生产环境该用 age 或 gpg CLI,自己写的工具只适合学原理或内网临时用。密钥管理、随机数质量、侧信道防护……这些点一旦漏掉,加密就形同虚设。










