从字符串创建 RSA 公钥
我使用 1024 RSA 生成了这个测试公钥,然后在另一个编码平台中将其编码为 DER 和 Base64.我将密钥复制到 Android/Eclipse 中的字符串中,并尝试使用 KeyFactory 将其转换为公钥.无论我尝试什么,它都会一直给我一个 InvalidKeySpecException .任何建议都将不胜感激.
I've generated this test public key using 1024 RSA and then encoded it to DER and Base64 in another coding platform. I copied the key into a string in Android/Eclipse and I am trying to turn it into a public key using KeyFactory. It just keeps giving me an InvalidKeySpecException no matter what I try. Any advice at all would be appreciated.
private void prepKeys() {
String AppKeyPub = "MIGHAoGBAOX+TFdFVIKYyCVxWlnbGYbmgkkmHmEv2qStZzAFt6NVqKPLK989Ow0RcqcDTZaZBfO5" +
"5JSVHNIKoqULELruACfqtGoATfgwBp4Owfww8M891gKNSlI/M0yzDQHns5CKwPE01jD6qGZ8/2IZ" +
"OjLJNH6qC9At8iMCbPe9GeXIPFWRAgER";
// create the key factory
try {
KeyFactory kFactory = KeyFactory.getInstance("RSA");
// decode base64 of your key
byte yourKey[] = Base64.decode(AppKeyPub,0);
// generate the public key
X509EncodedKeySpec spec = new X509EncodedKeySpec(yourKey);
PublicKey publicKey = (PublicKey) kFactory.generatePublic(spec);
System.out.println("Public Key: " + publicKey);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
推荐答案
您拥有的密钥是 PKCS#1 格式,而不是 Java 接受的 SubjectPublicKeyInfo 结构.PKCS#1 只是 RSA 参数的编码,缺少诸如算法标识符之类的东西.SubjectPublicKeyInfo 在内部使用 PKCS#1 - 无论如何都用于 RSA 公钥.
The key you have is in PKCS#1 format instead of SubjectPublicKeyInfo structure that Java accepts. PKCS#1 is the encoding of the RSA parameters only and lacks things such as an algorithm identifier. SubjectPublicKeyInfo uses PKCS#1 internally - for RSA public keys anyway.
由于 PKCS#1 公钥位于 SubjectPublicKeyInfo 结构的末尾,因此可以简单地为字节添加前缀,以便它们成为 RSA SubjectPublicKeyInfo.该解决方案更易于执行,无需额外的库,例如 Bouncy Castle.因此,如果您需要不使用外部库,那么您可以查看我的答案此处.
As the PKCS#1 public key is at the end of the SubjectPublicKeyInfo structure it is possible to simply prefix the bytes so that they become an RSA SubjectPublicKeyInfo. That solution is easier to perform without additional libraries such as Bouncy Castle. So if you need to go without an external library then you may have a look at my answer here.
或者,可以编写一个简单的 BER 解码器,将结构解码为两个 BigInteger 值.结构本身并不复杂但BER/DER长度编码需要一些时间来适应.
Alternatively a simple BER decoder could be written to decode the structure into the two BigInteger values. The structure itself is not that complicated but the BER/DER length encoding takes some getting used to.
不过,您也可以使用 Bouncy Castle(轻量级 API)来解决您的问题:
However, you can also use Bouncy Castle (lightweight API) to solve your issues:
String publicKeyB64 = "MIGHAoGBAOX+TFdFVIKYyCVxWlnbGYbmgkkmHmEv2qStZzAFt6NVqKPLK989Ow0RcqcDTZaZBfO5"
+ "5JSVHNIKoqULELruACfqtGoATfgwBp4Owfww8M891gKNSlI/M0yzDQHns5CKwPE01jD6qGZ8/2IZ"
+ "OjLJNH6qC9At8iMCbPe9GeXIPFWRAgER";
// ok, you may need to use the Base64 decoder of bouncy or Android instead
byte[] decoded = Base64.getDecoder().decode(publicKeyB64);
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(decoded);
BigInteger modulus = pkcs1PublicKey.getModulus();
BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey generatedPublic = kf.generatePublic(keySpec);
System.out.printf("Modulus: %X%n", modulus);
System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent); // 17? OK.
System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", generatedPublic.getClass().getName(), generatedPublic instanceof RSAPublicKey);
正如您所见,它实际上只需要一个类作为接口,尽管这当然得到了 Bouncy Castle 中整个 ASN.1/BER 解码器功能的支持.
As you can see it actually only requires a single class as interface, although that is of course backed up with the entire ASN.1/BER decoder functionality within Bouncy Castle.
请注意,可能需要将 Base 64 解码器更改为 Android 特定的一个(android.util.Base64
).此代码已在等效的 Java 运行时测试.
Note that it may be required to change the Base 64 decoder to the Android specific one (android.util.Base64
). This code was tested on an equivalent Java runtime.
相关文章