How to encrypt a string/stream with bouncycastle pgp without starting with a file How to encrypt a string/stream with bouncycastle pgp without starting with a file java java

How to encrypt a string/stream with bouncycastle pgp without starting with a file


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


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


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