我有一个带参数的 json 响应:
"jwk":{
"kty": "string",
"n": "string",
"e": "string",
"alg": "string",
"ext": bool
},
"pem": "--BEGIN RSA PUBLIC KEY--...SOMEKEY...--END RSA PUBLIC KEY--",
"alg": {
"name": "string",
"hash": {
"name": "string
}
}
}
我需要使用 RSA 公钥加密数据。 我正在尝试获取“pem”,清除它并创建公钥
String clearKey = rsaKey.replace("--BEGIN RSA PUBLIC KEY--", "").replace("--END RSA PUBLIC KEY--", "").replace("\\s","");
byte[] prByte = Base64.getDecoder().decode(clearKey);
KeyFactory keyFactory = KeyFactory.getInstanse("RSA");
keyFactory.generatePrivate(new PKCS8EEncodedKeySpec(prByte));
但是在这一步我有一个错误
:java.security.InvalidKeyException: IOException: algid parse error not a sequence
这段代码后面也有错误
byte[] prByte = Base64.getDecoder().decode(clearKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(prBytes);
PublicKey publicKey = keyFactory.generatePublic("keySpec"):
我知道 RSA PUBLIC KEY 也许应该映射到 RSAPublicKey 但为此我需要“n”和“e”属性?
RSA 公钥没有以您显示的字符串开头和结尾的 PEM 格式:所有 PEM 格式均以五个连字符、大写“BEGIN”、一个或多个大写单词的标签或类型描述、五个连字符和一个换行符开头;后面是一行或多行 base64,然后是类似的行,其中使用“END”而不是“BEGIN”,并且可选地“END”行之后的换行符可以省略。 请参阅维基百科以及其中引用的RFC 7468。
如果您的“PEM”实际上采用我(以及维基百科和7468)描述的格式,而不是您发布的格式,那么它是OpenSSL(最初是SSLeay)基于简单直接的ASN.1定义的“传统”格式由 PKCS1 定义的格式。这与 X.509 定义并由 Java 用作
X509EncodedKeySpec
的 X.509“SPKI”(SubjectPublicKeyInfo)格式不同。 (它与 Java 用于私钥的 PKCS8 格式更加不同,因为公钥不是私钥。)然而,它是 相关的,因为 SPKI 格式实际上是包含 AlgorithmIdentifier 的 ASN.1 SEQUENCE其中(令人惊讶!)标识了算法以及包含特定于算法的数据的位串,以及对于 RSA,特定于算法的数据is PKCS1
PKCS8EncodedKeySpec
,因此 RSA 密钥的 SPKI 的 DER 编码包含作为 OpenSSL 定义的 RSAPublicKey
文件中找到的 PKCS1 数据的后缀。有两种方法可以直接使用这种“传统”PEM 格式:
BEGIN/END RSA PUBLIC KEY
。
的 bcpkix+bcprov,其 KeyFactory.getInstance("RSA") .generatePublic( new X509EncodedKeySpec( spki ))
类与
PEMParser
结合可以直接处理传统的 RSA 公钥(以及许多其他格式)。
如何在Java中从String加载RSA公钥进行签名验证?
在没有库的情况下用 Java 读取 PKCS#1 或 SPKI 公钥
Java中解析RSA公钥失败
RSA 我应该使用 X.509 还是 PKCS #1
(还有更多链接)
如何在两种风格的公钥格式之间进行转换,一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY”
(背景但不是Java)
将 PKCS1
转换为 PKCS8 的类似问题也经常出现。我在 Java: Convert DKIM private key from RSA to DER for JavaMail 中写了一个相当于方法 1 的答案(即“包装” PKCS1 私钥以提供 PKCS8),另外两个人在 Getting RSA private key from 中也做了类似的事情PEM BASE64 编码的私钥文件 。修改我在 #23709898 中的方法,将 publickey-to-SPKI 而不是 privatekey-to-PKCS8 给出:
JcaPEMKeyConverter
但是由于您还有 JWK 表格,您还有第三种选择:
获取 jwk n 和 e 值(从您使用的任何 JSON 类/表示形式),将每个值转换为(正)BigInteger,将它们放入
// input: b64 contains the base64 _data_ from a BEGIN/END RSA PUBLIC KEY file
// (i.e. with the BEGIN/END lines and linebreaks removed)
byte[] oldder = Base64.getDecoder().decode (b64);
// concatenate the mostly-fixed prefix plus the PKCS#1 data
final byte[] prefix = {0x30,(byte)0x82,0,0, // SEQUENCE(lenTBD)
0x30,0x0d, 6,9,0x2a,(byte)0x86,0x48,(byte)0x86,(byte)0xf7,0x0d,1,1,1, 5,0, // AlgID for rsaEncryption,NULL
3,(byte)0x82,0,0,0 }; // BITSTRING(lenTBD) + unused
byte[] newder = new byte [prefix.length + oldder.length];
System.arraycopy (prefix,0, newder,0, prefix.length);
System.arraycopy (oldder,0, newder,prefix.length, oldder.length);
// and patch the (variable) lengths to be correct
int len = oldder.length+1, loc = prefix.length-3;
newder[loc] = (byte)(len>>8); newder[loc+1] = (byte)len;
len = newder.length-4; loc = 2;
newder[loc] = (byte)(len>>8); newder[loc+1] = (byte)len;
PublicKey pubkey = KeyFactory.getInstance("RSA") .generatePublic( new X509EncodedKeySpec( newder ));
RSAPublicKeySpec
运行:
KeyFactory