aes-gcm是文件加密默认选择,因其天然支持aead认证,一次调用完成加密与完整性校验,避免cbc需手动组合hmac的易错风险;标准库cipher.newgcm稳定免维护,但要求密钥严格32字节、nonce唯一12字节且不可复用。

直接用 cipher.NewGCM 加密文件再走 HTTPS 传输,是当前最稳妥的组合;别碰 CBC + 手动 HMAC,也别在 HTTP 层自己加解密。
为什么 AES-GCM 是文件加密的默认选择
GCM 模式天然带认证(AEAD),一次调用就完成加密+完整性校验,不用像 CBC 那样额外算 HMAC、再拼接、再分别验证。标准库 cipher.NewGCM 稳定、无依赖、免维护。
-
cipher.NewGCM要求密钥长度严格为 32 字节(AES-256),不能传 16 字节或硬编码字符串 - nonce 必须每次唯一,推荐 12 字节(
gcm.NonceSize()返回值),用crypto/rand.Read生成,不能复用 - 加密输出是
nonce || ciphertext || tag三段拼接,总长 = 12 + len(明文) + 16;解密时先切出前 12 字节作 nonce,其余喂给Open() - 如果用 16 字节 IV 去配 GCM,会 panic:不匹配
NonceSize(),不是“能跑就行”的问题
加密文件时必须处理的三个头部字段
密文不能光存数据,得把 salt、nonce、密文结构固化进文件头,否则解密端根本不知道怎么拆。常见错误是只写 IV、漏 salt,或把 salt 和 nonce 长度写死但没对齐。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 推荐结构:
[salt(16B)][nonce(12B)][ciphertext+tag]—— salt 用于密钥派生,nonce 用于本次加密,两者都需随机且唯一 - 生成 salt 用
crypto/rand.Read(salt),不要用时间戳或 PID;每次加密都重生成,不能缓存复用 - 写入顺序必须严格:先写 salt,再写 nonce,最后写密文;读取时按偏移硬切,比如
buf[0:16]取 salt,buf[16:28]取 nonce - 别用
os.Create()直接覆盖原文件;应写临时文件(如dst + ".tmp"),成功后再os.Rename()
大文件不能用 io.Copy 直接套 cipher.Stream
有人看到 cipher.Stream(如 CFB)支持流式接口,就写 io.Copy(dst, cipher.StreamWriter{...}),结果小文件看似正常,大文件解密失败或末尾乱码——因为 io.Copy 不保证块对齐,而 AES 分组密码要求输入长度是块大小整数倍(GCM 内部仍按块处理)。
- 正确做法:用固定缓冲区(如 64KB)分块读取,每块单独调用
gcm.Seal()加密,再写入;避免一次性os.ReadFile吃光内存 - 缓冲区大小建议设为 64 * 1024 或 128 * 1024,避开 16 的倍数陷阱(如 65535);GCM 对块长无强制要求,但太小影响性能
- 最后一块可能不足缓冲区大小,
gcm.Seal()仍可安全处理,无需手动填充 - 别用
bufio.Reader包裹文件句柄再喂给加密流——它内部缓存会破坏 nonce 与明文的严格对应关系
解密失败时 cipher.NewGCM.Open() 不报错,只返回 nil
这是最容易被忽略的坑:Open() 在认证失败(密钥错、nonce 错、密文被篡改)时不会 panic,也不会返回 error,而是静默返回 nil。如果你只检查 err != nil 就认为成功,实际拿到的是空切片或乱码。
- 必须同时判断
plaintext == nil和err != nil;典型写法:if plaintext == nil || err != nil { return err } - 解密后建议快速校验 SHA-256(如果发送方提供了摘要),但摘要本身要和密文一起传输,不能明文放在 HTTP header 里
- HTTP 上传场景下,别把密钥或 nonce 放 query string 或 form field;应作为 multipart 的独立 part,或 POST body 的二进制前缀
- 如果传输链路已用 HTTPS,应用层加密的目标只是防内部泄露,不是替代 TLS;二者叠加时,密钥管理复杂度翻倍,优先考虑 KMS 或环境变量注入
真正难的不是调通 NewGCM,而是确保 salt、nonce、密钥三者生命周期隔离,且每次加密都重新生成——少一个随机,就等于把锁换成贴纸。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










