1

I am using the following code to create a public and a private key for security purposes.

public KeyGenerator(int keylength) throws NoSuchAlgorithmException, NoSuchProviderException {
    this.keyGen = KeyPairGenerator.getInstance("RSA");
    this.keyGen.initialize(keylength);
}

public void createKeys() {
    this.pair = this.keyGen.generateKeyPair();
    this.privateKey = pair.getPrivate();
    this.publicKey = pair.getPublic();
}

public PrivateKey getPrivateKey() {
    return this.privateKey;
}

public PublicKey getPublicKey() {
    return this.publicKey;
}

public void writeToFile(String path, byte[] key) throws IOException {
    File f = new File(path);
    f.getParentFile().mkdirs();

    FileOutputStream fos = new FileOutputStream(f);
    fos.write(key);
    fos.flush();
    fos.close();
}

public static void main(String[] args) {
    KeyGenerator kg;
    try {
        kg = new KeyGenerator(2048);
        kg.createKeys();
        System.out.println(kg.getPublicKey().getFormat()); // this prints out X.509

        System.out.println(kg.getPrivateKey().getFormat()); // this prints out PKCS#8

        kg.writeToFile(PUBLIC_KEY_PATH, kg.getPublicKey().getEncoded());
        kg.writeToFile(PRIVATE_KEY_PATH, kg.getPrivateKey().getEncoded());
    } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
        System.err.println(e.getMessage());
    } catch (IOException e) {
        System.err.println(e.getMessage());
    }

}

I need to find a way to store in a vault the private key (which looks like the following picture) in the following format. At the moment when I open the key with a text editor I get something like the following.

enter image description here

Is there anyway to convert this PKCS#8 to an encoding appropriate for storing on a file?

Thanks!

JuanMoreno
  • 2,498
  • 1
  • 25
  • 34
Yorgos Lamprakis
  • 761
  • 7
  • 16
  • A file can contain binary data as well. If you need to store ASCII data, you can convert it via Base64 (see: java.util.Base64) – Ulf Jaehrig Sep 26 '18 at 14:39

2 Answers2

2

Note that regarding getFormat Javadoc this is the ASN.1 standard format:

Returns the name of the primary encoding format of this key, or null if this key does not support encoding. The primary encoding format is named in terms of the appropriate ASN.1 data format, if an ASN.1 specification for this key exists. For example, the name of the ASN.1 data format for public keys is SubjectPublicKeyInfo, as defined by the X.509 standard; in this case, the returned format is "X.509". Similarly, the name of the ASN.1 data format for private keys is PrivateKeyInfo, as defined by the PKCS #8 standard; in this case, the returned format is "PKCS#8".

But, if we need to change it for some reason we can use Bouncy Castle: For example:

  //Convert to PKCS#1
  PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(kg.getPrivateKey().getEncoded());
  ASN1Encodable encodable = pkInfo.parsePrivateKey();
  ASN1Primitive primitive = encodable.toASN1Primitive();
  byte[] privateKeyPKCS1 = primitive.getEncoded();
  //kg.writeToFile(PRIVATE_KEY_PATH, privateKeyPKCS1);

  //Convert 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();
  kg.writeToFile(PRIVATE_KEY_PATH, pemString.getBytes());

We'll get a file like this:

-----BEGIN RSA PRIVATE KEY----- 
MIIEpQIBAAKCAQEAr76DpCYkQKMCKRyjx9wyVKihU4vSBeTq7VpkJx9g616AUTtI
yzMZyHa2vVucgkZL9VFS+ZwJZk7b6pNUUSwnwKxHFnRndid2Hum1ZZZCzRYwhsKq
. . . 
XIA+HTgaXbEsCyDcX7EWVlpnTzq5ASO2llKT8V0Mswyh2fznbm5nH92fUKUku2nL 
VAQC2f8PL2eLec3wmb0ZWBazadakMC1fVH3umiBmFnkyDoEfojdOgSo=
-----END RSA PRIVATE KEY-----

I used this BouncyCastle version:

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.60</version>
</dependency>

This question talks about the same problem but for the public key encoding: Generating RSA keys in PKCS#1 format in Java

Thanks to the comment of @dave_thompson_085 I realized another way to do it using the class JcaMiscPEMGenerator

  JcaMiscPEMGenerator generator = new JcaMiscPEMGenerator(kg.getPrivateKey());
  stringWriter = new StringWriter();
  pemWriter = new PemWriter(stringWriter);
  pemWriter.writeObject(generator.generate());
  pemWriter.close();
  pemString = stringWriter.toString();
  kg.writeToFile(PRIVATE_KEY_PATH, pemString.getBytes());

To use it we need to add the following dependency instead:

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcpkix-jdk15on</artifactId>
  <version>1.60</version>
</dependency>
JuanMoreno
  • 2,498
  • 1
  • 25
  • 34
1

I feel quite stupid now that I have spent hours on that.. I will put the answer here.

So the problem is that I want to store as a string (in a text file the contents of a binary file - like the one depicted on the picture above)

If you are using a unix based system you can have it easily by:

base64 filename.key > string.txt

now if you want to have your binary file back, is as easy as:

base64 -D string.txt > filename-clone.key

So it was not that java related question

Yorgos Lamprakis
  • 761
  • 7
  • 16