Link to home
Start Free TrialLog in
Avatar of alexk23
alexk23

asked on

Decrypt pgp file using bouncycastle api

Hello, I am trying to decrypt PGP encrypted file. The file was encrypted using my public key that I generated. I could encrypt and decrypt the files that I created locally using bouncycastle API, but when my client encrypts the file on his side I am not able to decrypt it using bouncycastle API but could decrypt it manually using gnupg on command prompt.

When run decryption in my class I am not able to find secret key to decrypt the file. And I am not sure how my client decrypts it.

Please let me know if you have any suggestions.

import org.bouncycastle.openpgp.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
 
 
import java.io.*;
import java.util.Iterator;
import java.security.NoSuchProviderException;
import java.security.Security;
 
 
 
public class PGPSecurityService {
    public PGPSecurityService(){}
 
    public static  void main(String[] args){
        try{
            Security.addProvider(new BouncyCastleProvider());
            FileInputStream privKey = new FileInputStream("C:\\apps\\private\\secring.gpg");
            InputStream file = new BufferedInputStream (new FileInputStream("C:\\apps\\private\\encrypted.pgp"));
            System.out.println(decryptFile(file, privKey, "mykey".toCharArray()));
        } catch (Exception ex){
            ex.printStackTrace();
        }
    }
 
 
    private static String decryptFile(InputStream in, InputStream keyIn, char[] passwd) throws Exception {
        try {
            PGPObjectFactory pgpF = new PGPObjectFactory(PGPUtil.getDecoderStream(in));
            Object o = pgpF.nextObject();
            PGPEncryptedDataList enc = o instanceof  PGPEncryptedDataList ? (PGPEncryptedDataList) o :(PGPEncryptedDataList) pgpF.nextObject();
            Iterator it = enc.getEncryptedDataObjects();
            PGPPrivateKey sKey = null;
            PGPPublicKeyEncryptedData pbe = null;
 
            while (sKey == null && it.hasNext()) {
                pbe = (PGPPublicKeyEncryptedData) it.next();
                sKey =findSecretKey(keyIn, pbe.getKeyID(), passwd);
            }
            if (sKey == null) {
 
                throw new IllegalArgumentException("secret key for message not found.");
            }
 
            InputStream clear = pbe.getDataStream(sKey, "BC");
            PGPObjectFactory plainFact = new PGPObjectFactory(clear);
            Object message = plainFact.nextObject();
            if (message instanceof  PGPCompressedData) {
                PGPCompressedData cData = (PGPCompressedData) message;
                PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());
                message = pgpFact.nextObject();
            }
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            if (message instanceof PGPLiteralData) {
                PGPLiteralData ld = (PGPLiteralData) message;
                InputStream unc = ld.getInputStream();
                int ch;
                while ((ch = unc.read()) >= 0) {
                    baos.write(ch);
                }
            } else if (message instanceof  PGPOnePassSignatureList) {
                throw new PGPException("encrypted message contains a signed message - not literal data.");
            } else {
                throw new PGPException("message is not a simple encrypted file - type unknown.");
            }
 
            if (pbe.isIntegrityProtected()) {
               if (!pbe.verify()) {
                    System.err.println("message failed integrity check");
               }
            } else {
                System.err.println("no message integrity check");
            }
            return baos.toString();
        } catch (PGPException e) {
            e.printStackTrace();
        }
        return null;
    }
 
    private static PGPPrivateKey findSecretKey(InputStream keyIn, long keyID, char[] pass) throws IOException, PGPException, NoSuchProviderException {
        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
        System.out.println("pgpSec size="+pgpSec);
        System.out.println(keyID);
        PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
        return pgpSecKey != null? pgpSecKey.extractPrivateKey(pass, "BC"): null;
    }
    /*
    public static String decrypt(byte[] encdata, String keyLocation, String phrase) {
            try {
                ByteArrayInputStream bais = new ByteArrayInputStream(encdata);
                FileInputStream privKey = new FileInputStream(keyLocation);
                return decryptFile(bais, privKey, phrase.toCharArray());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        */
  
 
}

