Tom Wayne
Tom Wayne

Reputation: 53

Android AES Encryption Missing Bytes after Cipher.doFinal

I'm trying to encrypt an inputstream from glide.

I converted the inputstream into a byte array and pass it in my encrypt methode:

fun encrypt(input: ByteArray): ByteArray {

    Log.e("TAG", "inputsize: ${input.size}")

    val iv           = ByteArray(KeyStoreHelper.IV_SIZE)
    val secureRandom = SecureRandom()
    secureRandom.nextBytes(iv)

    val c = Cipher.getInstance(KeyStoreHelper.AES_MODE)
    c.init(Cipher.ENCRYPT_MODE, getKey(), GCMParameterSpec(KeyStoreHelper.GCM_SIZE, iv))
    Log.e("TAG", "outputsize: ${c.getOutputSize(input.size)}")
    val encodedBytes = c.doFinal(input)

    Log.e("TAG", "encodedBytesSize: ${encodedBytes.size}")

    val byteBuffer = ByteBuffer.allocate( iv.size + encodedBytes.size)
    byteBuffer.put(iv)
    byteBuffer.put(encodedBytes)

    Log.e("TAG", "byteBuffer: ${byteBuffer.array().size}")


    return byteBuffer.array()
}

The logs look like this:

inputsize: 750683 
outputsize: 750699 
encodedBytesSize: 95339 
byteBuffer: 95351

As you can see, the encrypted image byte array is way to small and I dont get why - If i try to encrypt strings or smaller images (about 100kb-200kb) it works like a charm.

Thanks for helping me out!

Kind regards Tom

Upvotes: 4

Views: 302

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93998

It seems you've run into a bug, weirdly enough at an illogical location: 95339 is a prime number. You'd almost think that some developer left in that value by purpose, in case he forgot or to test the test team.

However, it is not a good idea to cache all data in memory for such large swaths of information, even for GCM. You should try and use streaming instead. You can use the CipherOutputStream to perform encryption and CipherInputStream for decryption. You can connect these streams to other streams such as FileOutputStream and FileInputStream to directly read / write to the filesystem. It is also possible to write the IV to these underlying streams.

Beware that there may be big differences in how GCM is handled by different providers. As you've noticed, the one associated with the Android key store was build for security - of the key anyway - rather than speed. Other implementations of GCM may not show this bug. Beware that the available providers may differ between different Java(-esk) platforms and versions of these platforms.

Upvotes: 2

Related Questions