Morteza Shahriari Nia
Morteza Shahriari Nia

Reputation: 1452

Decrypt gpg in Java without using Java.Runtime

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.

Upvotes: 3

Views: 7400

Answers (3)

Skyr
Skyr

Reputation: 1010

The Bouncy Castle library provides (among other features) an OpenPGP implementation. The package org.bouncycastle.openpgp.examples contains several usage examples, one of them showing how to encrypt/decrypt a file using a public/secret key pair (you can have a look at the examples on GrepCode or on the project's Github mirror).

Upvotes: 1

Mikey
Mikey

Reputation: 430

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/

Upvotes: 1

Jens
Jens

Reputation: 590

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);
}

Upvotes: 3

Related Questions