rsa在go中不能加密任意长度数据,因2048位密钥pkcs#1 v1.5填充下明文上限为245字节;超长需分段加密或改用rsa+aes混合模式,且加解密必须严格匹配填充、密钥格式与字节长度。

RSA 加解密在 Go 中必须手动处理填充(padding),直接对原始字节调用 DecryptPKCS1v15 或 EncryptPKCS1v15 会 panic 或返回错误——这不是库的问题,是 RSA 本身不允许裸密钥运算。
为什么不能直接加密任意长度数据
RSA 是块密码,密钥长度决定单次可加密的明文上限。比如 2048 位密钥(256 字节),使用 PKCS#1 v1.5 填充时,最多只能加密 256 - 11 = 245 字节。超过就会触发 cipher: message too long for RSA public key size 错误。
- 实际可用长度 =
KeySizeInBytes - 11(PKCS#1 v1.5)或KeySizeInBytes - 42(OAEP) - 大文件/长文本必须分块或改用混合加密(RSA 封装 AES 密钥)
- Go 的
crypto/rsa不提供自动分块,得自己切片 + 填充校验
如何生成和保存 PEM 格式的密钥对
Go 默认生成的是 DER 编码的私钥(*rsa.PrivateKey),要写入文件供其他语言或工具使用,必须手动编码为 PEM。
- 私钥用
pkcs8.MarshalPrivateKey(推荐)或x509.MarshalPKCS1PrivateKey(仅传统格式) - 公钥用
x509.MarshalPKIXPublicKey(标准)或x509.MarshalPKCS1PublicKey(旧式) - PEM block type 必须匹配:私钥是
"PRIVATE KEY"或"RSA PRIVATE KEY",公钥是"PUBLIC KEY"或"RSA PUBLIC KEY"
示例关键步骤:
privBytes, _ := x509.MarshalPKCS1PrivateKey(priv)
pemBlock := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}
pem.Encode(file, pemBlock)
加解密必须显式指定填充方式
Go 不允许“无填充”操作,所有 Encrypt* 和 Decrypt* 方法都要求传入 rand.Reader 和明确的填充标识。最常用的是 rsa.EncryptPKCS1v15 和 rsa.DecryptPKCS1v15。
- 加密失败常见原因是明文超长,或
rand.Reader为nil(会 panic) - 解密失败常见于:密文被篡改、私钥不匹配、填充损坏,此时返回
crypto/rsa: decryption error - 不要用
DecryptPKCS1v15解密别人用 OAEP 加密的数据——算法不兼容
一个最小可运行加密片段:
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, &pubKey, []byte("hello"))
if err != nil {
log.Fatal(err) // 可能是 message too long 或 rand failure
}
plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, ciphertext)
生产环境务必避免直接 RSA 加密业务数据
真实系统中几乎从不直接用 RSA 加密用户输入。原因很实在:性能差、长度受限、无认证、易受选择密文攻击(如 Bleichenbacher 攻击)。
- 标准做法是:用 AES-GCM 加密数据,再用 RSA 加密 AES 的随机密钥(即 “RSA-KEM + AES-KEK” 模式)
- 如果必须用纯 RSA,请强制使用 OAEP(
rsa.EncryptOAEP),它带哈希和随机盐,比 PKCS#1 v1.5 更健壮 - 私钥解密操作必须在可信环境执行,且应限制频率防暴力穷举
最容易被忽略的一点:rsa.Decrypt* 函数在填充验证失败时**不会透露具体哪部分出错**(这是侧信道防护),但如果你自己实现错误分支逻辑并返回不同错误信息,反而可能引入时序攻击面。











