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.
Related
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.
I'm looking for a secure symmetric-key encryption algorithm compatible with both JavaScript and Java.
I've tried implementing one but I had some encoding issues.
You don't want to encrypt with JavaScript, especially on the client-side where it is open to tampering, and has no cryptographically secure random number generator.
I've tried implementing one but I had some encoding issues.
You tried to write your own encryption algo? You've gone against everything that the security world hold dear. No. Actual tutorials that explain how encryption works are so scared that people are going to screw things up because they don't understand the math behind it, I've actually seen this in one of them:
If you don't understand encryption, things like, what "cryptographically secure pseudo random number generator" actually is, and common attacks on it, you shouldn't do that.
If you don't understand things like side-channel attacks, you shouldn't do it.
If you don't understand what's going on in crypto and have read at-least two books on it you have no business implementing it.
Crypto is not a magic black box, it's something that is very VERY easy to screw up, even without touching any bit of code in a packaged solution.
What should you do? Forget about JS encryption. I know, I've tried it myself. It's a waste of time. Learn from my mistakes.
Go get an SSL certificate, SSL is the best way for us to encrypt messages on the transport level from a server to a client. It's about as secure as you can get. If you face an advesary that can defeat SSL, trust me, your JS-based crypto is also compromised.
Once it's at the server where it's secure from being tampered with, encrypt it. Anything else is a really long way to waste your time.
Also, go read these books:
![This one is free][4]
[![This one is cash money][5]][5]
(source: [schneier.com](https://www.schneier.com/images/book-ce-150w.jpg))
Then when you understand them come back and scream at me about why I'm wrong and don't understand how much you need JS on the client to do crypto.
There is an excellent DES (and by extension 3DES) implementation in JS, which I use quite often. I'll put up the link Monday, when I'm at the office and have it ready. Results from this (after base64 encoding for the transport) work perfectly with .Net/Mono (builtin), Java (bulitin) and PHP (mcrypt).
Found the links, but both are dead: http://www.shopable.co.uk/des.html and http://www.netdealing.com. I have put it up on http://pastebin.com/KbRsWKJY
This page has CTR mode, which is available in Java. I would recommend keys of 128 bits or you might run into trouble regarding the Java export policies on larger key sizes.
Here is a page which uses some very usefull methods of encryption, including password encryption techniques and ciphres with integrity checks and authentication, although you may need the bouncy castle libraries on Java to match those all.
There are oodles of libraries for JavaScript, but character encoding issues will be present on any of them. So make sure you use the same encoding both on the JavaScript side as well as on the Java side. A quick look up assures me that JavaScript uses UTF-16 internally, but don't hang me up on that.
Finally, don't try this at home, the libraries are there, use them (especially if they mention tests and/or official test vectors).
Like the other answers said, if you don't have to encrypt with JavaScript, avoid it. However, there are some valid use cases to encrypting in JavaScript.
When you need to, I recommend this library: https://keybase.io/triplesec/.
It's more secure than DES, which another answer links to.
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.
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.
From googling I found Jasypt, I'm wondering is it reliable? Anyone know about it?
I have come across it in my occupation and found it useful for verifying encryption algorithms from another source. I can't go into much detail of my verification processes but if you want to be able to encrypt data local to your PC then Jasypt is a great option. It abstracts a lot of crypto functionality and you can encrypt or decrypt data inside of 4 lines of code. However, if you want to encrypt traffic over a network then you may want to look into IPsec support. I also don't think you can configure the more granular settings in Jasypt like specifying a block or stream cipher type.