RSA私钥解密报错

  • 本文关键字:解密 私钥 RSA java rsa
  • 更新时间 :
  • 英文 :


我在前端使用RSA的代码:

const rsa = new JSEncrypt();
rsa.setPublicKey(k);
const resultText = rsa.encrypt("violet");
console.log(resultText);

我在后端使用RSA的代码:

byte[] inputByte = org.apache.commons.codec.binary.Base64.decodeBase64(str.getBytes("UTF-8"));
byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey);
PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new 
PKCS8EncodedKeySpec(decoded));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE,priKey);
String outStr=new String(cipher.doFinal(inputByte));
return outStr;

PublicKey like this:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA13gYdCmOjR9yqQD7ldzG
ZXabSon6SiLceCK6vRXf4NMbF+EQke0vRpqU3IZ/S1pFdvoQswQabsA4zf0WACVT
iaGIhWDlPu3mecri8rYtmOSfd8GCE0vEgFNvSD6IXRLPeLCB+i7WENBa4fCEtW8W
Hzdas96CLiESbjSAruRasQXP2OLqEA2GU83/069vh8uRKzui+yw0aAXZFyFyFRFa
lxYltFadVpz3+kBplvpzuj82t4fc3yCRbrpeRyTyX1sz0ULSxx/k3/p1OuJtIq9Y
9uN0G4gxhcDFJ4L41uXOln5CPapk7tlsYobhhvxYHw1rrweY+06hrQ7r0Hblv2nH
GQIDAQAB
-----END PUBLIC KEY-----

PrivateKey如下:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA13gYdCmOjR9yqQD7ldzGZXabSon6SiLceCK6vRXf4NMbF+EQ
ke0vRpqU3IZ/S1pFdvoQswQabsA4zf0WACVTiaGIhWDlPu3mecri8rYtmOSfd8GC
E0vEgFNvSD6IXRLPeLCB+i7WENBa4fCEtW8WHzdas96CLiESbjSAruRasQXP2OLq
EA2GU83/069vh8uRKzui+yw0aAXZFyFyFRFalxYltFadVpz3+kBplvpzuj82t4fc
3yCRbrpeRyTyX1sz0ULSxx/k3/p1OuJtIq9Y9uN0G4gxhcDFJ4L41uXOln5CPapk
7tlsYobhhvxYHw1rrweY+06hrQ7r0Hblv2nHGQIDAQABAoIBAAyqFmXde294BblB
QYhRbafRDNeYvIlW+zZkdC1g98OzJMiGhf7NvhWcSFud3CWFrMeNcyXSe+s+iRgy
Y/SmPP6969RLGa5VNVK7RhOV+aAe7/COAyM3NNmGDehlJIaz8FXbqggWcKaUWIMn
K+WuHdK/4ijoTyZ+8yJfG6Er8tisryLQ9io9+op9g/ZWzaUKgu934/cDxUt70bfm
x+ZEPi6YfkJ1uOpXnnadDyw2RUDcvCM3fK3KF5fqM7SJAXY9b1pmLr+Ccn1qkT9G
I+QHidEsGfJciX5AoHnlIMLPMVIPKBbq4GwC/Ngb41LprNJWlPR38N2ySjky/Jyt
159XWHECgYEA9lx2KfFmyLyVjnkIF3JI50mSZAw4YPBBqB27UInacvxXbjfVURht
xK60GB9OkDbFdeNh89x86Gfwvm5bTq4W8YSH4Obd5Fg8XjTuaicTi03CSfF5SdJn
JLLOUmlqP75gkbEPNUoOfqhqq6IbyJVB3egyL90cd2/wCdJOVLEUly8CgYEA3+Y4
lNdl0xedkDNkWsCyyA4iPSUzVxsuch9hW/VGBwzga8rtiNllpKifVvctQOEu/KUe
vVQRF78ojZaMGT33l6TivnUL54z9Lo9uWghoG8TqMfnG34pFPe3R+zvGP87Hrozw
1EUhiMT198SlB/YHrgGGGlJbG+rlm5GIx3lEdDcCgYA4RSw0LlA0v2ZFkX14pYDj
WxmVwnjKI3ZLqObU4XfE1cA+i4AssrC3wNOfwt7V77ywTYxc/9qD1uHVDS3LzdWt
uoCyrOi3tDOtrNdb5asAIXWkIAR9CRLH/hNEHZHIF3rFLDT2DgE7iso6g59m9DiE
L/nulsleunGQPLnpfDzgvwKBgDRV5Q3tl3CTSZJGYQPRnTikDR7LzkdjJCUq7qAH
IhpNyTuJEKL3ZgnqHGzAlERhHpGRqzDIMMKjPUBzW0YfNPuuYA3y4Bh83UV/42SK
KIOtMK0D3JeuA2dparbWDw4lMIm9iiGkEyWcHH6Q6Z6FxN/InWcTrxZEfu0xRI6T
6wtbAoGAfl5dW9LNoaNfQbgIq+PJKZm9f1frza55mFTJgo3ravdb3GmzWVHN8xRf
nLKyKyNLqbkT35IGc39NkALJLxT5RibkAZLiUiwqdMF63sgODbA9AGTmhe+JHS+V
hBmFnCyp6UiN9E4ZAWcZQILa0rRMftMFngAJ3El0ZP+HziRnNzs=
-----END RSA PRIVATE KEY-----

