Wednesday, January 25, 2012

Portable PGP: Encryption with Bouncy Castle

I came across the PPGP project Today and I thought about sharing it not only because it is a nice tool that runs in any OS (Java) which allows to encrypt/decrypt files and text using PGP, sign the result, generate keys but also because being Open Source Java Project the whole source code is available so you could use proven code that actually works to perform PGP operations in your own project.

Below is simple code almost entirely extracted from this project that just encrypts a file with a PGP public key.

package com.nestorurquiza.utils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
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.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;

/**
 * 
 * Code in part extracted from http://sourceforge.net/projects/ppgp/ 
 * A nice GUI to generate your own keys, encrypt and sign documents using PGP
 * 
 * @author nestor
 *
 */
public class PgpUtils {
    private final static int BUFFER_SIZE = 1 << 16;

    private static PGPPublicKey readPublicKeyFromCollection2(InputStream in) throws Exception {
        in = PGPUtil.getDecoderStream(in);
        PGPPublicKeyRing pkRing = null;
        PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(in);
        Iterator it = pkCol.getKeyRings();
        while (it.hasNext()) {
             pkRing = (PGPPublicKeyRing) it.next();
             Iterator pkIt = pkRing.getPublicKeys();
             while (pkIt.hasNext()) {
                     PGPPublicKey key = (PGPPublicKey) pkIt.next();
                     if (key.isEncryptionKey())
                             return key;
             }
        }
        return null;
    }
    

    /**
     * Encrypts a file using a public key
     * 
     * @param decryptedFilePath
     * @param encryptedFilePath
     * @param encKeyPath
     * @param armor
     * @param withIntegrityCheck
     * @throws Exception
     */
    public static void encryptFile(String decryptedFilePath,
            String encryptedFilePath,
            String encKeyPath,
            boolean armor,
            boolean withIntegrityCheck)            
            throws Exception{

        OutputStream out = new FileOutputStream(encryptedFilePath);
        FileInputStream pubKey = new FileInputStream(encKeyPath);
        PGPPublicKey encKey = readPublicKeyFromCollection2(pubKey);
        Security.addProvider(new BouncyCastleProvider());
        
        if (armor) 
            out = new ArmoredOutputStream(out);
            
        // Init encrypted data generator
        PGPEncryptedDataGenerator encryptedDataGenerator =
                new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(),"BC");
        
        encryptedDataGenerator.addMethod(encKey);
        
        
        OutputStream encryptedOut = encryptedDataGenerator.open(out, new byte[BUFFER_SIZE]);

        // Init compression  
        PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
        OutputStream compressedOut = compressedDataGenerator.open(encryptedOut);  

        PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();
        OutputStream literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY, decryptedFilePath, new Date(), new byte[BUFFER_SIZE]);
        FileInputStream inputFileStream = new FileInputStream(decryptedFilePath);
        byte[] buf = new byte[BUFFER_SIZE];  
        int len;
        while((len = inputFileStream.read(buf))>0){
            literalOut.write(buf,0,len);
        }
         
        literalOut.close();
        literalDataGenerator.close();
        
        compressedOut.close();
        compressedDataGenerator.close();
        encryptedOut.close();
        encryptedDataGenerator.close();
        inputFileStream.close();
        out.close();
        
    }
}

The Unit test showing how to use it:
package com.nestorurquiza.utils;

import java.io.IOException;

import org.junit.Test;
import org.xml.sax.SAXException;

public class PgpUtilsTest {
    @Ignore
    @Test    
    public void encryptTest() throws IOException, Exception, SAXException {
        String publicKeyFilePath = "/Users/nestor/Downloads/somePublicKey.pgp";
        String decryptedFilePath = "/Users/nestor/Downloads/someFile.csv";
        String encryptedFilePath = "/Users/nestor/Downloads/someFile.csv.enc";
        
        PgpUtils.encryptFile(decryptedFilePath, encryptedFilePath, publicKeyFilePath, false, true);
        
    }
}

No comments:

Followers