I have been following the tutorial "How do I encrypt and decrypt files using DES?" to add a simple file encryption to an existing Android 4+ app.
Everything works fine, except that the encryption and decryption is very, very slow.
The following two methods are pretty much the complete tutorial:
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey desKey = skf.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES"); // DES/ECB/PKCS5Padding for SunJCE
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, desKey);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[64];
int numBytes;
// Why is this taking so long?
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
}
Quite simple and basic, but it takes about 20-30 seconds to de/encrypt a 1 MB file. In detail it is the while-loop that copies the bytes between the two streams which is so slow.
Changing the size of the byte[] to a bigger value like 65536 to read more bytes at once does not change anything. I thought reading more bytes at once would speed up the process but this is not the case.
Copying data between "normal" streams without encryption does not take so long. Is it really the encryption that is this expensive? I have been using similar encryptions on other plattforms and such delays have never been a problem.
The tutorial uses DES but changing the algorithm to something different, e.g. AES does not change anything either.
Any ideas how I can speed this up?
I ran some experiments on my Google LG Nexus 5 running Android 4.4.4 using basically your code and encrypting a file of 1000000 (one million) bytes, reading and writing to/from the /sdcard filesystem.
no crypt 1421 ms
AES ECB mode 2577 ms
DES ECB 3214
Next, I modified your code slightly to use BufferedInputStream and BufferedOutputStream
no crypt 88 ms
AES ECB mode 855 ms
DES ECB mode 1419 MS
This shows that the timings are sensitive to buffering, and that AES is faster than DES.
The provider name is 'AndroidOpenSSL'