OpenPGP Integration (Java and JavaScript): Java keys generation

key next to keyhole

If you’ve read my previous post, you probably already know how much I appreciate OpenPGP. This standard brings structure to a complex subject, that is the secure encryption of our data. Considering the current wave of concern on privacy and data confidentiality, why not learning one more approach to secure data and communications?

Here’s what I’m proposing:

  1. We will start by learning  how to generate OpenPGP-compliant keys using Java.
  2. We will then examine one excellent library makes encryption on the server side a breeze!
  3. Consequently we will have a quick look at the sublime OpenPGP.js library.
  4. Finally, we will exchange encrypted messages between Java and JavaScript. How cool is that!

I cannot go too much into specifics regarding how exactly OpenPGP works. However I recommend you to read this excellent article by Zachary Voase: it should get you started.

The code for this series of tutorials is available on GitHub.

So buckle up: here we go!

Why generating OpenPGP keys on server side?

Before we can encrypt, we must generate our encryption key pair: one public, one private. One usually generates GPG encryption keys with the help of Gnu Privacy Guard. However the command line tool requires a minimum level of understanding of PGP, which your end users might not have. Even with front end tools to facilitate the process, GPG is not everybody’s cup of tea!

Since we’re great developers, we can certainly write something to generate these keys for our users. With a web front end, we could leverage OpenPGP.js, and excellent library which will be discussed in a forthcoming post. But we may not always have that option! In those situations we can have our server generate the keys for our clients.

For one specific case, I needed the client to be able to send data to the server in a very secure way. My solution was to have the server generate and cache its own key ring, and have the public key sent to the web clients. With those public keys, the web clients would encrypt their data with the OpenPGP.js library, using the server’s public key, before sending it over.

Setting up the project

If you haven’t done it yet, I’d advise you to head to my GitHub repository and check out the code for this tutorial.

The project uses Spring Boot for the global set up, resulting in a very concise pom.xml file. It imports one important library: BouncyCastle, the de facto Java standard for the encryption-hungry programmers! The OpenPGP class implements the whole logic and is built as a utility library which you should be able to reuse for your own projects. Obviously, the OpenPGPTest class ensures that everything works as expected…

We start by registering BouncyCastle as the security provider:

static {
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
        Security.addProvider(new BouncyCastleProvider());
    }
}

We also implement a simple ArmoredKeyPair class to encapsulate the notion of armored key pairs throughout the code. As a reminder: armored keys use a text format that looks like this:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.59

...

-----END PGP PUBLIC KEY BLOCK-----

OpenPGP Java keys generation

The entry-point method provides the key generation process’ outline:

