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.