如何使用 bouncycastle pgp 加密字符串/流而不从文件开始

发布于 2024-09-27 17:11:49 字数 10680 浏览 0 评论 0原文

我需要使用 bouncycastle 提供程序通过 pgp 加密流。我能找到的所有示例都是关于获取纯文本文件并对其进行加密,但是我不会拥有文件,并且重要的是纯文本永远不会写入磁盘。

我见过的大多数方法都使用

PGPUtil.writeFileToLiteralData ,它希望传入纯文本。我宁愿传入一个 byte[] 或一个 inputStream 。

有人可以给我指出一个

  • 从 string/byte[]/inputstream 开始的
  • 示例,将所述 string/byte[] 加密到我可以写入文件的 outputStrem
  • 从 inputStream 解密

以防其他人偶然发现此问题并想要完整的解决方案

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) + "'");


    }
}

I need to encrypt a stream with pgp using the bouncycastle provider. All of the examples I can find are about taking a plain text file and encrypting that however I won't have a file and it's important that the plain text never be written to disk.

Most of the methods I've seen are using

PGPUtil.writeFileToLiteralData which wants the plaintext passed in. I'd rather passin a byte[] or an inputStream.

Can someone point me to an example that

  • starts from string/byte[]/inputstream
  • encrypts said string/byte[] to an outputStrem that I can write to a file
  • decrypts from an inputStream

In case anyone else stumbles upon this and wants the full solution

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) + "'");


    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

音栖息无 2024-10-04 17:11:49

查看 PGPUtil 的源代码,您可以看到直接使用流或数组时要调用什么 API:

public static void writeFileToLiteralData(OutputStream out,
               char fileType, File file, byte[] buffer) throws IOException {
   PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
   OutputStream pOut = lData.open(out, fileType, file.getName(),
                   new Date(file.lastModified()), buffer);
   FileInputStream in = new FileInputStream(file);
   byte[] buf = new byte[buffer.length];
   int len;

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

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

Looking at the source of PGPUtil you can see what API to call when working with streams or arrays directly:

public static void writeFileToLiteralData(OutputStream out,
               char fileType, File file, byte[] buffer) throws IOException {
   PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
   OutputStream pOut = lData.open(out, fileType, file.getName(),
                   new Date(file.lastModified()), buffer);
   FileInputStream in = new FileInputStream(file);
   byte[] buf = new byte[buffer.length];
   int len;

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

   lData.close();
   in.close();
}
烟若柳尘 2024-10-04 17:11:49

发现于 grepcode 存储库 - payneteasy superfly 源

private static void writeBytesToLiteralData(OutputStream out,
    char fileType, String name, byte[] bytes) throws IOException {
        PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
        OutputStream pOut = lData.open(out, fileType, name,bytes.length, new Date());
        pOut.write(bytes);
}

Found at grepcode repository - payneteasy superfly sources

private static void writeBytesToLiteralData(OutputStream out,
    char fileType, String name, byte[] bytes) throws IOException {
        PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
        OutputStream pOut = lData.open(out, fileType, name,bytes.length, new Date());
        pOut.write(bytes);
}
海的爱人是光 2024-10-04 17:11:49

你的代码对我来说非常有用。我正在 ColdFusion(使用 Java)工作,需要获取密码,将它们编码在 LDIFDE 的简短导入文件中(将在另一台服务器上的 Active Directory 中使用),并且我从来不希望密码以明文形式接触磁盘。我只是稍微修改了它,添加了两个函数,抽象出将字符串加密到磁盘和从磁盘解密的常见用例。谢谢@dstarh。

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 {

    public PgpEncryption() {
        // Empty constructor
    }

    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 String encryptToFile(String inputStr, String keyFile, String outFile) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte[] original = inputStr.getBytes();

        FileInputStream pubKey = new FileInputStream(keyFile);
        byte[] encrypted = encrypt(original, readPublicKey(pubKey), null,
                true, true);

        FileOutputStream dfis = new FileOutputStream(outFile);
        dfis.write(encrypted);
        dfis.close();

        return new String(encrypted);
    }

    public static String decryptFromFile(String passphrase, String keyFile, String inputFile) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte[] encFromFile = getBytesFromFile(new File(inputFile));
        FileInputStream secKey = new FileInputStream(keyFile);

        byte[] decrypted = decrypt(encFromFile, secKey, passphrase.toCharArray());

        return new String(decrypted);
    }

    public static void main(String[] args) throws Exception {
        String encrypted = encryptToFile("Hello world","pub.asc","enc.asc");
        System.out.println("\nencrypted data = '" + new String(encrypted) + "'");

        String decrypted = decryptFromFile("open sesame", "secret.asc", "enc.asc");
        System.out.println("\ndecrypted data = '" + decrypted + "'");

    }
}

