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.
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;
}
*/
}
What is the error/exception thrown when you try to decrypt?
>>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
You are, i assume, attempting to decrypt it using his *public* key are you? That's what you must do
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.");
throw new IllegalArgumentException("
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
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?
He encrypts messages he sends to you using *your* public key. Is that what's happening?
ASKER
Yes. let me know if you would like to see the encrypted file.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thaks CEHJ, let me look at it and will let you know!
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
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
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();
}
}
}
}
ASKER
Although example wasnt clear and had some issues but gave me an idea, thanks CEHJ
Good :-)