CipherInputStream to the rescue: Saving memory usage when encrypting huge binary payloads

Hi, There:

If you are one of those lucky ones in the northeast like me, I hope your arms are not so sore after shoveling the snow! Normally I enjoy using my jumbo snow blower for any snow that’s larger than 4 inches. But it decided to quit with busted sheer bolts this time! Before it is fixed, my arm and back will step in for the job!

Anyway, at work we need to encrypt huge binary payload due to the nature of the data. I found that simply using Cipher to encrypt large payload, it often busts the Heap Size when the payload is a couple of hundreds of MB, depend on the JVM and the encrypting parameters, of course. But this limit is not desirable for us where we need sometimes 1 GB of data to be encrypted, in a timely way.

At this point, JDK 8 already has Streaming Encryption implemented for us! How nice!  The class is CipherInputStream. Here is the demo code excerpt that will encrypt byte[] mydata through the Streaming process and save the cipher into a file. The time to encrypt is almost linear to the size of byte[] mydata, indicating a nice Streaming process. Most importantly, no more Memory issues with heap size busting!

byte[] salt = new byte[8];
// random SALT

new Random().nextBytes(salt); 

// random Initial Vector IV when cipher init
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 1000); 

PBEKeySpec pbeKeySpec = new PBEKeySpec(“funkypassword”.toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance(“PBEWithHmacSHA256AndAES_256”);
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

// Create PBE Cipher
Cipher pbeCipher = Cipher.getInstance(“PBEWithHmacSHA256AndAES_256”);
// Initialize PBE Cipher with key and parameters
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

AlgorithmParameters algParams = pbeCipher.getParameters();
byte[] encodedAlgParams = algParams.getEncoded();

byte[] mydata = “make believe large payload secrete data here”.getBytes();
FileOutputStream fos = null;
CipherInputStream cis = null;

fos = new FileOutputStream(new File(“C:/temp/secrete.cipher”));
fos.write(encodedAlgParams);
cis = new CipherInputStream(new ByteArrayInputStream(mydata), pbeCipher);

byte[] b = new byte[1024];
int i = cis.read(b);
while (i != -1) {
fos.write(b, 0, i);
i = cis.read(b);
}

cis.close();
fos.close();

 

I am not posing the codes here. But if you want to decrypt huge binary payload, just use the CipherOutputStream in a similar way. It works just as nicely as CipherInputStream.

Cheers, and if we can’t help it, let it snow – let it snow !!

-Tony

Advertisements