Open in new window

Avatar of Gibu George
Gibu George
Flag of India image

What is the error/exception thrown  when you try to decrypt?
Avatar of CEHJ
>>but when my client encrypts the file on his side I am not able to decrypt it using bouncycastle API

You are, i assume, attempting to decrypt it using his *public* key are you? That's what you must do
Avatar of alexk23
alexk23

ASKER

The error is throwing by my null check when I am checking if the key is null
throw new IllegalArgumentException("secret key for message not found.");
Avatar of alexk23

ASKER

CEHJ, I am trying to decrypt the file by my secret key that I used to generate the public key for my client. Are you saying I should use public key to decrypt the file as well?
You decrypt messages *he* sends using *his* public key. He encrypts his own messages using his private key
Avatar of alexk23

ASKER

CEHJ, no the message is being encrypted using public key that I sent to them. And I am able to decrypt the message on command prompt using GnuPG. I checked the path to the secret key and the file I am trying to decrypt all looks good just can't find the key to decrypt encrypted file using my implementation of bouncy castle api
Sorry alexk23, what i just said was wrong.

He encrypts messages he sends to you using *your* public key. Is that what's happening?
Avatar of alexk23

ASKER

Yes. let me know if you would like to see the encrypted file.
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of alexk23

ASKER

Thaks CEHJ, let me look at it and will let you know!
Avatar of alexk23

ASKER

The example does almost the same thing in comparing the keys, but the problem is that when I compare the public vs. private keys I am getting following results:

Data was encrypted using public key:  -4270675083819455261
Data was encrypted using public key:  5471684833902076854

Got secret key: -7878772790183064541 mask=true SigningKey = true
Got secret key: 5471684833902076854 mask=false SigningKey= false

But it still puzzles me how I was able to decrypt same file in command prompt I got couple messages but was able to decrypt it.

gpg: Signature made 04/21/09 03:41:20  using DSA key ID 2BD4FDE5
gpg: Can't check signature: public key not found
gpg: WARNING: message was not integrity protected
Avatar of alexk23

ASKER

I figured it out the problem was with the message was encrypted and signed so I had to check the message signature first. Although example wasnt clear and had some issues but gave me an idea, thanks CEHJ
import org.bouncycastle.openpgp.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
 
import java.io.*;
import java.util.Iterator;
 
 
import java.security.NoSuchProviderException;
import java.security.Security;
 
 
 
public class PGPSecurityService {
 
 
    public static  void main(String[] args){
        try{
            Security.addProvider(new BouncyCastleProvider());
 
            /**
             * decrypt file
             **/
            // my private key
            InputStream privKey = new BufferedInputStream (new FileInputStream("C:\\apps\\private\\secring.gpg"));
            // file to decrypt
            InputStream file = new BufferedInputStream (new FileInputStream("C:\\apps\\encrypted.pgp"));
 
            decryptFile(file, privKey,"mykey".toCharArray());
        } catch (Exception ex){
            ex.printStackTrace();
        }
    }
 
