Bouncy Castle – Encrypt a stream

I should be forgiven for thinking that encrypting a stream of data instead of a disk file is more difficult than it is supposed to be. Actually when somebody like me who has no experience with writing secure code uses encryption/decryption libraries like Bouncy Castle, it is always hard. So even after the PCI auditor has paid us a visit many times I can still point out many loopholes in our security code like the AES key that is hard-coded. Split key technology is really hard to grok. So I have not attempted it yet. So the AES key is still inside the java class.

This example uses Bouncy Castle to decrypt a file using a GPG key and encrypt it again using another key on the fly. Some parts of the code that are supposed to be obvious are not shown but as I mentioned secure code is hard to write. The missing piece can be reconstructed from the Bouncy Castle examples.

I am planning to fix the code formatting in the blog soon.

Decrypt a file and return a stream

public InputStream decryptToStream( String file ) throws KeyNotFoundException{

PGPEncryptedDataList enc = null;

PGPObjectFactory objectFactory = null;

InputStream in = null;

try {

objectFactory = new PGPObjectFactory( new FileInputStream( file ) );

Object o = objectFactory.nextObject();

// What is a PGP marker packet ?

if ( o instanceof PGPEncryptedDataList ) {

enc = ( PGPEncryptedDataList ) o;

} else {

enc = ( PGPEncryptedDataList ) objectFactory.nextObject();

}

Iterator it = enc.getEncryptedDataObjects();

PGPPublicKeyEncryptedData pbe = null;

while ( it.hasNext()){

pbe = (PGPPublicKeyEncryptedData)it.next();

}

InputStream clear = pbe.getDataStream( getPGPSecretKey( pbe.getKeyID() ), "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) {

PGPLiteralData literal = (PGPLiteralData) message;

in = literal.getInputStream();

}
} catch (FileNotFoundException e) {

} catch (IOException e) {

} catch (NoSuchProviderException e) {

} catch (PGPException e) {

}
return in;
}

Encrypt the stream and write to a file

It should be possible to return a stream from this method instead of writing it to a file.

public void encrypt( PGPPublicKey key,
                               String compressedfile,
                               String encryptedfile,
                               InputStream in ) throws IOException,
PGPException,
NoSuchProviderException {
byte[] buf = new byte[ 1024 ],
literalBuffer = new byte[ 1024 ],
encryption = new byte[ 1024 ];

ByteArrayOutputStream o = null;

OutputStream out = null;

FileOutputStream fos = new FileOutputStream( new File( encryptedfile ));

PGPCompressedDataGenerator compressedData = new PGPCompressedDataGenerator(
PGPCompressedDataGenerator.ZIP);
PGPLiteralDataGenerator lg =
new PGPLiteralDataGenerator();

try {

PGPEncryptedDataGenerator data =
new PGPEncryptedDataGenerator( PGPEncryptedData.CAST5,
true,
new SecureRandom(),
"BC");

data.addMethod( key );
int bytes = 0;

OutputStream writeToEncrypt = data.open( fos,
encryption );

OutputStream lgo = lg.open( compressedData.open( writeToEncrypt ),
PGPLiteralData.BINARY,
compressedfile,
new Date(),
literalBuffer
);

while ((bytes = in.read( buf )) >= 0) {
//As it is written it is encrypted.

lgo.write( buf, 0 , bytes );

}

lg.close();
compressedData.close();
writeToEncrypt.close();
lgo.close();

} catch (IOException e) {

} catch (NoSuchProviderException e) {

} catch (PGPException e) {

}
}

add to del.icio.us : Add to Blinkslist : add to furl : Digg it : add to ma.gnolia : Stumble It! : add to simpy : seed the vine : : : TailRank : post to facebook

Leave a comment