2

i am having issues with java security. i have a bunch of bytes, and i want to split them into chunks of N bytes, encrypt them, and send them in separate (independant) messages.

here is my basic crypto stuff:

private byte[] generateIv(int size) {
    byte[] iv = new byte[size];
    randomSecureRandom.nextBytes(iv);
    return iv;
}

@Override
public byte[] encryptData(byte[] iv, byte[] in, Key key) throws CryptoException {
    try {
        Cipher c = Cipher.getInstance("AES/CTR/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        return c.doFinal(in);
    } catch (Exception ex) {
        throw new CryptoException(ex);
    }
}

@Override
public byte[] decryptData(byte[] iv, byte[] in, Key key) throws CryptoException {
    try {
        Cipher c = Cipher.getInstance("AES/CTR/PKCS5Padding");
        c.init(Cipher.DECRYPT_MODE,key, new IvParameterSpec(iv));
        return c.doFinal(in);
    } catch(Exception ex) {
        throw new CryptoException(ex);
    }
}

@Override
public byte[] createHMAC(byte[] pauload, Key sigKey) throws CryptoException {
    try {
        Mac mac = Mac.getInstance("HMACSHA256");  
        mac.init(sigKey);
        byte[] digest = mac.doFinal(pauload);
        return digest;
    } catch (Exception e) {
        throw new CryptoException("unable to create HMAC",e);
    }
}

i create the message like this (an AES-128 session key is generated in an initial handshake):

byte[] iv = generateIv();
byte[] hmac = createHMAC (inputBytes,key);
byte[] enc = encryptData(iv,inputBytes,key);

then i write in the message:

[iv bytes][enc bytes][hmac bytes]

on the opposite side, i do:

byte[] iv = readFirstEightBytes(inputBytes);
byte[] dec = decryptData(iv,inputBytes[8..N+8],key);
byte[] hmac = createHMAC(dec,inputBytes[N+9..end],key);
// compare hmac
return dec;

this works all nice and fluffy, except when i start to hammer it, it kind of tends to be really, really, slow. and my hotspots are:

encryptData     27%
createHMAC      22%
decryptData     18%

i was wondering if i'm being naive here? am i missing something obvious? i was wondering if i should maybe not get a fresh Cipher instance every time ... but i got a lot of concurrency, i am guessing that trying to make sharing an instance threadsafe is probably also not ideal ...

i see lots of room for improvement in the rest of my code, so this would make the encryption part look even worse.

who's got thoughts? or is 20 mb/s total throughput as good as it gets (on a modern, beefy laptop)?

rmalchow
  • 2,689
  • 18
  • 31
  • 2
    You might want to bring this to http://www.codereview.stackexchange.com/. – Andrew Cheong Feb 12 '16 at 07:49
  • 20 mb/s is not that good compared to [this quite old question](http://stackoverflow.com/questions/3045520/aes-acceleration-for-java). The OP has 90 mb/s throughput. Which cryptoprovider do you use? – Frank Feb 12 '16 at 08:08
  • Note: mb/s is mili bits per second, MB/s is mega bytes per second. – zaph Feb 12 '16 at 12:53
  • Just for comparison a current iPhone or MacBookPro encrypts at a rate of 400+ MB/s for AES. – zaph Feb 12 '16 at 13:12
  • @zaph my guess is hardware support? for clarification: i think the rest of my code is still improvable. this makes the fact that ~70% of the time is spent in the de/encryption code even worse. – rmalchow Feb 12 '16 at 13:32
  • @frank i am using the default one. no parameters in Cipher.getInstance(). i looked into that, and i was wondering if it would be worth trying a different one. i'll try bouncy castle first & let you know – rmalchow Feb 12 '16 at 13:32
  • @rmalchow Yes, there is HW support. Most newer Intel chips have hardware encryption support as do iOS devices and newer Android devices. Given the speeds you are obtaining (20 MB/s) you are getting some HW support, I see SW encryption to be 500+ times slower than HW backed encryption. – zaph Feb 12 '16 at 13:41
  • @rmalchow You could look into NSS respective JSS as a cryptoprovider that supports hardware acceleration. – Frank Feb 12 '16 at 13:54
  • @zaph yes ... given the right terminology, i looked into AES Intrinsics. i am using oracle jdk 1.8 on macos. according to the docs, it has built-in support on intel platforms (this applies). the flags are: -XX:+UseAES -XX:+UseAESIntrinsics ... however, i hardly see any difference between on and off ... – rmalchow Feb 12 '16 at 14:53
  • also, clarifying, this is in both directions, but both sides are running on localhost ... – rmalchow Feb 12 '16 at 15:18

0 Answers0