I am implementing the AES encryption algorithm in GCM operating mode in an android application.
My IDE (Intellij Idea) tells me that to use javax.crypto.spec.GCMParameterSpec the condition android.os.Build.VERSION.SDK_INT> = android.os.Build.VERSION_CODES.KITKAT is required.
I tried when the condition is not verified to use a javax.crypto.spec.GCMParameterSpec of which I downloaded the source file and included it in my project, but with it the encryption operations do not work correctly (the decrypted data does not match to original data or java.security.InvalidAlgorithmParameterException: IV must be specified in GCM mode).
Do you have any ideas to suggest on how I can also support previous versions of Android KITKAT?
Thanks in advance.
Initial versions of Android based on Java 6 did not give you GCMParameterSpec, but they would use IvParameterSpec instead. Besides the (usually 12 byte) IV, the GCMParameterSpec will give you two additional operations: the support for additional data and the tag size.
Now the tag size is not too much of a problem: first of all, usually the full 128 bits / 16 bytes are used. Furthermore you can just remove those bytes from the end of the ciphertext until you reach the required tag size, e.g. remove 4 bytes / 32 bits to get a tag size of 96 bits.
The additional data is a problem, as far as I know there is no way to specify those, at least not if you require a Cipher instance. You could of course use GCMBlockCipher instead, but then you'd not use Cipher and any possible acceleration provided by the platform (as Bouncy is software only).
And yes, as indicated, it is perfectly possible to implement GCM mode yourself for Android, as you don't need to sign any providers. Of course, you'd have to use a different GCMParameterSpec implementation, and it would be a good idea only to use the provider for the older platform, so some runtime switching seems to be required.
Related
According to documentation for app developers AES_128 and AES_256 are supported from api 26. https://developer.android.com/reference/javax/crypto/Cipher. For example now I'm using AES(GCM mode) with 128 bit key. What is the difference between AES with 128 bit key and AES_128 ?
There is no difference between AES with a 128-bit key and AES_128.
As you can see in the docs you linked, previous to API 26 there existed one primitive for AES, with various padding options/modes of operation.
To make things simpler, in API 26+ there is now two primitives to disambiguate the usage of AES with either a definitive 128-bit or 256-bit key.
If you are using AES, you should opt for AES-256 GCM as it provides a authenticated encryption, ensuring that the ciphertext cannot be tampered with, without the recipients knowledge.
AES-GCM operates with a 32-bit counter, so unfortunately with the same key, nonce (IV) pair you can only safely encrypt ~ 64GB of data (2^39-256 bits).
If you want to move to an even safer cipher, I recommend XSalsa20 or XChaCha20, which provide a 192-bit nonce size, effectively allowing a practically "unlimited" amount of data to be encrypted with the same key, nonce pair.
AES_128 doesn't exists. However, constants in Java don't generally use the hyphen (-) character, so the underscore is used to indicate AES-128 (still a strange choice for a String if you ask me).
AES-128 is just AES configured to use a 128 bit key. Internally it uses a specific sub-key derivation and 10 rounds. AES-256 has a different sub-key derivation and uses 14 rounds. AES-192 (12 rounds) isn't used much, as it has an awkward key size and it doesn't fully protect against attacks that may be applicable to AES-128.
Practically speaking there may be two differences when it comes to general usage. First of all, the API may be able to select an implementation of 128 or 256 bits of AES before the init methods are called. Secondly, I presume that the init method only accepts 128 bit keys when you configure AES-128.
We are having an android app which a decrypting and encrypting large (up to 100MB) files over HTTP-Streams.
Therefore, we are using CipherInputStreams and CipherOutputStreams which works fine for AES/CBC/PKCS7Padding. We recently switched to AES/GCM/NoPadding. Now the encryption and decryption is inacceptable slow for files over roughly 50MB.
Debugging into the android source code, reveals the issues: https://android.googlesource.com/platform/libcore/+/master/ojluni/src/main/java/javax/crypto/CipherInputStream.java#112
This method has byte buffer "oBuffer" which is reallocated and increased by 512bits until it can hold the whole message (see line: https://android.googlesource.com/platform/libcore/+/master/ojluni/src/main/java/javax/crypto/CipherInputStream.java#121)
I am aware of the note over this method which stated that in AEAD ciphers the whole message has to be buffered. This is one issue, because we cannot hold the whole message into a memory buffer. Another issue is that the oBuffer is constantly reallocated.
Is there any solution for using GCM with a streaming API?
Splitting the file into the parts and chaining is a solution for you.
Assume that you divide the file into n parts. Encrypt each of them with AES-GCM with the following additions. Prefix each part before encryption as follows;
tag_0 = ''
for i from 1 to n
ciphertextBlock_i, tag_i = AES-GCM( i:n || tag_i-1 || plaintextBlock_i)
prefix each part with the part number as i:n
prefix each part except the first one with the authentication tag of the previous part.
With these, you have now a chain that can be controlled after decryption. You can detect, additions, deletions. The order is under your control, you can send even without the order. However, you need to check the prefix.
You can also
add the part size, and
add the time of encryption, too if you fear from the replay attack.
Situation:
String is getting encrypted in Java environment (javax.crypto.Cipher/PBEWithMD5AndDES), base64 encoded
String is transfered to Android
Same crypto decoder is used, only different base64 library
=> we could not decrypt, getting
java.lang.SecurityException: Could not decrypt: pad block corrupted
During analysis we compared byte arrays, passed to the decode() method, in order to skip all possible base64 issues, and the arrays are identical.
Again, two identical byte arrays, passed to the same java module, produce different results (ok on java, exception on android).
Parameters, passed to Cipher module are hard-coded and identical on both platforms.
Where is the difference
We have finally found the difference between Java and Android code. It turned out Cipher component is just a container and does not implement anything by itself. The particular algorithm implementation is done by a provider and each platform has different list of providers configured. In our case if was some Sun implementation for Java and Bouncy Castle for Android. So it turned out that wir accidentaly used the encryption algorithm which implementation was different for different providers
I am using a 128-bit AES cipher algorithm. But the program takes a long time, since the files to encrypt are big.
I was wondering if there is a more light cipher algorithm to use in Android. I can't find a list of supported ciphers in Android.
Have you tried to use shorter keys with AES instead? You can try OpenSSL build as native code, but I guess dalvik already uses optimized libraries, I don't think it will help. There are good reasons AES takes some time, by choosing something faster, you will have to lower real security.
I suggest you should not encrypt whole file if you need speed. Instead, encrypt only header or parts of file, without which rest of file is not useful. However it depends on what data you are encrypting and will not work for generic data files.
I am writing an Android application that would both store data and communicate with a server using protocol buffers. However, the stock implementation of protocol buffers compiled with the LITE flag (in both the JAR library and the generated .java files) has an overhead of ~30 KB, where the program itself is only ~30 KB. In other words, protocol buffers doubled the program size.
Searching online, I found a reference to an Android specific implementation. Unfortunately, there seems to be no documentation for it, and the code generated from the standard .proto file is incompatible with it. Has anyone used it? How do I generate code from a .proto file for this implementation? Are there any other lightweight alternatives?
I know it's not a direct answer to your question, but an extra 30kb doesn't sound that bad to me. Even on EDGE that'll only take an extra 1 to 2 seconds to download. And memory is tight on android, but not THAT tight -- 30 kb is only about 1/10th of one percent of the available application memory space.
Are there any other lightweight alternatives?
I'm taking this to mean "to using protocol buffers", rather than "for using protocol buffers with an Android application". I apologise if you are already commited to protocol buffers.
This site is about "comparing serialization performance and other aspects of serialization libraries on the JVM". You'll find many alternatives listed there.
While there is no mention of the memory footprint of the different implementations at the moment I am sure it is a metric which the people on the wiki would be interested in.
Just to revive this archaic thread for anyone seeing it, the answer is to use Square's Wire library (https://github.com/square/wire)
As they mention themselves:
Wire messages declare public final fields instead of the usual getter methods. This cuts down on both code generated and code executed. Less code is particularly beneficial for Android programs.
They also internally build using the Lite runtime I believe.
And of course Proguard, the new Android 2.0 minify tools, [other generic answers], etc etc.
Use ProGuard[1] on your project. It will reduce the size of jars included in APK file.
[1] http://developer.android.com/guide/developing/tools/proguard.html