【问题标题】:Bouncycastle pgp decryption correct size but all blankBouncycastle pgp 解密大小正确但全为空白
【发布时间】:2018-04-18 13:36:42
【问题描述】:

当我调用它时,它成功加密了我的字符串,但解密文本的输出为空白。我没有收到任何错误,并且输出字符串的 byteArray 的长度正确(102),但它只有 102 个零。这改编自 KeyBasedFileProcessor 示例,但尝试基于流/字符串而不是基于文件。

package com.common.security.pgp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
import java.util.Iterator;

import org.apache.commons.io.IOUtils;
import org.bouncycastle.bcpg.ArmoredOutputStream;
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.PGPLiteralDataGenerator;
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;

/**
 * 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 PgpEncryption3 {
    /**
     * 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
     */
    private 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
     */
    private 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
     */
    private static void decryptFile(InputStream in, InputStream keyIn,
            char[] passwd, String defaultFileName, OutputStream out) throws Exception {
        in = PGPUtil.getDecoderStream(in);


        try {
            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) {
                System.out.println(message);
                PGPLiteralData ld = (PGPLiteralData) message;
                System.out.println(ld.getFileName());
                System.out.println(ld.getDataStream());
                InputStream unc = ld.getInputStream();
                int ch;
                while ((ch = unc.read()) >= 0) {
                    System.out.println(ch);
                    out.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");
            }
        } catch (PGPException e) {
            System.err.println(e);
            if (e.getUnderlyingException() != null) {
                e.getUnderlyingException().printStackTrace();
            }
        }
    }


    public static void writeStreamToLiteralData(OutputStream out,
            char fileType, byte[] data, String fileName, Date modDate) throws IOException {
        PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
        OutputStream pOut = lData.open(out, fileType, fileName, data.length, modDate);

        byte[] buf = new byte[4096];
        ByteArrayInputStream in = new ByteArrayInputStream(buf);
        int len;

        while ((len = in.read(buf)) > 0) {
            pOut.write(buf, 0, len);
        }

        lData.close();
        in.close();
    }

    private static void encryptFile(OutputStream out, byte[] data,String fileName,
            PGPPublicKey encKey, boolean armor, boolean withIntegrityCheck, Date modDate)
            throws IOException, NoSuchProviderException {
        if (armor) {
            out = new ArmoredOutputStream(out);
        }

        try {
            ByteArrayOutputStream bOut = new ByteArrayOutputStream();




            writeStreamToLiteralData(bOut,PGPLiteralData.TEXT, data, fileName,modDate);


            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 {
        Security.addProvider(new BouncyCastleProvider());


        Date modDate = new Date();

        String dataToEncrypt = "THIS IS SOME TEXTTHIS IS SOME TEXTTHIS IS SOME TEXTTHIS IS SOME TEXTTHIS IS SOME TEXTTHIS IS SOME TEXT";
        System.out.println(dataToEncrypt.length());
        byte[] data = dataToEncrypt.getBytes();
        String fileName = "blah.txt";
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        FileInputStream pKeyIn = new FileInputStream("/Users/me/blah.pub.key");
        encryptFile(out, data, fileName,readPublicKey(pKeyIn), true, false,modDate);
        System.out.println(new String(out.toByteArray()));

        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        System.out.println(in);
        FileInputStream sKeyIn = new FileInputStream("/Users/me/blah.sec.key");
        ByteArrayOutputStream decOut = new ByteArrayOutputStream();
        decryptFile(in, sKeyIn, "mypass".toCharArray(), "blah.txt", decOut);
        System.out.println(decOut.toByteArray().length);
        System.out.println(new String(decOut.toByteArray()));

    }
}

【问题讨论】:

    标签: java bouncycastle pgp


    【解决方案1】:

    完整的工作示例

    package com.common.security.pgp;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.util.Date;
    import java.util.Iterator;
    
    import org.bouncycastle.bcpg.ArmoredOutputStream;
    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.PGPLiteralDataGenerator;
    import org.bouncycastle.openpgp.PGPObjectFactory;
    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;
    
    /**
     * Simple routine to encrypt and decrypt using a Public and Private key with passphrase. This service
     * routine provides the basic PGP services between byte arrays.
     * 
     */
    public class PgpEncryption {
    
    
        private 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
         * 
         * @param encrypted
         *            The message to be decrypted.
         * @param passPhrase
         *            Pass phrase (key)
         * 
         * @return Clear text as a byte array. I18N considerations are not handled
         *         by this routine
         * @exception IOException
         * @exception PGPException
         * @exception NoSuchProviderException
         */
        public static byte[] decrypt(byte[] encrypted, InputStream keyIn, char[] password)
                throws IOException, PGPException, NoSuchProviderException {
            InputStream in = new ByteArrayInputStream(encrypted);
    
            in = PGPUtil.getDecoderStream(in);
    
            PGPObjectFactory pgpF = new PGPObjectFactory(in);
            PGPEncryptedDataList enc = null;
            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(), password);
            }
    
            if (sKey == null) {
                throw new IllegalArgumentException(
                        "secret key for message not found.");
            }
    
            InputStream clear = pbe.getDataStream(sKey, "BC");
    
    
    
            PGPObjectFactory pgpFact = new PGPObjectFactory(clear);
    
            PGPCompressedData cData = (PGPCompressedData) pgpFact.nextObject();
    
            pgpFact = new PGPObjectFactory(cData.getDataStream());
    
            PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
    
            InputStream unc = ld.getInputStream();
    
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int ch;
    
            while ((ch = unc.read()) >= 0) {
                out.write(ch);
    
            }
    
            byte[] returnBytes = out.toByteArray();
            out.close();
            return returnBytes;
        }
    
        /**
         * Simple PGP encryptor between byte[].
         * 
         * @param clearData
         *            The test to be encrypted
         * @param passPhrase
         *            The pass phrase (key). This method assumes that the key is a
         *            simple pass phrase, and does not yet support RSA or more
         *            sophisiticated keying.
         * @param fileName
         *            File name. This is used in the Literal Data Packet (tag 11)
         *            which is really inly important if the data is to be related to
         *            a file to be recovered later. Because this routine does not
         *            know the source of the information, the caller can set
         *            something here for file name use that will be carried. If this
         *            routine is being used to encrypt SOAP MIME bodies, for
         *            example, use the file name from the MIME type, if applicable.
         *            Or anything else appropriate.
         * 
         * @param armor
         * 
         * @return encrypted data.
         * @exception IOException
         * @exception PGPException
         * @exception NoSuchProviderException
         */
        public static byte[] encrypt(byte[] clearData, PGPPublicKey encKey,
                String fileName,boolean withIntegrityCheck, boolean armor)
                throws IOException, PGPException, NoSuchProviderException {
            if (fileName == null) {
                fileName = PGPLiteralData.CONSOLE;
            }
    
            ByteArrayOutputStream encOut = new ByteArrayOutputStream();
    
            OutputStream out = encOut;
            if (armor) {
                out = new ArmoredOutputStream(out);
            }
    
            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    
            PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
                    PGPCompressedDataGenerator.ZIP);
            OutputStream cos = comData.open(bOut); // open it with the final
            // destination
            PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
    
            // we want to generate compressed data. This might be a user option
            // later,
            // in which case we would pass in bOut.
            OutputStream pOut = lData.open(cos, // the compressed output stream
                    PGPLiteralData.BINARY, fileName, // "filename" to store
                    clearData.length, // length of clear data
                    new Date() // current time
                    );
            pOut.write(clearData);
    
            lData.close();
            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); // obtain the actual bytes from the compressed stream
    
            cOut.close();
    
            out.close();
    
            return encOut.toByteArray();
        }
    
        private 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.");
        }
    
        public static byte[] getBytesFromFile(File file) throws IOException {
            InputStream is = new FileInputStream(file);
    
            // Get the size of the file
            long length = file.length();
    
            if (length > Integer.MAX_VALUE) {
                // File is too large
            }
    
            // Create the byte array to hold the data
            byte[] bytes = new byte[(int)length];
    
            // Read in the bytes
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length
                   && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
                offset += numRead;
            }
    
            // Ensure all the bytes have been read in
            if (offset < bytes.length) {
                throw new IOException("Could not completely read file "+file.getName());
            }
    
            // Close the input stream and return bytes
            is.close();
            return bytes;
        }
    
        public static void main(String[] args) throws Exception {
            Security.addProvider(new BouncyCastleProvider());
    
    
            byte[] original = "Hello world".getBytes();
            System.out.println("Starting PGP test");
    
            FileInputStream pubKey = new FileInputStream("/Users/me/pub.key");
            byte[] encrypted = encrypt(original, readPublicKey(pubKey), null,
                    true, true);
    
            FileOutputStream dfis = new FileOutputStream("/Users/me/enc.asc");
            dfis.write(encrypted);
            dfis.close();
    
            byte[] encFromFile = getBytesFromFile(new File("/Users/me/enc.asc"));
            FileInputStream secKey = new FileInputStream("/Users/me/sec.key");
    
            System.out.println("\nencrypted data = '" + new String(encrypted) + "'");
    
            byte[] decrypted = decrypt(encFromFile, secKey, "passphrase".toCharArray());
    
            System.out.println("\ndecrypted data = '" + new String(decrypted) + "'");
    
    
        }
    }
    

    【讨论】:

    • @Rocky4Ever 不知道,这是我 10 年前写的。
    猜你喜欢
    • 1970-01-01
    • 2013-10-10
    • 2011-08-05
    • 1970-01-01
    • 2011-10-22
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 2022-07-23
    相关资源
    最近更新 更多