Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating RSA keys in PKCS#1 format in Java

When I generate an RSA key pair using the Java API, the public key is encoded in the X.509 format and the private key is encoded in the PKCS#8 format. I'm looking to encode both as PKCS#1. Is this possible? I've spent a considerable amount of time going through the Java docs but haven't found a solution. The result is the same when I use the Java and the Bouncy Castle providers.

Here is a snippet of the code:

KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA","BC"); keygen.initialize(1024); KeyPair pair = keygen.generateKeyPair(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic(); byte[] privBytes = priv.getEncoded(); byte[] pubBytes = pub.getEncoded(); 

The two resulting byte arrays are formatted as X.509 (public) and PKCS#8 (private).

Any help would be much appreciated. There are some similar posts but none really answer my question.

Thank You

like image 749
Anthony Avatar asked Sep 30 '11 13:09

Anthony


People also ask

How are RSA keys generated?

An RSA user creates and publishes a public key based on two large prime numbers, along with an auxiliary value. The prime numbers are kept secret. Messages can be encrypted by anyone, via the public key, but can only be decoded by someone who knows the prime numbers.


1 Answers

You will need BouncyCastle:

import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemWriter; 

The code snippets below have been checked and found working with Bouncy Castle 1.52.

Private key

Convert private key from PKCS8 to PKCS1:

PrivateKey priv = pair.getPrivate(); byte[] privBytes = priv.getEncoded();  PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes); ASN1Encodable encodable = pkInfo.parsePrivateKey(); ASN1Primitive primitive = encodable.toASN1Primitive(); byte[] privateKeyPKCS1 = primitive.getEncoded(); 

Convert private key in PKCS1 to PEM:

PemObject pemObject = new PemObject("RSA PRIVATE KEY", privateKeyPKCS1); StringWriter stringWriter = new StringWriter(); PemWriter pemWriter = new PemWriter(stringWriter); pemWriter.writeObject(pemObject); pemWriter.close(); String pemString = stringWriter.toString(); 

Check with command line OpenSSL that the key format is as expected:

openssl rsa -in rsa_private_key.pem -noout -text 

Public key

Convert public key from X.509 SubjectPublicKeyInfo to PKCS1:

PublicKey pub = pair.getPublic(); byte[] pubBytes = pub.getEncoded();  SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes); ASN1Primitive primitive = spkInfo.parsePublicKey(); byte[] publicKeyPKCS1 = primitive.getEncoded(); 

Convert public key in PKCS1 to PEM:

PemObject pemObject = new PemObject("RSA PUBLIC KEY", publicKeyPKCS1); StringWriter stringWriter = new StringWriter(); PemWriter pemWriter = new PemWriter(stringWriter); pemWriter.writeObject(pemObject); pemWriter.close(); String pemString = stringWriter.toString(); 

Check with command line OpenSSL that the key format is as expected:

openssl rsa -in rsa_public_key.pem -RSAPublicKey_in -noout -text 

Thanks

Many thanks to the authors of the following posts:

  • https://stackoverflow.com/a/8713518/1016580
  • https://stackoverflow.com/a/14052651/1016580
  • https://stackoverflow.com/a/14068057/1016580

Those posts contained useful, but incomplete and sometimes outdated info (i.e. for older versions of BouncyCastle), that helped me to construct this post.

like image 129
Alexei Khlebnikov Avatar answered Sep 28 '22 07:09

Alexei Khlebnikov