Java Bouncy castle 密码学:用同一程序加密时解密文件为空

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

我用这个程序用我们的 public 密钥 (在 .asc 中) 加密了一个文件,然后用我们的私钥环 解密了这个加密文件 (.skr).

加密部分正在创建一个文件,但是在解密同一个文件时,解密后的文件是空的。 我可以了解一下为什么它是空的。

仅供参考:对于未被该程序加密的其他文件,此解密部分与相同的 .skr 一起工作正常。

测试快到 main 方法中程序的结尾了。

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

只是一个简单的猜测。您的消息比输出流的缓冲区小,并且没有被刷新...?

您没有关闭 fOut。冲洗它是不够的,因为你仍然有资源泄漏。

这可能是由于外部 Buffer/FileWritter class 在您调用 PGP 函数时被使用但未被关闭的原因。尝试在外部方法中关闭 writer classes 并再次检查。可能有助于解决您的问题。