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.
Related
I'm trying to make a game that will tie into website content, and users' accounts will be shared across the site multiple versions of the client.
The problem is that the password needs to be salt-hashed in PHP, and I need to be able to verify through Java, and I can't find any information on secure cryptos (like PBKDF2) and ensuring that the generation is identical between PHP and Java.
I've seen some info on using PBKDF2 on PHP, OR Hmac with SHA-1, but not combining them as is suggested in the name of Java's "PBKDF2WithHmacSHA1". I have a handle now on the individual hashing for PHP or Java.
How do I set up the methods to be able to generate a salt and hash on PHP, store it in MySQL and be able to verify passwords through Java's hashing functions?
Would prefer to stick with PBKDF2, if at all possible (unless someone can suggest an equivalent that would work better for cross-compatibility).
P.S. Not particularly sure whether this deserved to be here or on Crypto SE. I figured, since I was asking about specific languages, I'd try here first.
So, it turns out it wasn't as complicated as I was thinking it was. I found this question that said that PHP's equivalent to Java's PBKDF2WithHmacSha1 was the hash_pbkdf2 function with the sha1 algorithm. From there it was just a matter of transferring the salt and hash from the PHP to the Java. Here's how it ended up:
1) PHP: For this one, I just copied the guy's pbkdf2 function and generated the salt and hash like he did.
2) Java: All that needed to happen was a bit of a change in the bytecode conversion, and it worked just fine.
After that, all I needed to do was modify the Java code to fit into my server/client setup (including secondary session hashing), and work out a few more bugs surrounding more salt and hash encoding and decoding through network transmission, and it works perfectly now.
A slightly more detailed answer is available on that other question.
Try to consider using a pre-built user and password management like JBoss KeyCloak. It is based on standards like OAuth2 and OpenID Connect, and things like password reset, user registration and social login come for free. It includes connectors for Java and JavaScript. Apparently connectors for PHP are available as well.
I have just watched a crypto 101 talk which said if you are typing the letters "AES" into your code, you're doing it wrong! The solution was to "just use GPG".
If you are storing your data on the cloud, all readers and writers need to know the key. If the key is a public private key, that's just a slow key but not a more secure key than just having a good password?
What standard alternatives are there to GPG that properly encrypt data at rest but use a shared secret instead of public keys?
I use Java, and would like to use a library, but want interchange with other platforms.
The solution is wrong in terms - you don't use "GPG" but OpenPGP.
Indeed for encryption using shared secrets (passphrases and alike) OpenPGP is optimal, as it supports multiple methods at the same time and includes compression.
The alternative would be to use CMS encryption with keypairs derived (in some predetermined way) from the shared secret. However such scheme is not standard.
I can remember also XML encryption that supports encryption with symmetric keys, but it has certain security flaws.
So OpenPGP is probably the best way to go.
Regarding compatibility - OpenPGP-compliant library should create packets that can be later processed by any other OpenPGP-compliant library or application. Unfortunately OpenPGP implementation in popular BouncyCastle library sometimes produces not compliant packets - we came across its issues several times when packets created with BouncyCastle could not be processed by GnuPG or our SecureBlackbox due to issues in the packet created.
I'm making a project in Java and Python that includes sending an encrypted string from one to the other. I can get the languages to understand each other and fully de-crypt / encrypt strings. However I was talking to somebody and was told that I am not being totally secure. I am using AES encryption for the project. Part of the problem is that I am distributing the software and need to come up with an effective way and secure way of making sure both the server side know the IV and 'Secret Key'. Right now the same string will always encrypt to be the same result. If I could change those two factors they would be different, so 2 users with the same password won't have the same encrypted password. Please do keep in mind that the server only needs to manage one account.
I appreciate your responses, and thank you very much ahead of time!
Typically, you'd generate the IV randomly, and send it along with the encrypted message. The IV doesn't need to be secret--it just needs to be different for every message you send.
There are a wide variety of concerns to worry about when implementing crypto. Your block cipher mode matters, for instance--if you're using an IV you probably aren't using ECB, but that leaves quite a few other options open. Padding attacks and other subtle things are also a concern.
Generally, you don't want to implement crypto yourself if you can possibly avoid it. It's much too easy to get wrong, and usually quite important to get right. You may want to ask for more help on the Security StackExchange.
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.
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.