Bouncy Castle – Encrypt a stream
July 28, 2010 Leave a comment
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) {
}
}











