Create PrivateKey and PublicKey from a String base64 encoding with DER format

跟風遠走 提交于 2019-12-02 23:17:31
Kohányi Róbert

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!