Read RSA keys from PEM files in Java
In a previous tutorial we dealt with RSA key generation and how to save them to PEM files in Java. In this tutorial we will learn how to read RSA keys from PEM files that we previously created. Once again, we will make use of the BouncyCastle library to take benefit from its PEM related classes, such as PemObject
and PemReader
.
To deal with this tutorial it is required:
- Maven.
- JDK 1.6+
- An IDE, such as Eclipse or Spring Tool Suite.
Table of Contents
- 1. Create a Maven project
- 2. Configure the POM file
- 3. Create PemFile class to encapsulate PEM file I/O operations
- 4. Create the main program class
- 5. Result
- Download the code
- References
1. Create a Maven project
Having Maven installed and its environment variables properly configured, execute the following command in a shell to create a brand new Maven project:
mvn archetype:generate -DgroupId=com.txedo.security -DartifactId=bouncycastle-pem-read -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Import the project into your favourite IDE and let’s get down to work.
2. Configure the POM file
Although we could have just evolved the bouncycastle-rsa-pem-write project, we have opted for creating a new one to add the new functionality. I suggest you as homework to merge both projects together. That said, the first step is to edit the pom file and add the BouncyCastle dependency. In the snippet below, we also added the log4j dependency to print some debug traces in our program.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.txedo.security</groupId>
<artifactId>bouncycastle-pem-read</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
3. Create PemFile class to encapsulate PEM file I/O operations
Create the PemFile
class and add a constructor that accepts a string as argument to initialize a PemObject
attribute (line 14). The argument must be the full path and filename to a PEM file located anywhere in your local hard drive or classpath. Do not forget to close the reader after successfully or unsuccessfully performing the reading operation to avoid warnings or unexpected behavior (line 18). Later, the main program will create PemFile
instances and actually read RSA keys.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
public class PemFile {
private PemObject pemObject;
public PemFile(String filename) throws FileNotFoundException, IOException {
PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename)));
try {
this.pemObject = pemReader.readPemObject();
} finally {
pemReader.close();
}
}
public PemObject getPemObject() {
return pemObject;
}
}
4. Create the main program class
The main class have two key generation methods, one for the private key and another for the public key that actually read RSA keys, and the main method that orchestrates all together.
First, the generate private key method (line 38) takes the filename to instantiate a PemFile
instance and read the private RSA key, build a PKCS8EncodedKeySpec
and then generate the private key. The generate public key method (line 45) takes seamlessly the filename to instantiate a PemFile
instance and read the public RSA key, build a X509EncodedKeySpec
and then generate the public key.
Finally, the main method adds the BouncyCastle
provider (line 23), gets a key factory instance using such provider (line 26) and generates previously read RSA keys by calling the generation methods described above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class Main {
protected final static Logger LOGGER = Logger.getLogger(Main.class);
public final static String RESOURCES_DIR = "src/main/resources/rsa-sample/";
public static void main(String[] args) throws FileNotFoundException, IOException, NoSuchAlgorithmException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
LOGGER.info("BouncyCastle provider added.");
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
try {
PrivateKey priv = generatePrivateKey(factory, RESOURCES_DIR + "id_rsa");
LOGGER.info(String.format("Instantiated private key: %s", priv));
PublicKey pub = generatePublicKey(factory, RESOURCES_DIR + "id_rsa.pub");
LOGGER.info(String.format("Instantiated public key: %s", pub));
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
}
private static PrivateKey generatePrivateKey(KeyFactory factory, String filename) throws InvalidKeySpecException, FileNotFoundException, IOException {
PemFile pemFile = new PemFile(filename);
byte[] content = pemFile.getPemObject().getContent();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
return factory.generatePrivate(privKeySpec);
}
private static PublicKey generatePublicKey(KeyFactory factory, String filename) throws InvalidKeySpecException, FileNotFoundException, IOException {
PemFile pemFile = new PemFile(filename);
byte[] content = pemFile.getPemObject().getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return factory.generatePublic(pubKeySpec);
}
}
5. Result
Once the program is executed, we get a console output like this:
Main:27 - BouncyCastle provider added.
Main:34 - Instantiated private key: RSA Private CRT Key
modulus: 80bfe9b773b36733509054642c2b5ab9f6ed3bb7f05d891b53dc04b9197c3bc0fb989dd3b9fff74ec53e38911089173c9507db1ed237f105e09e7de8b07dd1ec7c1c4859a80586fa909b8c7e3bfac90a696b51416d8d9b0774ffe3ffe494f36f5063e0f75b12772d7397ac297b2f45cd579b0fc24f36f206c8a8f4d07f2fe4dd
public exponent: 10001
private exponent: 67ff9d806c5b3c3f7d1238b8f9dcc35a78154529dd6510bd1c4e1b1a917582a6ee14675881643b964b496953f471686dad4c3d3976416dd57b8d4ad34ccd35658a8ffdabe54c349034777a0540b803baaa0274a2ff9ae188920789c88a27cb1973ff3a54c3995583029cc560764b4bb49bf33850d6960f0aed5148b15d69aa59
primeP: ef2b3fbb698e696a42bd5868cc1af071243ac93c21f770b835350c990d8fca2d0c36f4a00389356cf34aa4d23bd9717b0475eb7f46b69da1ad7742096b6aef7f
primeQ: 89cf6770a0abd13425b670d678814d9a826f5b02e2c6696dff6355fc0431ece44cef4b29985d72c928200938881dacf05ca4bd2e4109a3f58d1b362c924a19a3
primeExponentP: 9d3bb499740ac0f8afc9a52eb848599c3832418bbbd4dd90ecc1e47756781a75451b77f51e7dfcd694979505f57cbd631f8a9a78c1375b28284f47e5c36db8e7
primeExponentQ: 553020813ed0f741850e823211cbdc6ce6b46f4e19610d4b31d3f6131384c92b576394d2e19ce297f675d73d5ae6fd4098043ded99c69bd3eea62396e9d76481
crtCoefficient: daac44c1e731d792eabef504d577622b578082651bae4fa0c1e58579aaac6f64f9933f363252ccf2689bf0b981cf976ee41030730a8a8bc8a059aff86976a1fe
Main:37 - Instantiated public key: RSA Public Key
modulus: 80bfe9b773b36733509054642c2b5ab9f6ed3bb7f05d891b53dc04b9197c3bc0fb989dd3b9fff74ec53e38911089173c9507db1ed237f105e09e7de8b07dd1ec7c1c4859a80586fa909b8c7e3bfac90a696b51416d8d9b0774ffe3ffe494f36f5063e0f75b12772d7397ac297b2f45cd579b0fc24f36f206c8a8f4d07f2fe4dd
public exponent: 10001
The output indicates that the program read successfully the id_rsa
and id_rsa.pub
PEM files and printed them out in terms of modulus and exponents.
Download the code
The code used in this article to read RSA keys from PEM files in Java can be found in GitHub: