aes-cbc 文件加密需随机生成并保存 iv 和 salt,用 pbkdf2 衍生密钥,流式分块加解密并 pkcs#7 填充,校验和确保完整性,三者偏移须协议固化。

用 crypto/aes 实现 AES-CBC 文件加密时必须手动处理 IV
Go 标准库不自动管理初始化向量(IV),直接复用相同 IV 会导致密文可预测,严重削弱安全性。加密前必须生成随机 IV,并和密文一起保存(通常前置 16 字节)。
- 使用
cipher.NewCBCEncrypter前,调用crypto/rand.Read(iv)生成 16 字节 IV - 写入文件时,先写 IV(
file.Write(iv)),再写密文 - 解密时先读 16 字节作为 IV,再用它初始化
cipher.NewCBCDecrypter - 切勿硬编码 IV(如全零)或从密钥派生——这等于放弃 CBC 模式的核心安全前提
密钥不能直接用字符串,得用 crypto/sha256 或 golang.org/x/crypto/pbkdf2 衍生
用户输入的口令(password)长度不定、熵低,不能直接当 AES-256 密钥用。必须通过密钥派生函数(KDF)扩展为固定长度高熵密钥。
- 简单场景可用
sha256.Sum256([]byte(password)).Sum(nil)截取 32 字节,但抗暴力弱 - 生产环境务必用 PBKDF2:传入 salt(随机生成,存于文件头)、迭代次数 ≥ 100000、摘要用
sha256.New - 注意:salt 必须每次加密都重生成,且和 IV 一样写入输出文件头部(建议前 32 字节 salt + 16 字节 IV)
大文件别一次性读进内存,用 io.Pipe 配合分块加解密
对几百 MB 以上的文件调用 os.ReadFile 容易 OOM。应使用流式处理,边读边加/解密,保持常量内存占用。
- 用
bufio.NewReader按 64KB 或 128KB 分块读取明文 - 每块调用
block.Encrypt(注意:AES 块大小是 16 字节,输入必须是 16 的倍数,末尾需 PKCS#7 填充) - 推荐封装成
io.Reader和io.Writer:加密时包装原始文件 reader;解密时包装目标 writer - 避免自己实现填充逻辑——用
golang.org/x/crypto/pkcs7包的PAD/UNPAD
解密失败时常见错误是忽略 io.ErrUnexpectedEOF 和填充验证异常
密文损坏、IV 错位、密钥不匹配都会导致解密后明文无法正确去填充,但 Go 的 pkcs7.Unpad 默认 panic,容易掩盖真实原因。
立即学习“go语言免费学习笔记(深入)”;
- 必须用
pkcs7.IsPaddingValid先检查,再调用pkcs7.Unpad - 如果校验失败,优先排查:是否读少了 IV?salt 是否错位?密钥是否用了不同 KDF 参数?
- 不要依赖“解密没报错就等于成功”——错误的密钥也可能产出看似合法的字节流,只是内容乱码
- 可在加密后追加明文 SHA256 校验和(加密前计算,加密后附在密文末尾),解密后比对,提前发现完整性问题










