2010-10-27 184 views
10

有一个字符串被从以下格式发送:我们如何转换从PEM字符串为DER格式

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

我如何构建此字符串从一个公开的对象? 试过下面 删除页眉和页脚和的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) 

关键是被救援人员到场生成的缓冲API的openSSL PEM_write_bio_RSAPublicKey(bio, rsa);

+0

是否使用了链接。但不会做converstion为DER格式 – MSSV 2010-10-27 12:20:25

+0

请注意,您尝试执行的操作并不是真正的“转换为DER”。转换为DER只是解码base64,并将其输出为字节序列。您正在尝试解码ASN.1结构。 – Bruno 2010-11-03 16:34:00

回答

9

通过调用PEM_write_bio_RSAPublicKey只有密钥模数和公共指数被编码到输出PEM数据。然而,X509EncodedKeySpec预计今年ASN.1密钥格式:

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

您应该使用PEM_write_bio_PUBKEY功能编码使用的SubjectPublicKeyInfo结构,如预期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); 
} 
+0

如何或应该在哪里指定SubjectPublicKeyInfo结构? – MSSV 2010-10-27 18:59:44

+0

SubjectPublicKeyInfo结构在RFC 5280(http://tools.ietf.org/html/rfc5280)中指定,公钥结构在RFC 3279(http://tools.ietf.org/html/rfc3279 ) – Jcs 2010-10-27 21:26:02

+0

客户端密钥已收到,因此无法更改格式。可以使用其他方式加载此密钥并获取JCE示例的详细信息。 – MSSV 2010-10-29 04:25:59

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());某处)

0

您可以从您所提供的字符串建立一个公开对象如下:

  1. PEM字符串为二进制DER解码(使用充气城堡的PemReader)
  2. 喂养二进制DER成ASN.1解析器(快活城堡的ASN1InputStream作品)
  3. 获取从解析器解析ASN.1数据(如Bouncy Castle的ASN1Primitive)
  4. 解释该ASN.1数据作为RSA密钥(使用Bouncy Castle的RSAPublicKey)
  5. 构建为JSSE的密钥工厂的规范包括RSA密钥(使用Bouncy Castle的RSAPublicKeySpec的模数和指数)
  6. 使用JSSE的关键工厂制作一个公钥对象ct(你需要的JSSE公钥对象)

我希望更简单一些,但是找不到一个。我也无法在这里找到其他解决方案。

预请求数为我的解决方案:

  1. 的Java 7+(或者你需要手动展开试戴与资源)
  2. 充气城堡bcprov-jdk15on 1。53或更高版本(可以说是与早期的工作,但我没有测试过)

全部工作的Java 7+例如:

import org.bouncycastle.asn1.ASN1InputStream; 
import org.bouncycastle.asn1.ASN1Primitive; 
import org.bouncycastle.asn1.pkcs.RSAPublicKey; 
import org.bouncycastle.util.io.pem.PemObject; 
import org.bouncycastle.util.io.pem.PemReader; 

import java.io.IOException; 
import java.io.StringReader; 
import java.security.KeyFactory; 
import java.security.NoSuchAlgorithmException; 
import java.security.PublicKey; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.RSAPublicKeySpec; 

public interface PemToDer 
{ 
    static void main(String[] args) throws 
      NoSuchAlgorithmException, IOException, InvalidKeySpecException 
    { 
     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, NoSuchAlgorithmException, InvalidKeySpecException 
    { 
     try (StringReader reader = new StringReader(keystr); 
       PemReader pemReader = new PemReader(reader)) 
     { 
      PemObject pem = pemReader.readPemObject(); 
      byte[] der = pem.getContent(); 
      ASN1InputStream in = new ASN1InputStream(der); 
      ASN1Primitive primitive = in.readObject(); 
      RSAPublicKey key = RSAPublicKey.getInstance(primitive); 
      RSAPublicKeySpec spec = new RSAPublicKeySpec(
        key.getModulus(), key.getPublicExponent() 
      ); 
      KeyFactory factory = KeyFactory.getInstance("RSA"); 
      return factory.generatePublic(spec); 
     } 
    } 
}