我们如何将字符串从 PEM 转换为 DER 格式

2022-01-10 00:00:00 cryptography java jce

以以下格式发送字符串:

Have a String being sent from in the below format:

-----BEGIN RSA PUBLIC KEY-----
MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY
mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma
XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED
-----END RSA PUBLIC KEY-----

如何从这个字符串构造一个 PublicKey 对象?已尝试以下去掉页眉页脚和base64解码缓冲区

How do i construct a PublicKey Object from this string ? Have tried the below Remove the header and footer and base64 decode the buffer

public static PublicKey getFromString(String keystr) throws Exception
  {
  //String S1= asciiToHex(keystr);
   byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(keystr);
   X509EncodedKeySpec spec =
       new X509EncodedKeySpec(keyBytes);
     KeyFactory kf = KeyFactory.getInstance("RSA");
     return kf.generatePublic(spec);

  }

这会失败,要么是无效的密钥格式,要么会出现以下错误

This fails either as an invalid key format or will get below error

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
 at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:188)
 at java.security.KeyFactory.generatePublic(KeyFactory.java:304)
 at PublicKeyReader.getFromString(PublicKeyReader.java:30)
 at Tst.main(Tst.java:36)

正在通过openSSL的API生成密钥PEM_write_bio_RSAPublicKey(bio, rsa);

The Key is being generated thro the API of openSSL PEM_write_bio_RSAPublicKey(bio, rsa);

推荐答案

通过调用 PEM_write_bio_RSAPublicKey,只有密钥模数和公共指数被编码到输出 PEM 数据中.但是 X509EncodedKeySpec 应该是这种 ASN.1 密钥格式:

by calling PEM_write_bio_RSAPublicKey only the key modulus and public exponent are encoded into the output PEM data. However the X509EncodedKeySpec is expected this ASN.1 key format:

 SubjectPublicKeyInfo ::= SEQUENCE {
   algorithm AlgorithmIdentifier,
   subjectPublicKey BIT STRING }

您应该使用 PEM_write_bio_PUBKEY 函数,该函数使用 SubjectPublicKeyInfo 结构对公钥进行编码,正如 X509EncodedKeySpec

You should use the PEM_write_bio_PUBKEY function which encodes the public key using the SubjectPublicKeyInfo structure which as expected by X509EncodedKeySpec

解码密钥的另一种可能的解决方案.不幸的是,我认为不可能只使用标准 JDK API,但可以使用 Bouncycastle图书馆

An other possible solution to decode the key. Unfortunately I don't think it is possible to do only with the standard JDK API but it can be done with the Bouncycastle library

import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;

public static PublicKey getFromString(String keystr) throws Exception
{
  //String S1= asciiToHex(keystr);
   byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(keystr);
   ASN1InputStream in = new ASN1InputStream(keyBytes);
   DERObject obj = in.readObject();
   RSAPublicKeyStructure pStruct = RSAPublicKeyStructure.getInstance(obj);
   RSAPublicKeySpec spec = new RSAPublicKeySpec(pStrcut.getModulus(), pStruct.getPublicExponent());
   KeyFactory kf = KeyFactory.getInstance("RSA");
   return kf.generatePublic(spec);
}

相关文章