    private static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection  pgpSec, long keyID, char[] pass)
        throws PGPException, NoSuchProviderException{
        PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
        if (pgpSecKey == null){
            return null;
        } else {
            return pgpSecKey.extractPrivateKey(pass, "BC");
        }
    }
 
    private static PGPPublicKey readPublicKeyFromCol(InputStream in)throws Exception {
        PGPPublicKeyRing pkRing = null;
        PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in));
        //System.out.println("key ring size=" + pkCol.size());
        Iterator it = pkCol.getKeyRings();
        while (it.hasNext()) {
            pkRing = (PGPPublicKeyRing) it.next();
            Iterator pkIt = pkRing.getPublicKeys();
            while (pkIt.hasNext()) {
                PGPPublicKey key = (PGPPublicKey) pkIt.next();
                //System.out.println("Encryption key = " + key.isEncryptionKey() + ", Master key = " +key.isMasterKey());
                if (key.isMasterKey())
                    return key;
            }
        }
        return null;
    }
 
    private static void decryptFile( InputStream in, InputStream keyIn, char[] passwd)throws Exception{
        in = PGPUtil.getDecoderStream(in);
        try{
            PGPObjectFactory pgpF = new PGPObjectFactory(in);
            Object o = pgpF.nextObject();
            PGPEncryptedDataList enc = o instanceof PGPEncryptedDataList?(PGPEncryptedDataList)o : (PGPEncryptedDataList)pgpF.nextObject();
 
 
 
            //
            // the first object might be a PGP marker packet.
            //
            /*
            if (o instanceof PGPEncryptedDataList){
                enc = (PGPEncryptedDataList)o;
            }  else {
                enc = (PGPEncryptedDataList)pgpF.nextObject();
            }
            */
            //
            // find the secret key
            //
            Iterator it = enc.getEncryptedDataObjects();
            PGPPrivateKey sKey = null;
            PGPPublicKeyEncryptedData pbe = null;
            PGPSecretKeyRingCollection  pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
 
            while (sKey == null && it.hasNext()){
                pbe = (PGPPublicKeyEncryptedData)it.next();
                sKey = findSecretKey(pgpSec, pbe.getKeyID(), passwd);
            }
            if (sKey == null){
                throw new IllegalArgumentException("secret key for message not found.");
            }
 
            InputStream clear = pbe.getDataStream(sKey, "BC");
            PGPObjectFactory plainFact = new PGPObjectFactory(clear);
            Object message = plainFact.nextObject();
            if (message instanceof PGPCompressedData){
                PGPCompressedData   cData = (PGPCompressedData)message;
                PGPObjectFactory  pgpFact = new PGPObjectFactory(cData.getDataStream());
                message = pgpFact.nextObject();
                if (message instanceof PGPLiteralData){
                    PGPLiteralData      ld = (PGPLiteralData)message;
                    FileOutputStream    fOut = new FileOutputStream("C:\\apps\\private\\outputsigned.txt");
                    InputStream    unc = ld.getInputStream();
                    int    ch;
                    while ((ch = unc.read()) >= 0){
                        fOut.write(ch);
                    }
                }else if (message instanceof PGPOnePassSignatureList) {
 
                    PGPOnePassSignatureList p1 = (PGPOnePassSignatureList) message;
                    InputStream pubKey = new BufferedInputStream (new FileInputStream("C:\\apps\\private\\pubring.gpg"));
                    PGPPublicKey key =readPublicKeyFromCol(pubKey);
                    if(key!=null){
                        PGPOnePassSignature ops = p1.get(0);
                        System.out.println("ops.getKeyID()="+ops.getKeyID());
                        ops.initVerify(key, "BC");
                        // file output dirctory
                        FileOutputStream out = new FileOutputStream("C:\\apps\\private\\outputsigned.txt");
                        PGPLiteralData  p2 = (PGPLiteralData) pgpFact.nextObject();
                        int ch;
                        InputStream  dIn = p2.getInputStream();
                        while ((ch = dIn.read()) >= 0) {
                            ops.update((byte)ch);
                            out.write(ch);
                        }
                        out.close();
                    } else {
                        throw new PGPException ("unable to find public key for signed file");
                    }
                } else {
                    throw new PGPException("message is not a simple encrypted file - type unknown.");
                }
 
                if (pbe.isIntegrityProtected()){
                    if (!pbe.verify()){
                        System.err.println("message failed integrity check");
                    } else{
                        System.err.println("message integrity check passed");
                    }
                } else {
                    System.err.println("no message integrity check");
                }
            } else {
                System.out.println("unable to verify message");
            }
        }catch (PGPException e){
            System.err.println(e);
            if (e.getUnderlyingException() != null){
                e.getUnderlyingException().printStackTrace();
            }
        }
    }
 
 
}

Open in new window

Avatar of alexk23

ASKER

Although example wasnt clear and had some issues but gave me an idea, thanks CEHJ
Good :-)