但是-t,当我做java代码解密时,它报告了这样的错误:

java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=111, too big.

如何解决这个问题?

1。你正在解码错误。PEM格式有一个标识数据类型的- begin行、一个编码数据的base64块和一个- end行。BEGIN和END行是格式的一部分,但它们不包含base64编码的数据;只有中间的行包含base64编码的数据。显然,您将整个内容(包括BEGIN和END行)传递给commons.codec。Base64,这会导致在实际数据之前和之后解码一堆垃圾。该垃圾不是有效的ASN.1 DER,所以当Java试图将其解析为DER时,它会失败。

2。加上您的数据不是PKCS8-clear私钥。PEM类型的"RSA PRIVATE KEY"是openssl定义的格式,包含"传统"或"遗留"格式,即私钥的PKCS1表示。这不是PKCS8, PKCS8是Java原生支持的唯一密钥格式;这就是为什么规范类被命名为PKCS8EncodedKeySpec,因为它是一个编码为PKCS8,更具体地说是PKCS8-clear的关键规范。如果通过在base64解码之前删除BEGIN和END行来解决上述问题,Java可以将结果解析为DER,但不能解析为PKCS8-clear密钥;你会得到一个关于"algid解析错误,不是一个序列"的不同异常。要解决这个问题,有5种方法:

  • 更改初始生成密钥对的进程,使其生成PKCS8,而不是openssl遗留的PKCS1。特别是因为您无论如何都需要替换通过发布它而受到损害的密钥对,如207421所述。你不知道这个过程是什么,所以我不能给你任何细节。

  • 将生成的私钥或副本转换为PKCS8-clear。这不是编程或开发和离题,但如果您拥有或获得OpenSSL(在相同或任何可访问和安全的系统上),您可以执行

    openssl pkey -in oldfile -out newfile   # 1.0.0 up only, but older is now rare
    # or
    openssl pkcs8 -topk8 -nocrypt -in oldfile -out newfile   # even ancient versions
    

一旦你有一个PKCS8-clear文件,只需删除BEGIN和END行和base64-decode剩下的东西,并将其传递给KeyFactory作为PKCS8EncodedKeySpec,就像你已经做的那样。

  • 使用https://www.bouncycastle.org。'bcpkix' jar有(Java)代码来读取大量openssl支持的PEM格式,包括您拥有的RSA-PKCS1私钥格式。有很多关于这个的问题;只要搜索PEMParser和JcaPEMKeyConverter。

  • 自己转换。在删除BEGIN和END行之后,解码您拥有的文件主体,以获得PKCS1密钥,然后为该密钥构建PKCS8格式,然后将其作为PKCS8EncodedKeySpec传递给KeyFactory。请参阅Noa Resare和Jean-Alexis Aufauvre关于从PEM BASE64编码的私钥文件或我的Java中获取RSA私钥的答案:将DKIM私钥从RSA转换为DER用于JavaMail。

  • 完全自己做。解码没有BEGIN/END的文件以获得PCKS1,将其解析为DER,例如RFC8447,并构建RSAPrivateCrtKeySpec。我上面链接的Q上的其他一些a就是这样做的。然而,这需要:使用未归档的内部sun。*类,过去可以在Java中工作(因此有了现有的答案),但自2017年以来,"模块化"Java版本(9以上)逐渐变得更加困难或不可能;使用BouncyCastle,它已经记录了对ASN.1的支持(并且很好)——但是使用bcpkix来完成上面的全部工作更容易;或者编写自己的ASN.1解析,这是一项大量的工作。

PS:用RSA加密文本通常是一个糟糕的设计;它不适合那样做。但这不是真正的编程问题,不属于这里。

最新更新