public ArmoredKeyPair generateKeys(int keySize, String userIdName, String userIdEmail, String passphrase) throws PGPException {

    Date now = new Date();

    RSAKeyPairGenerator keyPairGenerator = keyPairGenerator(keySize);

    PGPKeyPair encryptionKeyPair = encryptionKeyPair(now, keyPairGenerator);
    PGPSignatureSubpacketVector encryptionKeySignature = encryptionKeySignature();

    PGPKeyPair signingKeyPair = signingKeyPair(keyPairGenerator, now);
    PGPSignatureSubpacketVector signingKeySignature = signingKeySignature();

    PGPKeyRingGenerator keyRingGenerator = new PGPKeyRingGenerator(
            PGPSignature.POSITIVE_CERTIFICATION,
            signingKeyPair,
            userIdName + " <" + userIdEmail + ">",
            new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1),
            signingKeySignature,
            null,
            new BcPGPContentSignerBuilder(signingKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1),
            secretKeyEncryptor(passphrase)
    );
    keyRingGenerator.addSubKey(encryptionKeyPair, encryptionKeySignature, null);

    try {
        return ArmoredKeyPair.of(
                generateArmoredSecretKeyRing(keyRingGenerator),
                generateArmoredPublicKeyRing(keyRingGenerator));
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

We use the RSAKeyPairGenerator from BouncyCastle to build our encryption and signature RSA keys.
Those keys are in turn “signed” with sub-packet vectors. We essentially flag the keys to describe they roles: we sign one as being the “encryption key”…

private PGPSignatureSubpacketVector encryptionKeySignature() {
    PGPSignatureSubpacketGenerator encryptionKeySignatureGenerator = new PGPSignatureSubpacketGenerator();
    encryptionKeySignatureGenerator.setKeyFlags(false, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
    return encryptionKeySignatureGenerator.generate();
}

… and the other as being the “signing key”:

private PGPSignatureSubpacketVector signingKeySignature() {
    PGPSignatureSubpacketGenerator signingKeySignatureGenerator = new PGPSignatureSubpacketGenerator();
    signingKeySignatureGenerator.setKeyFlags(false, KeyFlags.SIGN_DATA | KeyFlags.CERTIFY_OTHER); 
    signingKeySignatureGenerator.setPreferredSymmetricAlgorithms(false, new int[]{SymmetricKeyAlgorithmTags.AES_256});
    signingKeySignatureGenerator.setPreferredHashAlgorithms(false, new int[]{HashAlgorithmTags.SHA512});
    signingKeySignatureGenerator.setFeature(false, Features.FEATURE_MODIFICATION_DETECTION);
    return signingKeySignatureGenerator.generate();
}

We can now proceed to building a key ring for our keys.

Keeping our keys together

A PGP key ring keeps your keys together. We normally want two key rings. One stores our public keys and the public keys of whoever we trust and exchange messages with. The other, the secret key ring, regroups our private keys.

In practice we will use BouncyCastle to build a global “key ring generator”, from which we can extract our public and secret key rings:

PGPKeyRingGenerator keyRingGenerator = new PGPKeyRingGenerator(
        PGPSignature.POSITIVE_CERTIFICATION,
        signingKeyPair,
        userIdName + " <" + userIdEmail + ">",
        new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1),
        signingKeySignature,
        null,
        new BcPGPContentSignerBuilder(signingKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1),
        secretKeyEncryptor(passphrase)
);
keyRingGenerator.addSubKey(encryptionKeyPair, encryptionKeySignature, null);

Now that we have our key ring generator, we can generate our public and private key rings:

try {
    return ArmoredKeyPair.of(
            generateArmoredSecretKeyRing(keyRingGenerator),
            generateArmoredPublicKeyRing(keyRingGenerator));
} catch (IOException e) {
    throw new RuntimeException(e);
}
private String generateArmoredSecretKeyRing(PGPKeyRingGenerator keyRingGenerator) throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try (
            ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(outputStream);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(armoredOutputStream)
    ) {
        keyRingGenerator.generateSecretKeyRing().encode(bufferedOutputStream);
    }
    return outputStream.toString(StandardCharsets.UTF_8.name());
}

private String generateArmoredPublicKeyRing(PGPKeyRingGenerator keyRingGenerator) throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try (
            ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(outputStream);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(armoredOutputStream)
    ) {
        keyRingGenerator.generatePublicKeyRing().encode(bufferedOutputStream, true);
    }
    return outputStream.toString(StandardCharsets.UTF_8.name());
}

And voilà!

The full code for generating the keys as well as the test class that makes it run (OpenPGPTest) available on the GitHub repo. I have successfully used the keys generated by this code to exchange messages with a front end client using OpenPGP.js. But I’ll get back to that in a forthcoming post 😉

As you know, many of these posts are written by learning from the best out there.
The code I’ve described here is largely inspired from BouncyCastle’s PGP Cookbook. And these articles and posts do a great job at explaining the principles of PGP encryption in a simple, accessible way. I heartily recommend them:

Until next time,

Cheers!

 

 

 

Leave A Comment

Please be polite. We appreciate that. Your email address will not be published and required fields are marked

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: