Series: Signing Messages for Message Broker – Using Bouncycastle library to read PGP key and sign plain text

Why would you need this?

I am currently investigating how an advanced level of security can be applied to a message based micro service architecture.

One could easily rely on the authentication and authorization of the message broker. But this requires extensive options in the message broker.

So why not add an additional layer, by signing the messages via OpenPGP, GnuPG, PGP or similar patterns.

Therefore you’d also be able to sign the keys and create a trusted group within your artifacts.

As a first step, I’ve analyzed the options in Java to use a GPG public/private key set, in an export file. This seems to be handier than a real GPG trust store. It makes the distribution of the keys easier and less dependend on the base operating system.

Here is some source code…

I’ve used the bouncycastle library to do the heavy lifting of cryptographics, but anyways it is still a little tricky to put all the different pieces together.

Therefore I decided to give a little bit of an idea what has to be done by providing a little code snippet:

        Security.addProvider(new BouncyCastleProvider());

        String input = "Sign Me";
        String passphrase = "test1234";

        long keyId = Long.decode("0x566F1E11219B208A");

        @Cleanup
        InputStream fileInputStream =
                new FileInputStream("/tmp/exported-keys.asc");

        InputStream in = PGPUtil.getDecoderStream(fileInputStream);
        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in, new BcKeyFingerprintCalculator());

        PGPSecretKey secretKey = pgpSec.getSecretKey(keyId);

        if (secretKey == null) {
            throw new IllegalArgumentException("Can't find encryption key in key ring.");
        }


        PGPPrivateKey privateKey =
                secretKey.extractPrivateKey(
                        new JcePBESecretKeyDecryptorBuilder()
                                .setProvider("BC").build(passphrase.toCharArray()));
        PGPSignatureGenerator sigGenerator = new PGPSignatureGenerator(
                new JcaPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
                        .setProvider("BC"));

        sigGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);

        ByteArrayOutputStream buffer = new ByteArrayOutputStream();

        try (ArmoredOutputStream aOut = new ArmoredOutputStream(buffer)) {
            BCPGOutputStream bOut = new BCPGOutputStream(aOut);
            sigGenerator.update(input.getBytes(StandardCharsets.UTF_8));
            sigGenerator.generate().encode(bOut);
        }

        System.out.println(new String(buffer.toByteArray(), StandardCharsets.UTF_8));