Encryption in Dropbox-like Java application - java

I'm thinking about encryption in an application. The architecture consists of:
Server
Desktop client
Web client
mobile client
The goal is to allow user to store his data on the server, and access it from all clients, but to guarantee data privacy by encrypting data on the client.
Dropbox is an example of such an architecture, but as far as I know they don't do that - they must store plaintext data on their servers, otherwise they wouldn't be able to save on space by storing the same file only once, even if it was stored by multiple users.
How would you implement such an application? I'm thinking about using Java for desktop client; the same encryption code could theoretically be reused in GWT web client (compiled to Javascript) and in Android client. However, that's only in theory.
Is there an encryption library that's available on all these platforms?
What algorithms to use?
What about private keys? I can ask user for the password every time, but how do I ensure that private keys are the same for the same user in all clients?
I'd like to avoid multiple passwords; but if I use the same password for both data and authentication, how do I prevent server from giving data to a hacker which supplied the wrong password, or server from being able to decrypt user data because it has user's password?
What possible gotchas are there?

You actually need a few different pieces of cryto.
First, you want the client to encrypt the file for upload, and upon retrieving the encrypted payload back decrypt it.
Second, you want some method to transmitting the encrypted file for upload in a manner that insures that only the correct user can access his files.
The first problem requires a symmetric encryption algorithm. There are a bunch out there, but your best bet is probably AES. If you take a look at gwt-crypto at they have a wrapper for the java bouncy castle implementation. That takes care of two of three of your platforms. I don't work with android platform, but I'd be surprised if there wasn't an AES implementation floating around. As for the key, you'll probably end up with a hash of a password. Just keep in mind the possibility of rainbow tables and take appropriate measures. The password used to encrypt the file need never go over the wire, as I understand your model all encryption and deception is done on the client. Since you mentioned system administrators as a potential attacker, you really need to look into key loggers, memory dumps and the like, but that's beyond the scope of the specific question you asked.
The second problem is a solved problem using TLS with client and server side certificates. Clients for such are available for all three platforms you are looking at. Whether you want make your users go through the hassle of installing client side certificates, though, is up to you. There are various fallback options but none are as well vetted.

Related

Encryption and Decompiling

Im about to put my Android app on the marketplace. I recently encrypted all of my server/client communication. What i am wondering is if my data is encrypted using a specialized key, and if a person decompiles my code and extracts the key, then is it even worth encrypting the data in the first place? My communications ran a lot faster when the data wasn't encrypted. With the game being an action game, lag is going to be a huge "fun killer" and from experience i know it is frustrating. I know the encryption makes the app a lot safer, it makes it safer for the gamers and the server but it causes huge lag. Is the security worth the deduction in performance? Is even worth using encryption when your code can just be decompiled? I already use Android Proguard but if someone really wanted to decompile my code, they would take the time to sort through all of that garbage.
I think, it is safe to operate under these assumptions.
Client cannot be trusted. Ever.
Server is authoritative source of information.
Don't trust data that clients send you, make checks and validations against it (like if someone tries to 'teleport' from one map corner to another, by sending modified location).
Accept only data that's valid.
Ban cheaters.
Encryption is ok, but when it does not harm the game or gameplay (in your case it does).
You put the encryption key in the client code? Well that is worthless, encryption on the other hand is totally worth it, the problem is you chose the wrong way of doing it.
I would have probably used authentication instead of encryption (hashing all the data you are sending so that you can verify it at the server end). This will work for ordinary game info, because there is not much need for confidentiality. Unless you are sending in private user info like name, age, credit card info etc., I suggest you use plain authentication which is much faster than encryption. You can go for really simple hash functions or if you think that your game really motivates people to tamper with it, then you can use military grade hash functions like SHA-256 or above. But no matter which hash scheme you use, it should be much less time/resource consuming than implementing a proper encryption scheme.

What is the point of encrypting anything in Android (or Java) if source code can be reverse engineered?

