Golang RSA-OAEP加密后Java解密报BadPaddingException问题排查
我之前也踩过Golang RSA-OAEP加密、Java解密出现BadPaddingException: Decryption error的坑,几乎都是两端加密参数不匹配导致的——RSA-OAEP对哈希算法、掩码函数这些细节要求特别严格,差一点都不行。结合你给出的Go代码片段,咱们一步步排查:
1. 哈希算法不匹配(最常见原因)
Go标准库的rsa.EncryptOAEP如果不指定哈希函数,默认用的是SHA-1,但很多Java代码会默认用SHA-256或者其他算法,这直接会导致padding校验失败。
对应检查点:
- 看你的Go代码里
EncryptOAEP的第一个参数:- 如果是
rsa.EncryptOAEP(sha1.New(), ...),那Java端必须同步用SHA-1作为哈希算法 - 如果是
sha256.New(),Java端也要改成SHA-256
- 如果是
示例Java代码(匹配SHA-1的情况):
import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSource; import java.security.PrivateKey; import java.security.spec.MGF1ParameterSpec; // 初始化Cipher时必须明确指定OAEP的参数 Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); OAEPParameterSpec spec = new OAEPParameterSpec( "SHA-1", "MGF1", new MGF1ParameterSpec("SHA-1"), // MGF1的哈希算法要和主哈希一致 PSource.PSpecified.DEFAULT ); cipher.init(Cipher.DECRYPT_MODE, yourPrivateKey, spec); byte[] decrypted = cipher.doFinal(encryptedBytes);
2. MGF1掩码函数的参数不一致
RSA-OAEP依赖MGF1(掩码生成函数),它的哈希算法必须和主加密哈希算法完全一致。Go里EncryptOAEP会自动用和第一个参数相同的哈希作为MGF1的哈希,但Java如果不显式指定,可能会用不同的算法(比如有些环境默认MGF1用SHA-1,即使主哈希是SHA-256)。
解决方法:
不管用哪种哈希,Java端都要显式指定MGF1的哈希算法,和Go端保持一致。比如Go用SHA-256时:
// Go代码示例 hash := sha256.New() ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, rsaPublicKey, []byte(yourPlaintext), nil)
对应的Java代码:
OAEPParameterSpec spec = new OAEPParameterSpec( "SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT );
3. 明文长度超出限制
RSA-OAEP对明文长度有严格限制:
最大明文长度 = 密钥长度(字节) - 2*哈希长度(字节) - 2
比如2048位RSA密钥(256字节),用SHA-1(20字节)的话,最大明文长度是256 - 2*20 -2 = 214字节。如果Go加密的明文超过这个长度,要么加密时出错,要么被截断,导致Java解密时padding校验失败。
解决方法:
- 检查你要加密的字符串长度,超过限制的话,不要直接用RSA加密大文本,改用对称加密+RSA加密对称密钥的方案(比如AES加密文本,然后用RSA加密AES密钥)。
4. 公钥解析是否正确
你的Go代码里用x509.ParseCertificate解析证书获取公钥,但忽略了解析错误。要确保:
- 证书里的公钥确实是RSA类型(不是EC或其他)
- 解析过程没有报错(把
cert, _ = x509.ParseCertificate(block.Bytes)改成带错误检查的代码,比如:
cert, err := x509.ParseCertificate(block.Bytes) if err != nil { log.Fatalf("Failed to parse certificate: %v", err) } rsaPublicKey, ok := cert.PublicKey.(*rsa.PublicKey) if !ok { log.Fatal("Public key is not RSA") }
5. OAEP的Label参数是否一致
Go的EncryptOAEP最后一个参数是label(可选),如果你的代码里传了非nil的值,Java端解密时必须用完全相同的label。你的代码里是nil,对应Java端用PSource.PSpecified.DEFAULT(空label)就没问题,这点要确认。
内容的提问来源于stack exchange,提问作者Quick Learner

