Search code examples
javaencryptionbouncycastlepgp

Java Bouncy castle cryptography : decrypted file is empty when encrypted by the same program


I have used this program to encrypt a file with our public key (in .asc) and then decrypt this encrypted file using our private key-ring (.skr).

The encryption part is creating a file but when decrypting the same file , the decrypted file is empty. May I get an insight on the reason why it is empty.

FYI: This decryption part worked fine with same .skr for other file which was not encrypted by this program.

Test is towards the end of the program in the main method.

        package com.something.digtal.web.generic.utils;

        import org.bouncycastle.bcpg.ArmoredOutputStream;
        import org.bouncycastle.bcpg.CompressionAlgorithmTags;
        import org.bouncycastle.jce.provider.BouncyCastleProvider; 
        import org.bouncycastle.openpgp.PGPCompressedData; 
        import org.bouncycastle.openpgp.PGPCompressedDataGenerator; 
        import org.bouncycastle.openpgp.PGPEncryptedData; 
        import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; 
        import org.bouncycastle.openpgp.PGPEncryptedDataList; 
        import org.bouncycastle.openpgp.PGPException; 
        import org.bouncycastle.openpgp.PGPLiteralData; 
        import org.bouncycastle.openpgp.PGPObjectFactory; 
        import org.bouncycastle.openpgp.PGPOnePassSignatureList; 
        import org.bouncycastle.openpgp.PGPPrivateKey; 
        import org.bouncycastle.openpgp.PGPPublicKey; 
        import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; 
        import org.bouncycastle.openpgp.PGPPublicKeyRing; 
        import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; 
        import org.bouncycastle.openpgp.PGPSecretKey; 
        import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; 
        import org.bouncycastle.openpgp.PGPUtil;

        import java.io.*;
        import java.security.NoSuchProviderException;
        import java.security.SecureRandom; 
        import java.security.Security; 
        import java.util.Iterator; 

        //Matthew McCullough: Rediculous as it sounds, many of the functions such as  
        // private static void encryptFile() 
        // private static void decryptFile() 
        // private static PGPPrivateKey findSecretKey() 
        // private static PGPPublicKey readPublicKey() 
        // for PGP in BouncyCastle are private, thus making it unbearable to use 
        // in a simple manner against whole file contents. Thus, this class is duplicated from the 
        // core of BouncyCastle (KeyBasedFileProcessor being the original name), but with the 
        // methods made public so that the test can use them. 

        /**
         * A simple utility class that encrypts/decrypts public key based 
         * encryption files. 
         * <p> 
         * To encrypt a file: KeyBasedFileProcessor -e [-a|-ai] fileName publicKeyFile.<br> 
         * If -a is specified the output file will be "ascii-armored". 
         * If -i is specified the output file will be have integrity checking added. 
         * <p> 
         * To decrypt: KeyBasedFileProcessor -d fileName secretKeyFile passPhrase. 
         * <p> 
         * Note 1: this example will silently overwrite files, nor does it pay any attention to 
         * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase 
         * will have been used. 
         * <p> 
         * Note 2: if an empty file name has been specified in the literal data object contained in the 
         * encrypted packet a file with the name filename.out will be generated in the current working directory. 
         */ 
        public class EncryptedFileProcessorUtil 
        { 
            /**
             * A simple routine that opens a key ring file and loads the first available key suitable for 
             * encryption. 
             *  
             * @param in 
             * @return 
             * @throws IOException 
             * @throws PGPException 
             */ 
            public static PGPPublicKey readPublicKey( 
                InputStream    in) 
                throws IOException, PGPException 
            { 
                in = PGPUtil.getDecoderStream(in); 

                PGPPublicKeyRingCollection        pgpPub = new PGPPublicKeyRingCollection(in); 

                // 
                // we just loop through the collection till we find a key suitable for encryption, in the real 
                // world you would probably want to be a bit smarter about this. 
                // 

                // 
                // iterate through the key rings. 
                // 
                Iterator<?> rIt = pgpPub.getKeyRings(); 

                while (rIt.hasNext()) 
                { 
                    PGPPublicKeyRing    kRing = (PGPPublicKeyRing)rIt.next();     
                    Iterator<?>                        kIt = kRing.getPublicKeys(); 

                    while (kIt.hasNext()) 
                    { 
                        PGPPublicKey    k = (PGPPublicKey)kIt.next(); 

                        if (k.isEncryptionKey()) 
                        { 
                            return k; 
                        } 
                    } 
                } 

                throw new IllegalArgumentException("Can't find encryption key in key ring."); 
            } 

            /**
             * Search a secret key ring collection for a secret key corresponding to 
             * keyID if it exists. 
             *  
             * @param pgpSec a secret key ring collection. 
             * @param keyID keyID we want. 
             * @param pass passphrase to decrypt secret key with. 
             * @return 
             * @throws PGPException 
             * @throws NoSuchProviderException 
             */ 
            public static PGPPrivateKey findSecretKey( 
                PGPSecretKeyRingCollection  pgpSec, 
                long                        keyID, 
                char[]                      pass) 
                throws PGPException, NoSuchProviderException 
            {     
                PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID); 

                if (pgpSecKey == null) 
                { 
                    return null; 
                } 

                return pgpSecKey.extractPrivateKey(pass, "BC"); 
            } 

            /**
             * decrypt the passed in message stream 
             */ 
            public static void decryptFile( 
                InputStream in, 
                InputStream keyIn, 
                char[]      passwd, 
                String      defaultFileName, 
                String      outputPath) 
                throws Exception 
            { 
                in = PGPUtil.getDecoderStream(in); 

                PGPObjectFactory pgpF = new PGPObjectFactory(in); 
                PGPEncryptedDataList    enc; 

                Object                  o = 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; 
                    String              outFileName = ld.getFileName(); 
                    if (ld.getFileName().length() == 0) 
                    { 
                        outFileName = defaultFileName; 
                    } 

                    //MJM: Enhancement to allow targeting of output folder for decrypted files 
                    if (outputPath != null || outputPath.length() > 0) { 
                        outFileName = outputPath + outFileName; 
                    } 

                    BufferedOutputStream fOut = new BufferedOutputStream( new FileOutputStream(outFileName));

                    BufferedInputStream    unc = new BufferedInputStream(ld.getInputStream());
                    int    ch;


                    byte[] buffer = new byte[ 1024 * 1024 ];
                    int len;
                    while ( ( len = unc.read( buffer ) ) != -1 )
                    {
                        // Writing data and potentially sending off a part
                        fOut.write( buffer, 0, len );
                    }

                    /*
                    while ((ch = unc.read()) >= 0)
                    { 
                        fOut.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("message integrity check passed"); 
                    } 
                } 
                else 
                { 
                    System.err.println("no message integrity check"); 
                } 
            } 




            public static void encryptFile( 
                OutputStream    out, 
                String          fileName, 
                PGPPublicKey    encKey, 
                boolean         armor, 
                boolean         withIntegrityCheck) 
                throws IOException, NoSuchProviderException 
            {     
                if (armor) 
                { 
                    out = new ArmoredOutputStream(out); 
                } 

                try 
                { 
                    ByteArrayOutputStream       bOut = new ByteArrayOutputStream(); 


                    PGPCompressedDataGenerator  comData = new PGPCompressedDataGenerator( 
                                                                            PGPCompressedData.ZIP); 

                    PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName)); 

                    comData.close(); 

                    PGPEncryptedDataGenerator   cPk = new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(), "BC"); 

                    cPk.addMethod(encKey); 

                    byte[]                bytes = bOut.toByteArray(); 

                    OutputStream    cOut = cPk.open(out, bytes.length); 

                    cOut.write(bytes); 

                    cOut.close(); 

                    out.close(); 
                } 
                catch (PGPException e) 
                { 
                    System.err.println(e); 
                    if (e.getUnderlyingException() != null) 
                    { 
                        e.getUnderlyingException().printStackTrace(); 
                    } 
                } 
            } 

            public static void main( 
                String[] args) 
                throws Exception 
            { 


                //Encrypt
                OutputStream    out = new FileOutputStream("C:\\temp\\delete\\PGP_Test\\encryption_output.pgp"); 
                String          fileName = "C:\\temp\\delete\\PGP_Test\\encryption_input.txt"; 
                PGPPublicKey    encKey = readPublicKey(new FileInputStream("C:\\temp\\delete\\PGP_Test\\Online-eng-request_public.asc")); 
                encryptFile(out, fileName, encKey, false, false); 


                //Now decrypt
                String PASSPHRASE = "tata wants to chase a squirrel";
                String DE_INPUT = "C:\\temp\\delete\\PGP_Test\\encryption_output.pgp";
                String DE_OUTPUTPATH = "C:\\temp\\delete\\PGP_Test\\archive\\";
                String DE_OUTPUTFILE = "something_17APR2016.txt";
                String DE_KEY_FILE = "C:\\temp\\delete\\PGP_Test\\secring.skr";


                FileInputStream    in = new FileInputStream(DE_INPUT); 
                FileInputStream    keyIn = new FileInputStream(DE_KEY_FILE); 
                decryptFile(in, keyIn, PASSPHRASE.toCharArray(), new File(DE_OUTPUTFILE).getName(), DE_OUTPUTPATH); 
            } 
        }

Solution

  • You aren't closing fOut. Flushing it is insufficient, as you still have a resource leak.