Go标准库不提供AES模式一键切换封装,需自行封装Encryptor接口隔离cipher.BlockMode与cipher.AEAD逻辑;CBC要求16字节IV并手动PKCS#7填充,GCM要求12字节唯一nonce且禁止填充,CTR仅提供机密性无完整性校验。

直接用 crypto/aes + crypto/cipher 构建可切换模式的加密器
Go 标准库不提供“一键切换 AES-CBC/AES-GCM/AES-CTR”的高层封装,但你可以自己封装一个 Encryptor 接口,把模式差异收到底层实现里。关键不是写更多代码,而是把 cipher.BlockMode 和 cipher.AEAD 的初始化逻辑隔离清楚。
常见错误是混用 IV 和 nonce:CBC 模式用 cipher.NewCBCEncrypter 要求 IV 长度等于 block.BlockSize()(16 字节),而 GCM 用 cipher.NewGCM 返回的 AEAD 要求 nonce 长度为 gcm.NonceSize()(通常也是 12 字节,非 16)。硬编码 16 字节当 nonce 会导致 GCM panic。
- 每次加密必须调用
rand.Read()生成新 IV/nonce,不能复用 - CBC 模式需手动填充(如 PKCS#7),GCM 不需要且禁止填充
- GCM 的
Seal()输出 =nonce + ciphertext + auth tag,解密时要按长度切分 - CTR 模式不提供完整性校验,仅机密性 —— 若业务需要防篡改,别选它
rsa.EncryptOAEP 是安全底线,别碰 rsa.EncryptPKCS1v15
rsa.EncryptPKCS1v15 在现代系统中已不被推荐,它易受 Bleichenbacher 类型的适应性选择密文攻击。只要你的 Go 版本 ≥ 1.10(2018 年起),就该无条件使用 rsa.EncryptOAEP。
典型坑点:传给 rsa.EncryptOAEP 的哈希函数必须和签名时一致,且不能用 md5.New() 或 sha1.New() —— NIST 已弃用。SHA-256 是当前最小安全要求。
立即学习“go语言免费学习笔记(深入)”;
- label 参数一般传
nil,除非你有跨服务兼容需求 - 明文长度受限:对 2048 位 RSA,OAEP 最大明文约 190 字节;超长数据应先用 AES 加密,再用 RSA 封装 AES 密钥(即混合加密)
- 私钥解密必须用
rsa.DecryptOAEP,配对使用,不可混搭
sha256.Sum256 和 sha256.New() 的行为差异影响性能
sha256.Sum256() 返回的是值类型([32]byte),适合一次性小数据哈希;sha256.New() 返回指针类型(*hash.Hash),支持流式写入、复用、重置。二者底层共享同一实现,但误用会带来隐性开销。
比如你循环处理 1000 个文件做校验,若每次都调 sha256.Sum256(data),就会重复分配哈希上下文;而用一个复用的 sha256.New() 实例,调 h.Reset() + h.Write(),能减少 GC 压力。
-
Sum256适合单次、短数据(如 token 签名前缀)、无需复用场景 -
Sum(nil)返回的是追加结果,不是拷贝 —— 若后续还要用原 hash 对象,必须传空切片或显式拷贝 - HMAC 场景必须用
hmac.New(),不能用Sum256模拟,否则不安全
密钥不能硬编码,PBKDF2 生成密钥要设够迭代次数
用户密码 ≠ 加密密钥。直接拿字符串当 AES 密钥(如 []byte("my_pass_123"))是严重漏洞。必须用密钥派生函数(KDF)扩展熵,Go 标准库只提供 pbkdf2.Key()。
默认迭代次数 1000 是历史遗留值,2026 年已不够用。NIST SP 800-63B 推荐至少 600,000 次(对 SHA-256),实际项目建议 ≥ 1e6。低于此值,暴力破解成本过低。
- salt 必须随机且唯一,每次派生都应生成新 salt,并和密文一起存储(如前置 16 字节)
- 派生出的密钥长度要匹配算法要求:AES-256 需 32 字节,别截断或补零
- 不要自己实现 KDF,也不要试图用多次哈希代替 PBKDF2 —— 顺序哈希无法抵抗 GPU/FPGA 加速
最易被忽略的一点:GCM 模式下,nonce 复用一次就等于泄露全部密钥材料。它比密钥本身还脆弱 —— 生成、传输、存储、复用控制,每个环节都得当真。


















