Say I’m making a snapchat clone app for Android and iOS. Let’s say that I get a snapchat from Baz. I want to pre-download the audio for this snapchat. However, as the developer, I want to secure this audio from being viewable outside of the app.
I’ve been thinking of encrypting it using AES with an IV and key that are both generated from a pseudo-random function that takes the user’s unique ID as input. However, if an attacker found out that this was the way we encrypt our files, and had access to our PRF, he would easily be able to decrypt it and store it permanently. The thing is, I don’t have enough background in cryptography or android programming to tell if that’s really a concern or not. The attacker has to learn a lot about our cipher in order to break it, but he could gain pretty much all of that from looking at the unobfuscated source of our app.
Is my suggested approach cryptographically secure? What other, better or simpler approaches could I take to solving this problem?
3
he could gain pretty much all of that from looking at the unobfuscated
source of our app.
This is DEFINITELY a concern. If that’s the case, then your application definitely has a major security flaw. That could be anywhere from hardcoding password/keys in the code, to writing your own crypto algorithms, to just leaking out information just because of the way code is written.
An established practice in security community has been that even if the code is made public, it should have no impact on the security of the application. Likewise, the cryptographic algorithms and their implementations are public knowledge, and is scrutinized by the security community all the time. It is only after such scrutiny that they are declared secure “enough” for use for various well-defined purposes.
Having said that you have two MAJOR flaws:
- Pseudo random function is not a secure way to derive a key and IV. What you need to use is a Key Derivation Function (KDF), which are implemented in most languages.
- You need to derive a Key and an IV from a secret, such as a password or use asymmetric algorithm in which the private key is used for decryption which happens to be secret. User’s ID is NOT a secret.
There are also two places where you need to encrypt the data:
- Encrypt when it is send from one user to the other.
- Encrypt for storage on user’s device.
I do not know which of these two were you planning to use. For the first case, you can either use symmetric keys or asymmetric keys. Although asymmetric keys have become de facto standard, more recently, some security experts (such as Bruce Schneier) have recommended preferring symmetric over asymmetric keys, but you will have to evaluate which one suffices your needs.
In any case, when you are using a symmetric algorithm, then using user’s unique ID is not sufficient since unique IDs are usually known. You could use user’s password and then derive a key and IV for encryption using a key derivation function (KDF). You will find already implemented KDFs very much like encryption algorithms. You would want to use a random salt with a high number of iterations (recommendations vary, but I have found > 10000 is usually fast enough and considered reasonably secure). You can then embed the unencrypted salt and the number of iterations along with your cipher text in one package that you store. When you have to decrypt, you read that salt and the number of iterations from the package you stored, and use them with the password to derive the key and the IV, and decrypt the cipher text.
A better yet approach is to generate a master key, which you can secure using the mechanism defined above. Use this master key to actually encrypt all the data. This way, if the user changes the password, all you have to do is decrypt the master key, and encrypt again using a key and IV derived from the new password instead of doing this with all the data that the user has stored.
You can also use certificates (which are asymmetric keys) that you store on the client and use for encryption/decryption, but the overall approach will change somewhat. Without knowing exactly what you are trying to encrypt, I do not want to go into too many possibilities.
If you clarify a bit more whether you are looking for encryption between two parties vs encrypting data at rest, I might be able to come back and provide a better recommendation.
Securely communicating the key with which a message was encrypted is a solved problem with asymmetric encryption, where each user has a public key for encryption (that can be stored on your servers), and a private key for decryption that only the recipient knows. This private key needs to be protected somehow, e.g. by encrypting it with a user-chosen passphrase.
That is, we have three levels:
- The message, which is encrypted by a session key A.
- The key A is encrypted itself with a public key B.
- The user passphrase C to access the private part of the key B.
Don’t reinvent something that already exists – the top paragraph basically describes a PGP implementation (which is used for encrypted emails). You could probably adapt such an implementation to your needs.