Search code examples
javaencryptionbouncycastlepgpelgamal

How can I encrypt/decrypt content with ELGAMAL PGP algorithm by using Bouncy Castle Java library with Certificates persisted in JKS


I need to encrypt and decrypt some messages with PGP and using ELGAMAL algorithm. My Keys are stored in a JKS Keystore. As far as I understand I first need to read keys/certificates from JKS and convert them into PGP Keys so they can be used in PGP encryptor.

However when I try to use the "JcaPGPKeyConverter" and if I give "PublicKeyAlgorithmTags.ELGAMAL_GENERAL" for the public key type I get "org.bouncycastle.openpgp.PGPException: unknown EC algorithm" exception.

Here is the converter code to generate PGP Public Key:

JcaPGPKeyConverter jcaPGPKeyConverter = new JcaPGPKeyConverter();
Certificate encryptionCertificate = keyStore.getCertificate(certificateAlias);
PGPPublicKey pgpEncryptionPublicKey = jcaPGPKeyConverter.getPGPPublicKey(
             PublicKeyAlgorithmTags.ELGAMAL_GENERAL, // if I use ECDH here converter works
             encryptionCertificate.getPublicKey(), new Date());

Here is stack trace:

org.bouncycastle.openpgp.PGPException: unknown EC algorithm
    at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPublicBCPGKey(Unknown Source)
    at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPGPPublicKey(Unknown Source)
    at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPGPPublicKey(Unknown Source)

It works with "PublicKeyAlgorithmTags.ECDH" (I found on the source code of JcaPGPKeyConverter) but on later step I get the encryption method form the generated PGPPublicKey. So If I use ECDH on converter and only use algorithm written on the Public Key object, I guess then I am not using ELGAMAL any more for encryption:

PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256) //
                    .setWithIntegrityPacket(true) //
                    .setSecureRandom(random) //
                    .setProvider(BOUNCY_CASTLE));
// Here I use previously converted public key to generate encryption method and it gets algorithm from public key:
JcePublicKeyKeyEncryptionMethodGenerator encryptionMethodGenerator = 
                                         new JcePublicKeyKeyEncryptionMethodGenerator(pgpEncryptionPublicKey)
                                        .setProvider(BOUNCY_CASTLE);
encryptedDataGenerator.addMethod(encryptionMethodGenerator);

I have seen examples with ELGAMAL on internet but all generate keys on the fly. I need to use keys persisted in the JKS/JCEKS.

Is there another way to convert the Certificates read from the JKS into PGPPublicKey? Or can I directly define the Encryption Algorithm (ELGAMAL) on the PGPEncryptedDataGenerator?

Thanks for your help..


Solution

  • It seems like the "jcaPGPKeyConverter.getPGPPublicKey" needs the creation date of the certificate. On the first code block above I was using the execution time as creation time with 'new Date()' parameter.

    This works if the encryption and decryption happens in the same minute for example in unit tests. Otherwise since we convert key with different time parameter, converted key on different times do not work as expected. Replacing 'new Date()' parameter with certificate creation time fixes the issue.