当前位置: 首页 > 面试题库 >

从具有DER格式的String base64编码中创建PrivateKey和PublicKey

邬友樵
2023-03-14
问题内容

我的私钥和公钥在base64中的字符串中,该字符串使用ANS1 DER进行编码。我尝试创建Java PrivateKey和的实例PublicKey

byte [] llave2 = DatatypeConverter.parseBase64Binary(key);
PKCS8Key pkcs8 = new PKCS8Key( llave2, password.toCharArray()); //line 2
llave2 = pkcs8.getDecryptedBytes();                             //line 3
certificado = DatatypeConverter.parseBase64Binary(cer);

KeyFactory kf = KeyFactory.getInstance("RSA");  
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(llave2);
PrivateKey privateKey = kf.generatePrivate(ks);
X509EncodedKeySpec x = new X509EncodedKeySpec(certificado);
PublicKey publicKey = kf.generatePublic(x);

我在中收到以下错误PublicKey publicKey = kf.generatePublic(x)

    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException:     IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(Unknown Source)
    at java.security.KeyFactory.generatePublic(Unknown Source)
    at vital.cancelaciones.GeneraXMLCancelacion.main(GeneraXMLCancelacion.java:118)
Caused by: java.security.InvalidKeyException: IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
    at sun.security.x509.X509Key.decode(Unknown Source)
    at sun.security.x509.X509Key.decode(Unknown Source)
    at sun.security.rsa.RSAPublicKeyImpl.<init>(Unknown Source)
    at sun.security.rsa.RSAKeyFactory.generatePublic(Unknown Source)
    ... 3 more

我猜我应该对公共密钥做类似的事情,就像在第2行和第3行中对私有密钥做一样。因为证书也是加密的。有什么建议?


问题答案:

为了测试您的方案,我创建了一个RSA私钥openssl

openssl genrsa -out private.pem 1024

然后,我已将此密钥转换为PKCS#8 DER格式。

openssl pkcs8 -topk8 -inform PEM -in private.pem -outform DER -out private.der -nocrypt

的手册openssl将PKCS#8和DER都称为 格式 ,因此据我所知,会发生以下情况:

  • pkcs8告诉openssl我要使用PKCS#8格式的私钥。
  • -topk8告诉它我会指定用私钥-in不是 在PKCS#8(否则它会假设它是)。
  • -inform-in指定我要将(PEM)私钥转换为PKCS#8(如果没有,-topk8它将尝试将PKCS#8格式的密钥转换为 标准 密钥格式)。
  • -outform-out告诉我我要使用DER格式的键作为输出。
  • -nocrypt 告诉我我不想加密密钥。

然后,使用我的RSA密钥(标准格式)创建了一个证书。

openssl req -new -x509 -keyform PEM -key private.pem -outform DER -out public.der

证书包含与我的私钥相对应的公钥。

在完成所有这些操作之后,我已经使用Base64对私钥和证书进行了编码。

base64 private.der > private.der.b64
base64 public.der > public.der.b64

生成了以下文件。

private.pem      # standard
private.der      # pkcs8/DER
private.der.b64 
public.der       # x509/DER
public.der.b64



public static void main(String[] args) throws IOException, GeneralSecurityException {
  // get a handle on the base64 encoded key and certificate
  File privateKeyFile = new File("private.der.b64");
  File publicKeyFile = new File("public.der.b64");

  // pull them into arrays
  byte[] privateKeyBytes = toByteArray(privateKeyFile);
  byte[] publicKeyBytes = toByteArray(publicKeyFile);

  // decode them
  privateKeyBytes = toDecodedBase64ByteArray(privateKeyBytes);
  publicKeyBytes = toDecodedBase64ByteArray(publicKeyBytes);

  // get the private key
  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  KeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
  PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

  // get the public key
  CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
  Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(publicKeyBytes));
  PublicKey publicKey = certificate.getPublicKey();
}

private static byte[] toByteArray(File file) throws IOException {
  // java 7's try-with-resources statement
  try (FileInputStream in = new FileInputStream(file);
      FileChannel channel = in.getChannel()) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    channel.transferTo(0, channel.size(), Channels.newChannel(out));
    return out.toByteArray();
  }
}

private static byte[] toDecodedBase64ByteArray(byte[] base64EncodedByteArray) {
  return DatatypeConverter.parseBase64Binary(
      new String(base64EncodedByteArray, Charset.forName("UTF-8")));
}

主要问题是您拥有证书而不是公共密钥。证书包含公钥,但是不能加载X509EncodedKeySpec(...),这就是为什么CertificateFactory必须使用的原因。

(顺便说一下,这里有一篇很棒的文章/教程openssl以及Java密码学的用法。我的信息部分来自那里。)



 类似资料:
  • 我试图用Java创建一个ECDSA签名。当我在python中创建一个时,它可以在Java中得到很好的验证。但是反之亦然,我得到了一个BadSignatureException,Python使用ECDSA库,Java使用SpongyCastle。 签名的Python实现:

  • 问题内容: 我需要创建一个可以将int,long,double等类型转换为字符串的格式的字符串。使用Obj-C,我可以通过以下方式进行操作。 怎么做迅速? 问题答案: 我认为这可以帮助您: 结果示例:

  • 本文向大家介绍servlets 编码风格和建议,包括了servlets 编码风格和建议的使用技巧和注意事项,需要的朋友参考一下 示例 内容已移回到良好的'ol Servlets Wiki页面

  • 问题内容: 我有以下疑问与如何在Java中创建格式日期有关。 在Java应用程序中,我必须创建一个采用以下格式的日期(该值必须是当前日期): 2015-05-26 ( yyyy-mm-dd ) 所以我知道我可以通过以下方式简单地构建一个新对象来获取当前日期: 但是如何指定日期格式? 特纳克斯 问题答案: 尝试这样: 要以yyyy-MM-dd格式格式化当前日期,您可以尝试像这样 请参考SimpleD

  • 输出字符串: 02/04/2014 现在我需要以相同的方式格式化日期(“02/04/2014”)。

  • 问题内容: 考虑以下代码: 我的结果是预期的(2134,3423,4234,343)。 我确实将最后一个逗号替换为)以得到预期的结果。总的来说,有更好的方法吗? 问题答案: 您可以使用Commons Lang : 或者,如果您不能使用外部库: