Android KeyStore provides a whole list of available ciphers, which leads me to the following question: Which combination would be Best Practice to use in 2019? Every combination seems to have its own set of drawbacks and as someone who is not a security expert, it is realy difficult to decide which one to use.
Some background information:
I am working on a Kotlin-based Android app which connects to an API. The user must provide a pair of username:password to authenticate to the API, which will then return a hexadecimal bearer token for future authentication. The connection to the API is already TLS-encrypted, so no need for additional encryption here.
The problem is storing the informations securely. The username as well as the password and bearer token have to be stored securely. A common solution to this problem seems to be to encrypt the credentials and store them via the Preferences API. As the encryption only happens inside the app and no key-exchange is needed, symmetric-key encryption looks like the way to go.
TL; DR: Prefer AES/GCM/NoPadding. Do not ever use AES/ECB/*.
In your situation, you'll want to prefer authenticated symmetric encryption, and the only option that provides this in the list you link is AES/GCM/NoPadding.
The benefit for you here is that, not only is your data encrypted, it is also safe from tampering - if someone or something modifies the stored data, you'll get an exception when you attempt to decrypt it. The other listed modes do not have this property. This means that the stored ciphertext could be modified and you wouldn't know - it may or may not still decrypt (I say may or may not as it can throw an exception in other circumstances, like bad padding after modification).
The drawback (and it isn't much of one) is that you must ensure you never use the same key and nonce together. If you do - and an attacker can access or view two different sets of ciphertext - it becomes trivial for them to break and decrypt. The easiest way around this is to simply always generate a random nonce. You'll be able to encrypt 2^96 times before you run into any issues!
If you can't or don't want to use AES/GCM/NoPadding for whatever reason, select from AES/CTR/NoPadding or AES/CBC/PKCS7Padding. Both have their own drawbacks. You'll need to find a way to prevent tampering yourself (HMACs are usually used). I tend to prefer AES/CTR/NoPadding as it is very similar (at least to use) to AES/GCM/NoPadding.
Lastly, do not use anything ECB related. ECB BAD.
Related
I am trying to create an Android app that encrypts data on-the-fly and write it to storage. Already implemented the app with no encryption, checked 100+ examples/posts of encryption on stackoverflow but couldn't decide which method to use.
At first thought of of using AES and did some googling to find how secure it is. Entering 16 or 32 character (better security, i hope) passwords every time doesn't seems convenient. As an alternative Asymmetric encryption came to mind. Encrypt with one key and decrypt with the other, so that i can leave the key used for encryption in the memory and use the other key only when data needs to be decrypted (like offline on a PC, or on another app).
Files that will be encrypted will be mostly images,video, audio recordings, office documents.
Does second method leaves any vulnerabilities? Between AES and RSA which one is better if i need to balance for speed and security. Data isn't anything top-secret, just need to prevent falling to wrong hands. The device is not encrypted, running KitKat. How well does both method stands against some kind of attack ?
EDIT: Describing two methods.
Method 1: Use password based AES encryption, manually enter 16/32 character password upon application start, clear the password after sometime/certain triggers from the memory. Enter password again when required.
Method 2: Use private/public key based RSA encryption. Leave one key, the one used for encryption on the device. Use the other key during decryption, which is scarcely performed.
This question is somewhat difficult to answer since you haven't actually described any methods, you've just named two encryption algorithms. If implemented properly, both algorithms are more than secure for your needs.
It is important to remember that RSA can encrypt data no longer than its key length (minus some for padding), so in most cases RSA alone is not enough.
If you are simply encrypting information on a single device and want the user in control of when it is encrypted and decrypted, e.g. with a password, you can use PBKDF2 to derive a key of x length (e.g. for AES256, 32 bytes) with a password string as input.
Don't bother using RSA if you aren't going to take advantage of its asymmetric properties. In most cases (but not all) RSA is redundant if no server or additional party is involved.
You don't describe your problem much, but if it was me, I'd use AES.
When using AES, please keep the following in mind:
Never use ECB mode.
Never use plain ASCII bytes as a key. You should use PBKDF2 or similar to derive a key, normally 100,000 rounds is good.
Always use a secure RNG to create your IV (if your cipher mode uses one, some, like CTR, use a nonce instead, but the concept is pretty much the same).
Always remember that AES does not ensure integrity. Use a MAC to detect changes in the ciphertext before decrypting.
I am working on an IM app that has a native Android and a native iOS implementation. One of the required features is being able to encrypt messages by entering an ordinary password string. These messages must then be decrypted by entering this password. I was also told to "use AES".
My plan, which I have tried with near-success, is to take the password string, salt it with some context info that I know will never change, and generate a fixed-length key using something like MD5. I know this isn't super secure.
To decrypt, I repeat above, and I get the same key. Then, I decrypt the data with that key, and get the original data back.
I got this to work on Android and iOS, but they cannot decrypt each other's data, which tells me there might be implementation differences that I can't see and that I can't change. The first 16 bytes of the AES128-encrypted data on both platforms are always the same, but after that, they are completely different. What can I check for?
To be ultra-clear, the user experience is to be identical to that of sharing a zip file with a password. The user enters the password, at any time, from any device, and BAM, they get the unencrypted data. Sharing keyfiles or any of that stuff is NOT part of this.
There is no need to use any salt (at least I don't see any reason for that)
AES is a standard - no matter what is implementation, results will be this same.
This same output for first 128 bits and different rest of data means that you are using different cipher modes AES is block cipher and you are probably using it with 128b block size on both platform, so first block is encrypted this same way and next ones are encrypted with different keys. Please read more about block cipher modes
I am making an Android application which involves two phones exchanging a lot of data over several minutes. I would like this communication to be encrypted and have been researching the various cryptographic options available. It seems like the most suited would be a hybrid algorithm, that uses asymmetric encryption (like RSA) to exchange a session key and a symmetric algo (like AES) to actually encrypt / decrypt the data.
From what I know of hybrid encryption, every packet sent between the two devices should use a new session key, which is embedded within the packet (encrypted with the other party's public key) to facilitate decryption at the other end.
To save CPU, I am considering using just one session key which is exchanged using RSA, and then encrypting / decrypting all data using this key, so that I can save on costly RSA operations. However, I understand that this is not recommended? Can someone please confirm this and tell me how I should proceed?
EDIT:
Thought I would add some more information here -
The communication protocol is completely custom and my own. Data is sent in unencrypted UDP packets, with a lot of metadata and an encrypted payload. So that rules out using regular SSL / TLS.
Also, for every session I generate new private and public keys, exchange the public keys and then use that to exchange a session key which is used in AES. I am using 2048-bit RSA and 256-bit AES. This, AFAIK, is more than enough and probably overkill for most communication. I will admit that my knowledge of cryptography isn't excellent, but I'm reading and learning as much as I can to make this as secure as possible.
Nothing 'wrong' with it, just a security tradeoff. The longer the keys, the longer the session can be. You're trying to keep the key long enough, or the session short enough, or a mixture, such that key compromise is infeasible in the time available. You also need to consider whether it's OK to leak the data for the entire session if a key gets cracked, or whether you need the extra security of a new key per message or whatever.
Why not use a l long live TLS/SSL session? This does pretty much exactly what you want, efficiently and doesn't require you to write tricky crypto code you will almost certainly get wrong.
In general, almost any crypto system I am aware of generates one symmetric key for the entire session and uses that for the duration. This is what TLS does and what SSH does. I believe this is what IPSEC does. There is no problem with this from a cryptographic point of view assuming you use a sane cipher like AES have sufficiently large IVs/Counters/Nonces such that they don't repeat.
The one worry about using this is that if your secret key leaks, you loose all the data in the session. However, if your secret key can leak, so too can your private key. At which point an attacker could decrypt previous session keys and get the data even if you followed the one key per packet mode.
I need to store sensitive data in a sqlite database in an android app.
How can I be sure this data is very safe?
I know I can encrypt the data using a key, but where do I store that key? I don't want to ask the user to fill in a key either, I just want it to work on it's own.
Because I am afraid of reverse engineering I don't want to put an encryption key in the code either.
I found out about SQLCipher. It says it's a very secure way of encrypting the data in the database, but why is it that way? Don't I also need to keep a key to unlock that information? Or is this really a perfect way of making sure the data is safe?
And if it isn't, what is an (almost) fail-proof way of storing sensitive data in an sqlite database?
You said...
I don't want to ask the user to fill in a key either, I just want it
to work on it's own. Because I am afraid of reverse engineering I
don't want to put an encryption key in the code either.
Unfortunately, you need to do one of these things (well, probably). You can ask the user for a password and then derive a key from that using an algorithm designed for that purpose (that's known as Password Based Encryption - PBE - and Android includes some good PBE algorithms standard). You could store the key in your code or as a resource within your APK, but then someone would be able to reverse engineer it. You can do so and obfuscate your code, which will slow down the reverse engineering process, but you cannot make it impossible (your code will need to determine the key at some point so it's just a matter of an attacker figuring out how it is doing it).
Other approaches that have been tried here include forcing your client to connect back to a server to retrieve the key over the network...but then what happens if network connectivity is interrupted and what prevents the server from giving the key out to anyone, like an attacker? Well, then you could use mutually-authenticated SSL to ensure only your client is allowed to get it...but then you need to store the client-side SSL private key...which is exactly the same problem you have now. :)
So...the bottom line is that you need a key (or something equivalent) to encrypt/decrypt the data. You can store it and make it harder for someone to reverse engineer it. You can inconvenience the user and make them type in a password. But...you need that secret knowledge somehow.
Symmetric cryptography requires a key to encrypt and the same key to decrypt. There is no way around it.
Do not store the key in the code because it can be decompiled (Like you've said).
Ask the user for a password on the first use and use PBKDF2 to derive a cryptographically secure key to use in the encryption.
Either the user has to enter the password or you need to store it in the memory. What I'd do is, ask the user to specify a duration where the key will be cached in the memory to use for decryption.
And if the duration is expired, the user WILL have to enter the password again.
I didn't check SQLCipher thoroughly but it says it uses AES-256. AES is a symmetric cryptographic algorithm and it needs a key to encrypt and the same key to decrypt.
Is it possible to let apps auto gen a random password? May be gen from place,time or others information this will no need to ask user's pass.
I have an Android application and within it some strings which I send through htpps. Is it possible to encrypt those hardcoded strings (such as for example passwords) in Android application to be unreadable from the apk file?
Regards,
So if I understand your question correctly, you want to store encrypted strings within the Android apk file (in strings.xml for example). If this is the case, yes, you can absolutely store encrypted strings wherever you please.
The kicker is that in order to decrypt these strings, you'll need a key. Wherever you end up storing the key becomes the weak link in this chain. If your app is reverse engineered and someone gets a hold of the key, your strings are no longer encrypted.
So to answer your question, no, it's not possible to do what want.
Check out What is the most appropriate way to store user settings in Android application and a whole bunch of other question. Basically you can obfuscate and encrypt to some extend but you will never be completely safe on a rooted device and against network sniffing attacks. That said though that applies everywhere.. find your best compromise between level of effort to implement and crack and the data you are protecting.
I think you should explain what do you want to do with this strings.
If you want just send password to server and make some kind of authorization, you can use MD5 or some other hash function to hide thode values. Hashed password can be compared with hashed password at the server side.
If you want to send encrypted text and decrypt it at the receiver side then you have to use some encryption algorithm, e.g. DES (some kind of encrypting key will be needed).