从 DER 格式的字符串 base64 编码创建 PrivateKey 和 PublicKey

发布于 2024-12-20 15:29:49 字数 1583 浏览 1 评论 0原文

我的私钥和公钥位于 base64 的字符串中,使用 ANS1 DER 进行编码。我尝试创建 java PrivateKeyPublicKey 的实例:

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 行中的私钥执行的操作。因为证书也是加密的。有什么建议吗?

I have my Private and Public keys in a String in base64 which where encoded using ANS1 DER. I tried creating the instance of a java PrivateKey and 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);

I get the following error in 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

I guess I should do something similar with the public key as done with the private key in lines 2 and 3. Because the certificate is also encrypted. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

执笔绘流年 2024-12-27 15:29:49

为了测试您的场景,我使用 openssl 创建了一个 RSA 私钥。

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 的原因。

(顺便说一句,这里是一篇关于< code>openssl 和 Java 加密的使用情况。)

To test your scenario, I've created an RSA private key with openssl.

openssl genrsa -out private.pem 1024

Then I've converted this key to PKCS#8 DER format.

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

The manual of openssl refers to PKCS#8 and DER both as formats, so as far as I'm concerned the following happens:

  • pkcs8 tells openssl that I want to work with private keys in PKCS#8 format.
  • -topk8 tells it that the private key I'm going to specify with -in is not in PKCS#8 (otherwise it'll assume it is).
  • -inform and -in specify that I want to convert the (PEM) private key to PKCS#8 (without -topk8 it'll try to convert a key already in PKCS#8 format to a standard key format).
  • -outform and -out tells it I want a DER formatted key as output.
  • -nocrypt tells it that I don't want to encrypt the key.

Then, with my RSA key (in standard format) I've created a certificate.

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

The certificate contains the public key corresponding to my private key.

After all of these, I've encoded both the private key and the certificate with Base64.

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

The following files were generated.

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

The main problem was that you had a certificate instead of a public key. The certificate contains the public key, but it cannot be loaded with X509EncodedKeySpec(...), this is why the CertificateFactory has to be used instead.

(By the way here is a great article/tutorial on openssl and Java cryptography usage. I've got my info partly from there.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文