javaencryptioninputstreamjncryptor

How to encrypt an InputStream with JNCryptor


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?


Solution

  • 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();
                ...
            }
        }
    }