RSA-OAEP加密结果差异:Java与OpenSSL加密后JS解密问题
RSA-OAEP加密兼容性问题:OpenSSL密文无法被JS Crypto Subtle解密
我用Java和OpenSSL对文本字符串执行RSA-OAEP加密时发现:Java生成的密文可以通过JavaScript Crypto Subtle Web API成功解密,但OpenSSL生成的密文无法解密,需要排查问题根源。
1. 密钥信息(JS Crypto Subtle生成,RSA-OAEP 2048位,SHA-256哈希)
公钥(Base64格式)
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8JhmO71HZ1vb8uxKhw6MM+ZvtTmc9Tw6AFpJVgXKiTjebj1SPdnxhdhJ5Bj15RN0rGNACXhAyUdn7zsp66/tmjNuC91L+9PvQBjDbXLsx7XUV9nIGJ3aYO5/qruVNXwyemf7wlwZVDF7oeZ8JUfjABTg7a7xui2WdXDHgvhTQdvQ9TS0NkX9xWAiDSn/HWfoEBC7TLeKeVjHsT7g1JnskGxfVhFrLfxQCxYZle4ebXP7dCPsff4WNNCxzBQtHHt8iEoZ0SVKBzS5zhdLHIdAIW4ELdnYsM7iTlWZO+kfWnlV2i13lAJobhxOAqwsg4OqkTsrx0KtWfZH40bNtFzx8wIDAQAB
私钥(Base64格式)
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDwmGY7vUdnW9vy7EqHDowz5m+1OZz1PDoAWklWBcqJON5uPVI92fGF2EnkGPXlE3SsY0AJeEDJR2fvOynrr+2aM24L3Uv70+9AGMNtcuzHtdRX2cgYndpg7n+qu5U1fDJ6Z/vCXBlUMXuh5nwlR+MAFODtrvG6LZZ1cMeC+FNB29D1NLQ2Rf3FYCINKf8dZ+gQELtMt4p5WMexPuDUmeyQbF9WEWst/FALFhmV7h5tc/t0I+x9/hY00LHMFC0ce3yIShnRJUoHNLnOF0sch0AhbgQt2diwzuJOVZk76R9aeVXaLXeUAmhuHE4CrCyDg6qROyvHQq1Z9kfjRs20XPHzAgMBAAECggEAPtCjPGyeFFu00LclfB5tt20t9CQ/GP3o7MelxvpLF0mMNT74VmKs/rNqE037ARxzxUBCa1aEn6hvd9O8DadIgw5zaFCWMoDyQYtVlqE/NaMA9hDLf7XS2qTaGyLPgX/UFAZLAkMWb9ddfncVKYybtR0+Xn/i56dYVYAk7spTvmkai5Q4Li5eEJqrRNse5fg/wiwDda/cWlEvlvfziAjU51gS/Y9ItUT8Z1g8A2NYfqgFVgBVb0qrtbP76TWPbeLZr1FXTMDB0MO+zuC+1lq48+CYqSJqi9a4GlW2gi0wkaQe3VIOsHipv82kSh20LczXiSKqF58F8m4whWqpa02rrQKBgQD6tbuFiY8fVXi44m1mFO7KDIVXFjuMca0+qXisVaUhG4q42fnlHN0kyuH2IFXNxHD+gE4MnvAUkXDkG1znaz8vM2tfQn6vSpU7OytwOt6UEMWm+112083nGMUy1Me/6rAJbBWfTAl0KXY9/Y/SuEL8u+W6Eas+eASUIe1DooI4xwKBgQD1rAfUXjuRH6WFnbITdG8B3WVZhRCx3YuQVE1UnHR8N6qfx6qKIricvKMSvtWAj0UiIbSA8DENyfMiyAbGpZ0cILxtdXZOtZFW9hfiOeLptnYKTJXOiGoju1prxpUNUKu/1kd7e0clxN75mooge8yFFA6il43wYhhwO2si+FYJdQKBgQDL+1TpX3StX9NrSf8MkXd/uRQ8OQCWUl9MnoJqZPyHpWsG34Ms4IElUFTs9n4Zfv0YdLgMGLzpXzRkw8ahG2c7NjDkPqvoX1xv5sJ++8bg3YyTQe1XoxjiMAsyQmGLSp2T7PbitvDyLFHiOg3surL2AsL00y9rEidXhwsOfohJPQKBgQCqhw4sQHjShIgNlmfMj06amcZG/FGZVPISbiH7cFp++tjp7duX5QAGc/4x/dsPUOOpDIJR2egC7UJiyzvA2aaTprmEtTs46VmIZmwvsQSsO+X1wjFeWlxqjxr1orNFudBt6dxWfzzkn6Iy2i203Jobac+61r5EtKLIDMaSUJTQHQKBgQDaNTfgakpyZBSp/Ydzu76qDKpzGuDqrLBnR/lui4DrSyUoOjNwaGlkU/B6USdaC/BGO7lI08HZU7FzutvXb1mKS+nUI7rKvSTN9NKUJF4MaBv9q40RViKkF9vbq2f1wMs2KUNc0ex2ZL+5BOBICJNHyVulKSxY54Z55L/H4FZmWw==
2. Java加密代码
接收Base64格式公钥,生成PublicKey实例,使用RSA/ECB/OAEPPadding加密文本并输出Base64密文,该密文可被JS Crypto Subtle成功解密:
String stringToEncrypt = "This is encrypted message!!!"; byte[] publicKeyBytes = Base64.getDecoder().decode("MIIBIjANBgkqhki...."); Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey rsaPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes)); cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey, oaepParams); String cipherBytes = Base64.getEncoder().encodeToString(cipher.doFinal(stringToEncrypt.getBytes()));
3. JS Crypto Subtle相关代码
密钥对生成
const keyPair = await window.crypto.subtle.generateKey( { name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" }, true, ["encrypt", "decrypt"] )
私钥导入
return window.crypto.subtle .importKey("pkcs8", base64StringToArrayBuffer(privateKeyInPem), { name: "RSA-OAEP", hash: "SHA-256", }, true, ["decrypt"]).then(key=>{ return key; })
解密代码
const dec = new TextDecoder(); function str2ab(str) { const buf = new ArrayBuffer(str.length); const bufView = new Uint8Array(buf); for (let i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } console.log('cipher: '+cipher) return window.crypto.subtle.decrypt({ name: "RSA-OAEP", }, privateKey, str2ab(window.atob(cipher)) ).then(result=>{ console.log('DECRYPTED MSG:'+dec.decode(result)); })
4. OpenSSL加密命令
使用同一公钥(Base64转DER格式)执行加密,生成的密文无法被上述JS代码解密:
# 加密命令 rsautl -encrypt -pubin -keyform DER -inkey publicKey.der -oaep -in input.txt -out out.bin # 转Base64命令 enc -A -base64 -in out.bin -out base64.txt
问题根源与解决方法
原因分析
OpenSSL的rsautl -oaep选项默认使用SHA-1作为哈希算法和MGF1的哈希算法,但你的Java和JS代码明确指定了SHA-256作为哈希算法,两者参数不匹配导致解密失败。
修正后的OpenSSL命令
需要显式指定OAEP的哈希算法和MGF1的哈希算法为SHA-256:
# 加密命令(指定SHA-256哈希和MGF1-SHA256) rsautl -encrypt -pubin -keyform DER -inkey publicKey.der -oaep -digest sha256 -mgf1 digest:sha256 -in input.txt -out out.bin # 转Base64命令不变 enc -A -base64 -in out.bin -out base64.txt
验证说明
- 确保公钥转换正确:将Base64公钥转为DER格式的命令为
echo "公钥Base64内容" | base64 -d > publicKey.der(注意去除公钥中的换行和空格) - 执行修正后的加密命令后,生成的Base64密文即可被JS Crypto Subtle代码正常解密
内容的提问来源于stack exchange,提问作者Ilja Veselov
相关产品推荐
相关产品推荐

