go中rsa加密需严格匹配密钥生成、填充方式、字节流处理三环;密钥必须用crypto/rand.reader生成且长度为1024/2048/3072/4096;明文长度≤pub.size()−11;加解密函数须成对使用;pem解析不可跳过x509步骤。

Go 里用 crypto/rsa 做非对称加密,不是“调个函数就行”,而是必须严格匹配密钥生成、填充方式、字节流处理这三环;任一环节错位,就会遇到 crypto/rsa: message too long、crypto/rsa: decryption error 或静默失败。
rsa.GenerateKey 必须用 crypto/rand.Reader,且密钥长度只能是 1024/2048/3072/4096
私钥安全性完全依赖随机源——math/rand 生成的密钥可预测,哪怕只在测试环境用也会埋雷。必须用 crypto/rand.Reader,不能替换成 rand.New(rand.NewSource(time.Now().UnixNano()))。
密钥长度不是随便填的数字:rsa.GenerateKey(rand.Reader, 2048) 合法,rsa.GenerateKey(rand.Reader, 2000) 会 panic。低于 2048 位已不被现代 TLS 接受;生产建议直接上 3072 或 4096。
- 生成后得到的
*rsa.PrivateKey自带公钥字段(priv.PublicKey),无需额外提取 - 导出私钥时优先用
x509.MarshalPKCS8PrivateKey,它支持 3072+ 密钥;MarshalPKCS1PrivateKey仅兼容老系统且有长度限制 - PEM block type 必须写对:
"RSA PRIVATE KEY"对应 PKCS#1,"PRIVATE KEY"对应 PKCS#8;写错会导致x509.ParsePKCS1PrivateKey返回 nil 而不报错
加密前必须确认明文长度 ≤ rsa.PublicKey.Size() − 11
RSA 不是通用数据管道。用 rsa.EncryptPKCS1v15 加密时,明文最大长度 = pub.Size() − 11 字节(PKCS#1 v1.5 固定填充开销)。2048 位密钥对应 256 − 11 = 245 字节;中文 UTF-8 编码下,一个汉字占 3 字节,实际能加密的汉字数远少于 245。
- 别直接加密 JSON、长 token 或文件内容;真实场景应走混合加密:用 AES 加密原始数据,再用 RSA 加密那个随机 AES 密钥
- 检查长度用
len([]byte(plaintext)),不是len(plaintext)(后者是 rune 数) - 如果硬要测试小字符串,先转
[]byte再校验长度:if len(data) > pub.Size()-11 { panic("message too long") }
加密和解密函数必须成对使用,且参数类型不能错
rsa.EncryptPKCS1v15 和 rsa.DecryptPKCS1v15 是绑定对;若加密用了 EncryptOAEP,解密就必须用 DecryptOAEP,混用必失败。
- 解密时第一个参数必须是
*rsa.PrivateKey,传*rsa.PublicKey或 interface{} 会 panic - 第二个参数是加密输出的密文
[]byte,不是 base64 字符串——除非你加密前手动做了 base64.Encode,否则解密前不要 decode - 第三个参数固定为
crypto/rand.Reader(OAEP 需要,PKCS1v15 实际未使用但签名强制要求) - 即使解密成功,也必须检查返回的
error是否为 nil;某些填充错误会返回空切片而不报错
从 PEM 文件加载密钥时,x509 解析步骤不可跳过
crypto/rsa 不认识 PEM 格式,必须经 x509 解码后再解析。常见错误是跳过 pem.Decode 直接喂给 x509.ParsePKCS1PrivateKey,结果得到 nil 私钥,后续调用立即 panic。
- 读取 PEM 文件后,先用
pem.Decode提取*pem.Block,检查block != nil - 公钥解析用
x509.ParsePKIXPublicKey(对应"PUBLIC KEY"block type),不是ParsePKCS1PublicKey(已废弃) - 私钥解析根据 PEM 头选:
"RSA PRIVATE KEY"→x509.ParsePKCS1PrivateKey;"PRIVATE KEY"→x509.ParsePKCS8PrivateKey - 解析失败时不 panic,只返回 nil + error,必须显式判断
最易被忽略的点:整个流程中所有字节流必须端到端保持原始形态——不额外 UTF-8 decode、不误加 base64、不漏掉 crypto/rand.Reader 的传参位置。RSA 加解密失败,90% 不是算法问题,而是这些“小地方”没对齐。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











