Monday, January 2, 2012

Java: Implementing PGP Single Pass Sign and Encrypt using League of Bouncy Castle library

The League of Bouncy Castle Cryptography library is chock-full of goodies but it is hard to convert what is in there to more practical examples.
The example files are a solid basis but I seam to need to fiddle quite a bit until it something is usable for me. The PGP Single Pass Sign and Encrypt process is one of these things that took me for a long time to figure out. I owe much of the actual solution impementation to John Opincar who solved this puzzle for C#.
Here is my implementation for Java:


  * This is the primary function that will create encrypt a file and sign it

  * with a one pass signature. This leans on an C# example by John Opincar

  * @author Bilal Soylu

  * @param targetFileName

  *            -- file name on drive systems that will contain encrypted content

  * @param embeddedFileName

  *            -- the original file name before encryption

  * @param secretKeyRingInputStream

  *            -- Private Key Ring File

  * @param targetFileStream

  *            -- The stream for the encrypted target file

  * @param secretKeyPassphrase

  *            -- The private key password for the key retrieved from

  *            collection used for signing

  * @param signPublicKeyInputStream

  *            -- the public key of the target recipient to be used to

  *            encrypt the file

  * @throws Exception


 public void fEncryptOnePassSignatureLocal(String targetFileName,

   String embeddedFileName, InputStream secretKeyRingInputStream,

    OutputStream targetFileStream, String secretKeyPassphrase,   

   InputStream signPublicKeyInputStream, InputStream contentStream) throws Exception {

  // ** INIT

  // read public Key from stream (file, if keyring we use the first working key)

  PGPPublicKey encKey = readPublicKey(signPublicKeyInputStream);

  // need to convert the password to a character array

  char[] password = secretKeyPassphrase.toCharArray();

  int BUFFER_SIZE = 1 << 16; // should always be power of 2(one shifted bitwise 16 places)

  //for now we will always do integrity checks and armor file

  boolean armor = true;

  boolean withIntegretyCheck = true;

  //set default provider, we will pass this along

  BouncyCastleProvider bcProvider = new BouncyCastleProvider();

  // armor stream if set

  if (armor)

   targetFileStream = new ArmoredOutputStream(targetFileStream);

  // Init encrypted data generator

  PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(

    SymmetricKeyAlgorithmTags.CAST5, withIntegretyCheck,

    new SecureRandom(), bcProvider);


  OutputStream encryptedOut =,new byte[BUFFER_SIZE]);

  // start compression

  PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(


  OutputStream compressedOut =;

  //start signature

  //PGPSecretKeyRingCollection pgpSecBundle = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(secretKeyRingInputStream));

  //PGPSecretKey pgpSecKey = pgpSecBundle.getSecretKey(keyId);

  PGPSecretKey pgpSecKey = readSecretKey(secretKeyRingInputStream);

  if (pgpSecKey == null)

   throw new Exception("No secret key could be found in specified key ring collection.");

  PGPPrivateKey pgpPrivKey = pgpSecKey.extractPrivateKey(password,bcProvider);

  PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(


    HashAlgorithmTags.SHA1, bcProvider);


  signatureGenerator.initSign(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);

  // iterate to find first signature to use

  for (@SuppressWarnings("rawtypes")

  Iterator i = pgpSecKey.getPublicKey().getUserIDs(); i.hasNext();) {

   String userId = (String);

   PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();

   spGen.setSignerUserID(false, userId);


   // Just the first one!




  // Create the Literal Data generator output stream

  PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();

  // get file handle

  File actualFile = new File(targetFileName);

  // create output stream

  OutputStream literalOut =,

    PGPLiteralData.BINARY, embeddedFileName,

    new Date(actualFile.lastModified()), new byte[BUFFER_SIZE]);



  // read input file and write to target file using a buffer

  byte[] buf = new byte[BUFFER_SIZE];

  int len;

  while ((len =, 0, buf.length)) > 0) {

   literalOut.write(buf, 0, len);

   signatureGenerator.update(buf, 0, len);


  // close everything down we are done









  if (armor) targetFileStream.close();



  * Try to find a public key in the Key File or Key Ring File

  * We will use the first one for now.

  * @author Bilal Soylu

  * @param in -- File Stream to KeyRing or Key

  * @return first public key

  * @throws IOException

  * @throws PGPException


 private static PGPPublicKey readPublicKey(InputStream in)

   throws IOException, PGPException {

  in = PGPUtil.getDecoderStream(in);

  PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in);


  // we are only looking for the first key that matches



  // iterate through the key rings.


  Iterator rIt = pgpPub.getKeyRings();

  while (rIt.hasNext()) {

   PGPPublicKeyRing kRing = (PGPPublicKeyRing);

   Iterator kIt = kRing.getPublicKeys();

   while (kIt.hasNext()) {

    PGPPublicKey k = (PGPPublicKey);

    if (k.isEncryptionKey()) {

     return k;




  throw new IllegalArgumentException(

    "Can't find encryption key in key ring.");





  * Find first secret key in key ring or key file. 

  * A secret key contains a private key that can be accessed with a password.

  * @author Bilal Soylu

  * @param in -- input Key file or key ring file

  * @param passwd -- password for key

  * @return matching private key

  * @throws IOException

  * @throws PGPException

  * @throws NoSuchProviderException


 private static PGPSecretKey readSecretKey(InputStream in)

   throws IOException, PGPException, NoSuchProviderException {


  PGPSecretKey               sKey = null;

  try {

   in = PGPUtil.getDecoderStream(in);

   PGPSecretKeyRingCollection pgpPriv = new PGPSecretKeyRingCollection(in);


   // we just loop through the collection till we find a key suitable for

   // decrypt

   Iterator  it = pgpPriv.getKeyRings();       

   PGPSecretKeyRing   pbr = null;


         while (sKey == null && it.hasNext())


          Object readData =;

          if (readData instanceof PGPSecretKeyRing) {           

           pbr = (PGPSecretKeyRing)readData;             

              sKey =  pbr.getSecretKey();




         if (sKey == null)


             throw new IllegalArgumentException("secret key for message not found.");



        catch (PGPException e)



            if (e.getUnderlyingException() != null)





        return sKey; 



1 comment:

Mauricio Sanaphre said...

Really useful!! This is what I was looking for, you just saved my day and code works very smooth, thanks!!