Your code was extremely useful to me. I am working in ColdFusion (with Java) and needed to take passwords, encode them in a short import file for LDIFDE (to be used in Active Directory on another server) and I never wanted the passwords to touch the disk in plaintext. I modified it only slightly to add two functions that abstract out the common use case of encrypting a string to disk and decrypting from disk. Thank you @dstarh.

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 {

    public PgpEncryption() {
        // Empty constructor
    }

    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 String encryptToFile(String inputStr, String keyFile, String outFile) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte[] original = inputStr.getBytes();

        FileInputStream pubKey = new FileInputStream(keyFile);
        byte[] encrypted = encrypt(original, readPublicKey(pubKey), null,
                true, true);

        FileOutputStream dfis = new FileOutputStream(outFile);
        dfis.write(encrypted);
        dfis.close();

        return new String(encrypted);
    }

    public static String decryptFromFile(String passphrase, String keyFile, String inputFile) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte[] encFromFile = getBytesFromFile(new File(inputFile));
        FileInputStream secKey = new FileInputStream(keyFile);

        byte[] decrypted = decrypt(encFromFile, secKey, passphrase.toCharArray());

        return new String(decrypted);
    }

    public static void main(String[] args) throws Exception {
        String encrypted = encryptToFile("Hello world","pub.asc","enc.asc");
        System.out.println("\nencrypted data = '" + new String(encrypted) + "'");

        String decrypted = decryptFromFile("open sesame", "secret.asc", "enc.asc");
        System.out.println("\ndecrypted data = '" + decrypted + "'");

    }
}
浸婚纱 2024-10-04 17:11:49

这篇文章可能很旧,但这个答案可能对其他人有用。如果您只想加密和解密文本,请避免写入磁盘。你可以做这样的事情(来自原始帖子中的代码片段)...

    // the string you will like to encrypt
    byte[] original = "I love programming".getBytes(); 

    // KeyProvider.PUBLIC_KEY this is just a string holding your public key. you can have it stored in memory or something. 
    byte[] encrypted = encrypt(original, readPublicKey(new ByteArrayInputStream(KeyProvider.PUBLIC_KEY.getBytes())), null, true, true); 

    System.out.println(new String(encrypted)); // this will output your encrypted message

    //encryted here is the encrypted string in byte array you will like to decrypt and also the KeyProvider.PRIVATE_KEY is string holding your private key
    byte[] decrypted = decrypt(encrypted, new ByteArrayInputStream(KeyProvider.PRIVATE_KEY.getBytes()), "".toCharArray());


    System.out.println(new String(decrypted)); //output the decrypted message

希望这有帮助

This post may be old but this answer may be useful to someone else. To avoid writing to disk, if all you want to do is encrypt and decrypt text. You can do something like this (from the code snippet in the original post)...

    // the string you will like to encrypt
    byte[] original = "I love programming".getBytes(); 

    // KeyProvider.PUBLIC_KEY this is just a string holding your public key. you can have it stored in memory or something. 
    byte[] encrypted = encrypt(original, readPublicKey(new ByteArrayInputStream(KeyProvider.PUBLIC_KEY.getBytes())), null, true, true); 

    System.out.println(new String(encrypted)); // this will output your encrypted message

    //encryted here is the encrypted string in byte array you will like to decrypt and also the KeyProvider.PRIVATE_KEY is string holding your private key
    byte[] decrypted = decrypt(encrypted, new ByteArrayInputStream(KeyProvider.PRIVATE_KEY.getBytes()), "".toCharArray());


    System.out.println(new String(decrypted)); //output the decrypted message

Hope this helps

并安 2024-10-04 17:11:49

这是我的解决方案。在整个压缩和加密过程中不会创建任何文件。

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
import java.util.Iterator;

public class PgpHelper {

    public static byte[] encrypt(String fileName, String content, String pgpPublicKey) throws IOException, PGPException, NoSuchProviderException {
        Security.addProvider(new BouncyCastleProvider());

        ByteArrayOutputStream zipOut = new ByteArrayOutputStream();
        PGPCompressedDataGenerator zipData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
        OutputStream zipPacket = new PGPLiteralDataGenerator()
            .open(zipData.open(zipOut), PGPLiteralData.BINARY, fileName, content.length(), new Date());
        zipPacket.write(content.getBytes(StandardCharsets.UTF_8));
        zipPacket.close();
        zipData.close();
        byte[] zipBytes = zipOut.toByteArray();
        zipOut.close();

        PGPEncryptedDataGenerator encryptor = new PGPEncryptedDataGenerator(
            PGPEncryptedData.CAST5, true, new SecureRandom(), "BC");
        InputStream keyIn = new ByteArrayInputStream(pgpPublicKey.getBytes());
        encryptor.addMethod(readPublicKey(keyIn));
        keyIn.close();

        ByteArrayOutputStream encryptOut = new ByteArrayOutputStream();
        OutputStream encryptPacket = encryptor.open(encryptOut, zipBytes.length);
        encryptPacket.write(zipBytes);
        encryptPacket.close();
        byte[] encryptBytes = encryptOut.toByteArray();
        encryptOut.close();
        return encryptBytes;
    }

