RSA - Java 的 KeyFactory 在 bouncycastle 的 PEM 解析器成功的地方失败
RSA - Java's KeyFactory fails where bouncycastle's PEM parser succeeds
我有一个 PEM 格式的 public 密钥(从 iOS 设备接收):
String pemPubKey = ""+
"-----BEGIN RSA PUBLIC KEY-----\n"+
"MIIBCgKCAQEA07ACQHTTrgX7ddNtyamh58xwD+S+pSrJz/Rah4zj0HIg4V/Ok5vk\n"+
"Wx6y4UyuKLCtefeiB2ipg/n1ZZ0eRac1B4UwPhAtILGQzgIUgOp0cQ3Cb94ugq92\n"+
"wxkxeEdWmIFIlXgWOf6I8yWp9DZaigrRhA2kPbY01zKxCsX1ZxKMVu2sU/HM1hJy\n"+
"aebLLND002yLzuRDLXbacmCt5U6vDQDjBmm3uZ26fEMF+GTCnn6fJBq5RDfRKjpS\n"+
"fVM0mCePO9RHiwu3oHfqoyLA2QGlCexXcIYq7KbJjC9vcamAWRqQdHlsSj5ezDTR\n"+
"GofA6HtQ+zNdGHOvqsYtbN8MJSlUXXy39wIDAQAB\n"+
"-----END RSA PUBLIC KEY-----";
如果我尝试使用 KeyFactory 将其解析为 PublicKey
:
KeyFactory kf = KeyFactory.getInstance("RSA");
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");
String encoded = parse.matcher(pemPubKey).replaceFirst("");
byte[] pem = Base64.getMimeDecoder().decode(encoded);
PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(pem));
我得到:java.security.InvalidKeyException: IOException: algid parse error, not a sequence
.
但是当我这样使用 bouncycastle
时:
SubjectPublicKeyInfo subjectPublicKeyInfo =
(SubjectPublicKeyInfo) new PEMParser(new StringReader(pemPubKey)).readObject();
PublicKey pubKey;
if (PKCSObjectIdentifiers.rsaEncryption == subjectPublicKeyInfo.getAlgorithm().getAlgorithm()) {
DLSequence der = (DLSequence) subjectPublicKeyInfo.parsePublicKey().toASN1Primitive();
ASN1Object modulus, exponent;
modulus = (ASN1Object) der.getObjectAt(0);
exponent = (ASN1Object) der.getObjectAt(1);
RSAPublicKeySpec spec =
new RSAPublicKeySpec(new BigInteger(modulus.toString()), new BigInteger(exponent.toString()));
KeyFactory factory = KeyFactory.getInstance("RSA");
pubKey = factory.generatePublic(spec);
} else {
// Throw some exception
}
我得到一个有效的PublicKey
并且算法被正确识别。
为什么 java 的解析器在这里失败了?我是否正确地从 SubjectPublicKeyInfo
迁移到 PublicKey
?
更新:
我已尝试使用 openssl
:
验证密钥
$ openssl rsa -inform PEM -pubin -in pub.pem -text -noout
unable to load Public Key
140735659656136:error:0906D06C:PEM routines:PEM_read_bio:no start
line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pem/pem_lib.c:704:Expecting:
PUBLIC KEY
从页眉/页脚中删除 RSA
后:
$ openssl rsa -inform PEM -pubin -in pub.pem -text -noout unable to
load Public Key 140735659656136:error:0D0680A8:asn1 encoding
routines:ASN1_CHECK_TLEN:wrong
tag:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:1164:
140735659656136:error:0D07803A:asn1 encoding
routines:ASN1_ITEM_EX_D2I:nested asn1
error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:314:Type=X509_ALGOR
140735659656136:error:0D08303A:asn1 encoding
routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1
error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:653:Field=algor,
Type=X509_PUBKEY 140735659656136:error:0906700D:PEM
routines:PEM_ASN1_read_bio:ASN1
lib:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pem/pem_oth.c:84:
Java 的解析器没有失败,您的 public 密钥是 而不是 Java 编码的 SubjectPublicKeyInfo 结构的实例的 X509EncodedKeySpec
正在期待。我还没有通过 Bouncycastle 例程来了解它为什么成功,但 PEMParser 旨在解析许多不同类型的所谓“PEM”文件。
SubjectPublicKeyInfo 在 RFC 5280 中定义为:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
您的 public 密钥是一个简单的 PKCS#1 RSAPublicKey,在 RFC 8017 中定义为:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
关于“PEM”文件的最后一句话。将某些内容描述为“PEM”格式时需要小心,因为 PEM 并不是真正的特定格式。 “PEM”只不过是在 base64 中编码真实格式,然后将 base64 包装在“-----BEGIN -----”和“-----END -----”行中,其中 希望唯一描述base64编码的数据是什么。
我有一个 PEM 格式的 public 密钥(从 iOS 设备接收):
String pemPubKey = ""+
"-----BEGIN RSA PUBLIC KEY-----\n"+
"MIIBCgKCAQEA07ACQHTTrgX7ddNtyamh58xwD+S+pSrJz/Rah4zj0HIg4V/Ok5vk\n"+
"Wx6y4UyuKLCtefeiB2ipg/n1ZZ0eRac1B4UwPhAtILGQzgIUgOp0cQ3Cb94ugq92\n"+
"wxkxeEdWmIFIlXgWOf6I8yWp9DZaigrRhA2kPbY01zKxCsX1ZxKMVu2sU/HM1hJy\n"+
"aebLLND002yLzuRDLXbacmCt5U6vDQDjBmm3uZ26fEMF+GTCnn6fJBq5RDfRKjpS\n"+
"fVM0mCePO9RHiwu3oHfqoyLA2QGlCexXcIYq7KbJjC9vcamAWRqQdHlsSj5ezDTR\n"+
"GofA6HtQ+zNdGHOvqsYtbN8MJSlUXXy39wIDAQAB\n"+
"-----END RSA PUBLIC KEY-----";
如果我尝试使用 KeyFactory 将其解析为 PublicKey
:
KeyFactory kf = KeyFactory.getInstance("RSA");
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");
String encoded = parse.matcher(pemPubKey).replaceFirst("");
byte[] pem = Base64.getMimeDecoder().decode(encoded);
PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(pem));
我得到:java.security.InvalidKeyException: IOException: algid parse error, not a sequence
.
但是当我这样使用 bouncycastle
时:
SubjectPublicKeyInfo subjectPublicKeyInfo =
(SubjectPublicKeyInfo) new PEMParser(new StringReader(pemPubKey)).readObject();
PublicKey pubKey;
if (PKCSObjectIdentifiers.rsaEncryption == subjectPublicKeyInfo.getAlgorithm().getAlgorithm()) {
DLSequence der = (DLSequence) subjectPublicKeyInfo.parsePublicKey().toASN1Primitive();
ASN1Object modulus, exponent;
modulus = (ASN1Object) der.getObjectAt(0);
exponent = (ASN1Object) der.getObjectAt(1);
RSAPublicKeySpec spec =
new RSAPublicKeySpec(new BigInteger(modulus.toString()), new BigInteger(exponent.toString()));
KeyFactory factory = KeyFactory.getInstance("RSA");
pubKey = factory.generatePublic(spec);
} else {
// Throw some exception
}
我得到一个有效的PublicKey
并且算法被正确识别。
为什么 java 的解析器在这里失败了?我是否正确地从 SubjectPublicKeyInfo
迁移到 PublicKey
?
更新:
我已尝试使用 openssl
:
$ openssl rsa -inform PEM -pubin -in pub.pem -text -noout unable to load Public Key 140735659656136:error:0906D06C:PEM routines:PEM_read_bio:no start line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pem/pem_lib.c:704:Expecting: PUBLIC KEY
从页眉/页脚中删除 RSA
后:
$ openssl rsa -inform PEM -pubin -in pub.pem -text -noout unable to load Public Key 140735659656136:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:1164: 140735659656136:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:314:Type=X509_ALGOR 140735659656136:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:653:Field=algor, Type=X509_PUBKEY 140735659656136:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pem/pem_oth.c:84:
Java 的解析器没有失败,您的 public 密钥是 而不是 Java 编码的 SubjectPublicKeyInfo 结构的实例的 X509EncodedKeySpec
正在期待。我还没有通过 Bouncycastle 例程来了解它为什么成功,但 PEMParser 旨在解析许多不同类型的所谓“PEM”文件。
SubjectPublicKeyInfo 在 RFC 5280 中定义为:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
您的 public 密钥是一个简单的 PKCS#1 RSAPublicKey,在 RFC 8017 中定义为:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
关于“PEM”文件的最后一句话。将某些内容描述为“PEM”格式时需要小心,因为 PEM 并不是真正的特定格式。 “PEM”只不过是在 base64 中编码真实格式,然后将 base64 包装在“-----BEGIN -----”和“-----END -----”行中,其中 希望唯一描述base64编码的数据是什么。