Android and Java provide a crypto API that is relatively easy to use for crypto non-experts.
But since we know that no code can really be protected from reverse engineering, especially string constants used as seeds or shared secrets, I am wondering: What is the point of going through the ordeal of encrypting and decrypting in Android applications?
Am I missing something?
Trying to make my question clearer and more concrete: Suppose I have an application in which certain strings used by the code and in the code (i.e. not user data) need to be secret: One approach is to store them in encrypted form in the compiled .apk and decrypt them (using an obfuscated hard-coded password) at runtime. Another approach would be to store them in encrypted form in a remote server, fetch them (over the Internet) and decrypt (using a shared password) them at runtime.
I don't see much difference between the two, since both require the "secret key" being present in the (reverse-engineer-able) code.
Is there a solution to this problem?
If there isn't a solution, why encrypt at all?
This is not strictly a problem with Android or Java. Anything can be reversed, it's just harder if it's native code. And bear in mind that they don't even have to reverse it: you have to eventually decrypt the data on memory to manipulate it. At this point, the attacker can just take a memory dump and they will get your data. If they have physical access to the device, and you are manipulating the data in software, there is really nothing you can do to stop them. The solution for this is to use a dedicated hardware module (HSM) that is tamper-resistant or at least tamper-evident (if some one messes with it, it either deletes all data or at least keeps some logs of the event). Those come in different shapes and sizes ranging from smart cards to network connected devices that cost a lot. Currently not available for Android, but maybe it will get something similar to a TPM, so you can store your keys securely and do crypto operations in hardware.
So consider just how secret your data needs to be and decide on an adequate protection level.
You might want to have it downloaded it over SSL (that would protect it in transit), making sure you authenticate both the server (so you know you re getting the right data from a trusted place) and the client (so you can be sure you are only giving the data to the right person). You can use SSL client authentication for this, and it will be much more secure than any custom encryption/key exchange scheme you (or anyone who is not a cryptography expert) might come with.
The shared secret in the crypto API is not something that you would store in the app (as you say, that would be vulnerable to reverse-engineering -- though perhaps not as vulnerable as you would expect; obfuscation is pretty easy).
Imagine instead you wanted to create/read encrypted files on your phone (for your secret grocery list).
After creating one, you save it using a master password (that is immediately discarded by the program). Then when you want to read it, you have to re-enter your master password. That's the shared secret the API refers to, and it is completely tangential to reverse-engineering.
The problem you are describing is somewhat similar to storing a master password for a password manager problem.
In that case the solution offered is using salt for password hashes.
ateiob Any time you store the master password in the app you are really just making it a bit harder for unauthorized users to access the encrypted data.
First we can agree that encrypting data with a "master key" embedded in an application and storing that data on the phone is open to having the "master key" reverse engineered and the data decrypted.
Second I think we can agree that encrypting data with a secret password and then deleting the secret password should be reasonably safe using strong encryption, 256 bit keys and strong passwords. Both techniques apply to programming on mobile devices. In fact, iOS, supports BOTH needs out of the box.
[keychainData setObject:#"password" forKey:(id)kSecValueData];
Perhaps a real world example may help.
Say if on low memory a temporary data field must be persisted and protected, it can be encrypted with a master password and cleared when the user clears the temporary data field. The temporary data field is never stored as plain text.
So there are two passwords, a master password, embedded in the app for temporary short term encryption and a secret password, that usually must be entered by the user, for longer term persisted encrypted data.
Finally, if you are encrypting files, consider adding another level of indirection. So that the current secret password is used to encrypt a random key which is used to encrypt all the user's files. This allows the user to change the secret password without any need to decrypt, encrypt all the encrypted files.
The attacker is assumed to have a copy of your code. The secrecy of your data should depend entirely on the key. See Kerckhoffs's Principle.
To keep your key secret you must separate it from your code. Remember it. Keep it on a piece of paper in your wallet. Store it on a USB stick that you usually keep in a safe. Use a program like PasswordSafe. There are many possibilities.
It is of course possible to make any attacker work her way through many layers of keys to get to the key she actually needs. PasswordSafe and similar are one such option. You will notice that such programs do not give you an option to "remember your password" for you.

Java - Password encryption/decryption for external sites

On our server, we have several periodical jobs that login to external accounts through API's. Currently, these passwords are hard-coded (in the clear). We are going to be storing them in a database and would like to encrypt the passwords, but we must be able to decrypt them to login to the external sites. Is there a way to store these passwords securely without having another password stored in the clear for encryption/decryption? (This seems like a common problem, but I am not familiar enough with security terminology to classify it). Thanks!
What you are trying to achieve is very similar to this question. Ideally you do not want to keep these secrets in the database, you want to keep them as far away from your application as possible. Why? Because this way you can at least rule out the application itself as an attack surface and it will be much harder to get access to those passwords.
In your case you want to protect the encryption keys with a password. This means that you have to store the password somewhere. Should you encrypt that password again? This leads to a vicious cycle - it's what I meant by this section of the answer:
... What brings us to that resource. It's really a hen-and-egg problem with key stores and passwords. The only really clean solution to this is entering the passwords manually each time the app/database is started. But this tends to be a real problem (think of: crash in the middle of the night), so people tend to store the passwords in a text file on the file system. It's acceptable as long as you follow some guidelines:...
If you encrypt something, then there is a secret resource, the key involved. The ideal way to keep it secret is, as outlined in the quote, memorizing it and entering it manually so that no trace of it is left behind. As this is often not manageable, you have to live with something less secure than memorizing but better than storing the secret in plain text.
The same recommendations as in that post apply to your case with regard to storing the secret password in a file. As an alternative you could try to leverage OS Secure Storage facilities such as Windows Data Protection.

Java crypto API vs. different platforms

I have an Android application, which uses javax.crypto to encrypt some text data in files. Encryption implementation is similar to this. The application works fine with the encrypted data it previously created.
Now, I almost ported my Android application to desktop (JFace/SWT). I'm using the same encryption implementation for the ported application, as it does not depend on any Android-specific API. The ported application works fine with encrypted data it created.
The problem is that desktop application cannot decrypt data, which was saved with Android application. The Android application fails to decrypt data, which was saved with desktop application as well. I double checked bytes streams of plain data and password to encrypt on both platforms. They are the same, so there are no problems with text encoding or so. But encryption routine return different encrypted results on different platforms even input data is byte-to-byte identical.
Does Java crypto API guarantees the same operation on different platforms? Should an encryption provider (AES/128bit in my case) work the same way on Android, Linux and Windows? Is there a way to tune javax.crypto to get interoperability on different platforms?
AES-128 should work the same on both systems. In theory.
In practice there are a lot of details that need to be the same on both systems.
are you using the same padding at both sides?
are you using the same mode (CBC, CTR, ECB) at both sides?
do you have exactly the same password at both sides?
do you have the same IV/Nonce at both sides?
do you have the same key derivation method on both sides?
Check any defaults on both systems. If the defaults don't match then you will need to set one side or the other explicitly.
It is a mistake to depend on a cryptographically-random number generator generating the same random numbers on different platforms. Normally, the cryptographic random salt used in a key-derivation algorithm has to be communicated from sender to receiver. It might be communicated as a secret, but it does need to be communicated. The "master password" is the main secret, of course.
One way these salts are often communicated is as a prefix on the ciphertext. That makes the ciphertext longer than the plaintext, but I don't think that matters in your sample technique.
Also, for a full-up encrypted-message exchange, other parameters of the encryption need to be communicated to the decrypter. You can wire those into your implementations, as you've done here, but depending on reproducibility seems too brittle. It is of course something an attacker can replicate, of course, so it is not part of your secret.
You might want to rethink the key-generation algorithm setup to be something more robust.
Afterthought: What is happening in the current approach is a cryptographically-useful RNG is being used in a way where all the randomness has been removed! The recommendation to check out PBKDF2 and key-derivation generally is a good one.
You'd have to show us some code. One frequent beginner mistake is to store the encrypted data in a String rather than the byte[] it came in. String isn't a container for binary data. This technique can fail in many ways including default charade differences.

How can I hide the salt code in Flash or Java?

I need to be able to transmit data from a Flash browser application to a PHP file on a web server, both securing and validating the data whilst and at the same time trying to prevent unauthorised creation of the message. (I want to try and ensure that the message comes from the application, not a user sending a message via another means).
In a C++ application I would Salt the data, and send the hash of the data along with it, and then validate the hash against the data to ensure integrity and source.
However, in Flash (& Java), applications can be decompiled so that the source code is viewable. So if I used this method, someone could (relatively) easily find the salt, and then create a 'valid' message of their own to send outside of the application.
Is there any way I can 'hide' this salt code to help secure the transmission? Yes, I know there are code obfuscators, but they don't fully hide the code, just add another layer.
Or is there another method entirely that could be used to transmit data and validate the source & content at the PHP end?
No matter what you do, the code to do it will be there in the client, and all you can do is obfuscate. If you, as Tomasz says, were to have the client authenticate with the server and then receive a salt (or a key from a asymmetric key-pair) you still need to have all the code necessary to connect to that server in the client. So by design, no matter what you do, all the ingredients to do so has to be in the client, and thus on your "hackers" computer. It's just a question of much harder it would be for a hacker to understand it.
It's the same for all kinds of clients, no matter what language they're written in. If a DVD player can show a decrypted DVD disc on your TV, it has to have the key to decrypt it in memory, which you can find. This is why no-one has made perfect copy-protection :)
EDIT:
As all the others are saying. Off-the-shelf obfuscator is probably the best way to go, and you could make the client jump through some extra hoops first aswell.
EDIT2:
Turns out I didn't understand Tomasz correctly. If the user himself has the key to authenticate to the server in order to get the hash, that will indeed authenticate that the message was sent from the user, but still not from the application. If this is a matter of avoiding cheating then the hacker is probably already a customer (buying a product or making an account). If what you want is to authenticate the user, then it's a completely different matter, and that is quite possible. (with it's own problems of-course)
There's no truly secure way to protect programs that run on the client. (C++ can also be decompiled by the way.) It's always going to be possible for users to run clients that have been hacked, and any encryption key will have to be present in the code in some form. You may be able to make it more difficult for casual hackers but that's it. Whatever you implement will amount to another form of obfuscation; you may as well look at the off-the-shelf obfuscators.
Perhaps first authenticate with the server, get a salt key from the server, then use it? This way users wanting to fake messages even if capable of decompiling the app would have to authenticate also.
Other than that - at some time you always need the password, hash, key (or whatever is needed to encrypt or validate data) available to the application and either you get it first from your server or embed in the application, which would be recognizable by decompilation.
EDIT
As others have pointed there is no 100% security, everything can be hacked, the point is to make it not too easy, to prevent casual hackers, that's all. So as Jim stated an off-the-shell obfuscator may be the best compromise.

Categories

Resources