    @SuppressWarnings("unchecked")
    private static PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {
        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in));
        Iterator<PGPPublicKeyRing> itKeyRings = pgpPub.getKeyRings();
        while (itKeyRings.hasNext()) {
            PGPPublicKeyRing keyRing = itKeyRings.next();
            Iterator<PGPPublicKey> itKeys = keyRing.getPublicKeys();
            while (itKeys.hasNext()) {
                PGPPublicKey key = itKeys.next();
                if (key.isEncryptionKey()) {
                    return key;
                }
            }
        }
        throw new IllegalArgumentException("Can't find encryption key in key ring.");
    }
}

Here is my solution. No file is created throughout the compress and encryption processes.

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
import java.util.Iterator;

public class PgpHelper {

    public static byte[] encrypt(String fileName, String content, String pgpPublicKey) throws IOException, PGPException, NoSuchProviderException {
        Security.addProvider(new BouncyCastleProvider());

        ByteArrayOutputStream zipOut = new ByteArrayOutputStream();
        PGPCompressedDataGenerator zipData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
        OutputStream zipPacket = new PGPLiteralDataGenerator()
            .open(zipData.open(zipOut), PGPLiteralData.BINARY, fileName, content.length(), new Date());
        zipPacket.write(content.getBytes(StandardCharsets.UTF_8));
        zipPacket.close();
        zipData.close();
        byte[] zipBytes = zipOut.toByteArray();
        zipOut.close();

        PGPEncryptedDataGenerator encryptor = new PGPEncryptedDataGenerator(
            PGPEncryptedData.CAST5, true, new SecureRandom(), "BC");
        InputStream keyIn = new ByteArrayInputStream(pgpPublicKey.getBytes());
        encryptor.addMethod(readPublicKey(keyIn));
        keyIn.close();

        ByteArrayOutputStream encryptOut = new ByteArrayOutputStream();
        OutputStream encryptPacket = encryptor.open(encryptOut, zipBytes.length);
        encryptPacket.write(zipBytes);
        encryptPacket.close();
        byte[] encryptBytes = encryptOut.toByteArray();
        encryptOut.close();
        return encryptBytes;
    }

    @SuppressWarnings("unchecked")
    private static PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {
        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in));
        Iterator<PGPPublicKeyRing> itKeyRings = pgpPub.getKeyRings();
        while (itKeyRings.hasNext()) {
            PGPPublicKeyRing keyRing = itKeyRings.next();
            Iterator<PGPPublicKey> itKeys = keyRing.getPublicKeys();
            while (itKeys.hasNext()) {
                PGPPublicKey key = itKeys.next();
                if (key.isEncryptionKey()) {
                    return key;
                }
            }
        }
        throw new IllegalArgumentException("Can't find encryption key in key ring.");
    }
}
夏九 2024-10-04 17:11:49

我也有完全相同的用例,我无法将未加密的数据存储在任何地方,并且我必须加密字节和输入流。所以我为它编写了一个实用程序:

随意浏览和使用您想要的任何代码块。希望有帮助!

这是 repo 链接

readme.md 包含有关如何使用它的说明

这里也是一篇完整的文章在它上面。

下面是 测试类,其中我有用于字节输入流PGP加密和解密的工作测试用例我认为输出流文件涵盖了每个用例。

@Test
public void testByteEncryption() throws IOException, PGPException {
    // Encrypting the test bytes
    byte[] encryptedBytes = pgpEncryptionUtil.encrypt(testString.getBytes(Charset.defaultCharset()),
            publicKey.openStream());
    // Decrypting the generated encrypted bytes
    byte[] decryptedBytes = pgpDecryptionUtil.decrypt(encryptedBytes);
    // Comparing the original test string with string generated using the decrypted bytes
    assertEquals(testString, new String(decryptedBytes, Charset.defaultCharset()));
}

