Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decrypt gpg in Java without using Java.Runtime

Tags:

java

rsa

gnupg

I have a .gpg file and a RSA private key. How can I programatically decrypt it without using operating system? e.g. without using something like Runtime.getRuntime().exec("gpg -decrypt.....");

Libraries I've found all run operating system. Like GnuPG or gnugpg-for-java.

like image 258
Morteza Shahriari Nia Avatar asked Mar 16 '26 01:03

Morteza Shahriari Nia


2 Answers

As Skyr mentioned: Bouncy Castle is the way to go.

What do you want to do with this key? If your goal is to en- or decrypt files you might want to take a look at bouncy-gpg (shameless plug: I wrote it).

Using secret keys is actually three steps

  1. Parse the key and put it into a PGPSecretKeyRing
  2. Extract the secret key from the keyring
  3. Decrypt it with the password

1. Parsing the exported key

In any case look here for the part that parses keys:

class ...

private PGPSecretKeyRingCollection secretKeyRings = new PGPSecretKeyRingCollection(EMPTY_LIST);

 ...

/**
 * Add a new secret keyring to the public keyrings.
 * .
 * Can read the result of "gpg --export" and "gpg --export -a keyid"
 * .
 * E.g. "gpg --export-secret-key -a keyid":
 * addSecretKey("-----BEGIN PGP PRIVATE KEY BLOCK----- ....".getBytes("US-ASCII")
 * <p>
 * The password is queried via the callback (decryptionSecretKeyPassphraseForSecretKeyId).
 *
 * @param encodedPrivateKey the key ascii armored or binary
 * @throws IOException  IO is dangerous
 * @throws PGPException E.g. this is nor a valid key
 */
public void addSecretKey(byte[] encodedPrivateKey) throws IOException, PGPException {

    if (encodedPrivateKey == null) {
        throw new NullPointerException("encodedPrivateKey must not be null");
    }

    try (
            final InputStream raw = new ByteArrayInputStream(encodedPrivateKey);
            final InputStream decoded = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(raw)
    ) {
        PGPSecretKeyRing pgpPrivate = new PGPSecretKeyRing(decoded, getKeyFingerPrintCalculator());
        this.secretKeyRings = PGPSecretKeyRingCollection.addSecretKeyRing(this.secretKeyRings, pgpPrivate);
    }
}

2. Getting the key from the keyring

       final PGPSecretKeyRingCollection pgpSec = ...
       final PGPSecretKey encryptedKey = pgpSec.getSecretKey(keyID);

3. Decrypting the key

Later you have to decrypt the key using a password like so:

 /**
 * Decrypt an encrypted PGP secret key.
 *
 * @param encryptedKey An encrypted key
 * @param passphrase   The passphrase for the key
 * @return the decrypted secret key
 * @throws PGPException E.g. wrong passphrase
 */
public static PGPPrivateKey extractPrivateKey(PGPSecretKey encryptedKey, final char[] passphrase) throws PGPException {
    LOGGER.debug("Extracting secret key with key ID '0x{}'", Long.toHexString(encryptedKey.getKeyID()));

    PGPDigestCalculatorProvider calcProvider = new JcaPGPDigestCalculatorProviderBuilder()
            .setProvider(BouncyCastleProvider.PROVIDER_NAME).build();

    PBESecretKeyDecryptor decryptor = new JcePBESecretKeyDecryptorBuilder(
            calcProvider).setProvider(BouncyCastleProvider.PROVIDER_NAME)
            .build(passphrase);

    return encryptedKey.extractPrivateKey(decryptor);
}
like image 122
Jens Avatar answered Mar 18 '26 15:03

Jens


there are too many examples that I've tried on Bouncy Castle with PGP. The common issue is keyID can't be found in KeyRing.

So, I found @Jens' bouncy-gpg (not sure if he still maintains it.)

Here is his documentation from github.io. It's simple to follow and works! https://neuhalje.github.io/bouncy-gpg/

like image 21
Mikey Avatar answered Mar 18 '26 16:03

Mikey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!