
本文解决 go 中 rsa-oaep 加密后写入文件再读取解密失败的问题,核心在于确保加解密时 label 参数严格一致,并避免二进制密文被文本处理方式破坏。
本文解决 go 中 rsa-oaep 加密后写入文件再读取解密失败的问题,核心在于确保加解密时 label 参数严格一致,并避免二进制密文被文本处理方式破坏。
在使用 crypto/rsa 的 DecryptOAEP 进行密码管理时,一个常见但隐蔽的错误是:加密与解密时传入的 label 参数不一致。这并非文件 I/O 本身的问题(ioutil.WriteFile 和 ioutil.ReadFile 完全适用于二进制数据),而是 OAEP 填充机制的强制要求——label 必须完全相同,否则解密必然失败并返回 crypto/rsa: decryption error。
? OAEP 的 label 必须严格匹配
RSA-OAEP 是一种带标签的确定性填充方案,label 参与掩码生成和完整性校验。Go 标准库明确要求(见 官方文档):
"The label parameter must match the value given when encrypting."
在你的代码中:
- ✅ 加密时(第 167 行):encrypt_oaep(pubKey, plain, []byte(product)) —— 正确传入非空 label;
- ❌ 解密时(第 120 行):decrypt_oaep(privKey, encrypted, label) —— label 未初始化,实际为 nil 或空切片 []byte{},与加密时的 []byte(product) 不等价。
即使内容相同,nil 和 []byte{} 在 Go 中是不同值,且 []byte(product) 与空 label 的哈希结果完全不同,导致 OAEP 验证失败。
✅ 正确解法:统一 label 值
将解密调用改为显式传入相同的 label:
// 加密时(保持不变)
encrypted, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubKey, plaintext, []byte("myapp-password"))
if err != nil {
log.Fatal("encrypt failed:", err)
}
// 写入二进制文件(安全,无编码损失)
err = os.WriteFile("enc.bin", encrypted, 0644)
if err != nil {
log.Fatal("write failed:", err)
}
// 读取(同样二进制安全)
data, err := os.ReadFile("enc.bin")
if err != nil {
log.Fatal("read failed:", err)
}
// 解密时:必须使用完全相同的 label 字节序列
decrypted, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privKey, data, []byte("myapp-password"))
if err != nil {
log.Fatal("decrypt failed:", err) // 此处不再触发 decryption error
}
⚠️ 注意:ioutil 已被弃用,推荐使用 os.WriteFile / os.ReadFile(Go 1.16+),语义更清晰且性能相当。
? 关键注意事项
- 不要对密文做任何文本编码(如 UTF-8 转换、base64 除非显式需要):[]byte 是原始二进制,直接写入/读取即可。
- label 应为有意义的常量字符串(如 "password-v1"),避免动态生成或空值;若需多产品隔离,可用 []byte(fmt.Sprintf("vault-%s", product))。
- 密钥和密文应分开存储:私钥绝不应与加密数据同文件存放,建议使用受控权限的独立文件(如 0600)。
- 务必校验错误:RSA 解密失败通常意味着输入损坏或参数错配,不应静默忽略。
通过确保 label 一致性与二进制 I/O 的正确使用,你的密码保管器即可稳定完成“加密 → 存储 → 读取 → 解密”全流程。











