How to encrypt an InputStream with JNCryptor

2k views Asked by At

I'm developing an iPad app and using RNCryptor for the encryption and decryption on the device. There is a Java version of this encryption format available in the form of JNCryptor.

I now have data to be read from an InputStream, but I want to encrypt the data before it is read. I found a class called CipherInputStream, which seems to do exactly what I'm looking for. Only thing is, I need a Cipher (and Provider) to specify the encryption method, and I don't know how to do that. Is it even possible to define a custom Provider?

Does anyone have suggestions on alternative ways to use JNCryptor for the encryption of an InputStream?

3

There are 3 answers

0
Johanneke On BEST ANSWER

In the end I ended up writing a class to read the InputStream, encrypt the data parts at a time, and write to a PipedOutputStream. This PipedOutputStream I then connected to a PipedInputStream, which I eventually returned. The encryption and writing to the PipedOutputStream happens on a separate thread to avoid deadlock.

PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream(pin);
EncryptionPipe pipe = new EncryptionPipe(5, pout, in, cipher, mac, metaData);
//EncryptionPipe(int interval, OutputStream out, InputStream in
//              ,Cipher cipher, Mac mac, byte[] metaData)
pipe.start();
return pin;

And in EncryptionPipe:

public class EncryptionPipe extends Thread {
    ...
    @Override
    public void run() {
        try {
            mac.update(metaData);
            out.write(metaData);

            byte[] buf = new byte[1024];
            int bytesRead = 0;
            byte[] crypted;
            byte[] hmac;
            while ((bytesRead = in.read(buf)) != -1) {
                if (bytesRead < buf.length) {
                    //the doFinal methods add padding if necessary, important detail!
                    crypted = cipher.doFinal(buf, 0, bytesRead);
                    hmac = mac.doFinal(crypted);

                    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                    bytes.write(crypted);
                    bytes.write(hmac);
                    crypted = bytes.toByteArray();
                    bytesRead = crypted.length;
                    bytes.close();
                } else {
                    crypted = cipher.update(buf, 0, bytesRead);
                    mac.update(crypted, 0, bytesRead);
                }
                out.write(crypted, 0, bytesRead);
                synchronized (this) {
                    this.wait(interval);
                }
            }
            out.close();
            ...
        }
    }
}
0
Duncan Jones On

JNCryptor v1.1.0 was released yesterday and provides support for streaming encryption and decryption.

Use AES256JNCryptorInputStream to decrypt and AES256JNCryptorOutputStream to encrypt.

4
Zim-Zam O'Pootertoot On

You can use the default Java provider. To instantiate a cipher you would use

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")

This uses AES and Cipher Block Chaining mode. CBC only works on multiples of 16 bytes, so you're also specifying a way to pad your input to multiples of 16 bytes.

Here is some more sample AES code to get you started