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

时间:2010-10-27 12:10:15

标签: java cryptography jce

以下列格式发送字符串:

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

如何从此字符串构造PublicKey对象? 试过以下 删除页眉和页脚,base64解码缓冲区

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);

  }

作为无效密钥格式失败或将失败

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 PEM_write_bio_RSAPublicKey(bio, rsa);

的API生成的

3 个答案:

答案 0 :(得分:9)

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

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

您应该使用使用SubjectPublicKeyInfo结构对公钥进行编码的PEM_write_bio_PUBKEY函数,该结构符合X509EncodedKeySpec的预期

解码密钥的其他可能解决方案。不幸的是,我不认为只能使用标准JDK API,但可以使用Bouncycastle库来完成

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);
}

答案 1 :(得分:5)

BouncyCastle的PEMReader将为您完成此任务:

String pemKey = "-----BEGIN RSA PUBLIC KEY-----\n"
            + "MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY\n"
            + "mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma\n"
            + "XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED\n"
            + "-----END RSA PUBLIC KEY-----\n";
PEMReader pemReader = new PEMReader(new StringReader(pemKey));
RSAPublicKey rsaPubKey = (RSAPublicKey) pemReader.readObject();
System.out.println("Public key: "+rsaPubKey);

(请注意,您之前可能需要Security.addProvider(new BouncyCastleProvider());。)

答案 2 :(得分:0)

更新:极大地简化了流程和代码,感谢@ dave_thompson_085

您可以从您提供的字符串构造一个PublicKey对象,如下所示:

  1. 从二元DER中读取主题公钥信息(SPKI)(使用Bouncy Castle&#39 PEMParser)
  2. 将SPKI送入转换器以获取PublicKey(Bouncy' s城堡的JcaPEMKeyConverter工作)
  3. 我的解决方案的预先要求:

    1. Java 7+(或者您需要手动展开试用资源)
    2. Bouncy Castle bcprov-jdk15on 1.51或更高版本(不在1.50或更早版本上运行,不在1.47或更早版本上编译)
    3. 完整的Java 7+示例:

      import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
      import org.bouncycastle.openssl.PEMParser;
      import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
      
      import java.io.IOException;
      import java.io.StringReader;
      import java.security.PublicKey;
      
      public interface PemToDer
      {
          static void main(String[] args) throws IOException {
              createRsaPublicKey(
                      "-----BEGIN RSA PUBLIC KEY-----\n" +
                      "MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY\n" +
                      "mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma\n" +
                      "XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED\n" +
                      "-----END RSA PUBLIC KEY-----"
              );
          }
      
          static PublicKey createRsaPublicKey(String keystr) throws IOException {
              try (StringReader reader = new StringReader(keystr);
                   PEMParser pemParser = new PEMParser(reader)) {
                  SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
                  JcaPEMKeyConverter pemKeyConverter = new JcaPEMKeyConverter();
                  return pemKeyConverter.getPublicKey(subjectPublicKeyInfo);
              }
          }
      }