@Test
public void testFileEncryption() throws IOException, URISyntaxException, PGPException {
    // Generating a pgp encrypted temp file from the test file
    File encryptedFile = tempFolder.newFile();
    File originalFile = new File(testFile.toURI());
    try (OutputStream fos = Files.newOutputStream(encryptedFile.toPath())) {
        pgpEncryptionUtil.encrypt(fos, Files.newInputStream(originalFile.toPath()), originalFile.length(),
                publicKey.openStream());
    }
    // Decrypting the generated pgp encrypted temp file and writing to another temp file
    File decryptedFile = tempFolder.newFile();
    pgpDecryptionUtil.decrypt(Files.newInputStream(encryptedFile.toPath()),
            Files.newOutputStream(decryptedFile.toPath()));
    // Comparing the original file contents with the decrypted file contents
    assertEquals(IOUtils.toString(Files.newInputStream(originalFile.toPath()), Charset.defaultCharset()),
            IOUtils.toString(Files.newInputStream(decryptedFile.toPath()), Charset.defaultCharset()));
}

@Test
public void testInputStreamEncryption() throws IOException, URISyntaxException, PGPException {
    // Generating a pgp encrypted input stream from the test file
    File originalFile = new File(testFile.toURI());
    InputStream encryptedIn = pgpEncryptionUtil.encrypt(Files.newInputStream(originalFile.toPath()),
            originalFile.length(), publicKey.openStream());
    // Decrypting the generated input stream and writing to a temp file
    File decryptedFile = tempFolder.newFile();
    pgpDecryptionUtil.decrypt(encryptedIn, Files.newOutputStream(decryptedFile.toPath()));
    // Comparing the original file contents with the decrypted file contents
    assertEquals(IOUtils.toString(Files.newInputStream(originalFile.toPath()), Charset.defaultCharset()),
            IOUtils.toString(Files.newInputStream(decryptedFile.toPath()), Charset.defaultCharset()));
}

I also had the exact same use case, where I could not store the unencrypted data anywhere and I had to encrypt both bytes and inputstream. So I wrote a utility for it:

Feel free to browse and use whatever chunk of code of code you want. Hope it helps !

Here is the repo link

The readme.md contains instructions on how to use it

Here is also a full fledged article on it.

Below is a snippet of the test class, where I have working test cases for the PGP encryption and decryption of bytes, inputstreams, outputstreams and files which I guess covers every use case.

@Test
public void testByteEncryption() throws IOException, PGPException {
    // Encrypting the test bytes
    byte[] encryptedBytes = pgpEncryptionUtil.encrypt(testString.getBytes(Charset.defaultCharset()),
            publicKey.openStream());
    // Decrypting the generated encrypted bytes
    byte[] decryptedBytes = pgpDecryptionUtil.decrypt(encryptedBytes);
    // Comparing the original test string with string generated using the decrypted bytes
    assertEquals(testString, new String(decryptedBytes, Charset.defaultCharset()));
}

@Test
public void testFileEncryption() throws IOException, URISyntaxException, PGPException {
    // Generating a pgp encrypted temp file from the test file
    File encryptedFile = tempFolder.newFile();
    File originalFile = new File(testFile.toURI());
    try (OutputStream fos = Files.newOutputStream(encryptedFile.toPath())) {
        pgpEncryptionUtil.encrypt(fos, Files.newInputStream(originalFile.toPath()), originalFile.length(),
                publicKey.openStream());
    }
    // Decrypting the generated pgp encrypted temp file and writing to another temp file
    File decryptedFile = tempFolder.newFile();
    pgpDecryptionUtil.decrypt(Files.newInputStream(encryptedFile.toPath()),
            Files.newOutputStream(decryptedFile.toPath()));
    // Comparing the original file contents with the decrypted file contents
    assertEquals(IOUtils.toString(Files.newInputStream(originalFile.toPath()), Charset.defaultCharset()),
            IOUtils.toString(Files.newInputStream(decryptedFile.toPath()), Charset.defaultCharset()));
}

@Test
public void testInputStreamEncryption() throws IOException, URISyntaxException, PGPException {
    // Generating a pgp encrypted input stream from the test file
    File originalFile = new File(testFile.toURI());
    InputStream encryptedIn = pgpEncryptionUtil.encrypt(Files.newInputStream(originalFile.toPath()),
            originalFile.length(), publicKey.openStream());
    // Decrypting the generated input stream and writing to a temp file
    File decryptedFile = tempFolder.newFile();
    pgpDecryptionUtil.decrypt(encryptedIn, Files.newOutputStream(decryptedFile.toPath()));
    // Comparing the original file contents with the decrypted file contents
    assertEquals(IOUtils.toString(Files.newInputStream(originalFile.toPath()), Charset.defaultCharset()),
            IOUtils.toString(Files.newInputStream(decryptedFile.toPath()), Charset.defaultCharset()));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文