Best way to encrypt messages in Java where ciphertext is public - java

I'm writing an app in Java where users must be able to share encrypted messages, and communication happens exclusively via a database where all data is publicly visible.
Requirements are roughly:
Each user may publish some information (e.g. a public key) to the public database but should only do this once
Other users must be able to encrypt a message for a target user and publish it publicly on the same database
The intended recipient must be able to decrypt the message, but no other user should be able to do so
The encryption must be strong enough that no plausible brute force computation should be able to decrypt the message (now or in the future)
Messages are arbitrary length, but usually quite small (think short emails, tweets etc.)
Must be easy to implement in regular Java (libraries like Bouncy Castle are fine if needed)
Users already have Ed25519 key pairs for digital signatures if necessary
What crypto algorithm or combination of algorithms would be best to meet these requirements? I'm assuming some form of asymmetric encryption algorithm with a public/private key pair for each user but alternative ideas welcome. I definitely want to avoid the "roll your own crypto" trap though....

You (almost) always roll your own protocols. Which is usually where the hacks are.
Now, if you were to roll your own algorithm (as in, you avoid, say, AES-256, and write something on your own. We'll just XOR every byte with a repeated application of 'OhWowThisIsTheBestSecurityEvar', it's like a one-time pad right, can't be cracked! - that kinda thinking is what the whole 'dont roll your own crypto' meme is all about. Don't do that.
Even if you use off the shelf 'protocols', it's real easy to mess it up and create holes. The protocol side (HOW you use the crypto algorithms) is by its nature not easily abstracted into a single, hard-to-impossible to abuse prebuilt library.
So, roll your own. Protocol that is.
It seems nearly trivial here - but it's not. The basic job is to use Public/Private key crypto, in the usual fashion, encrypting the message with symmetric crypto (say, AES-256), generating a random IV and random key, and storing both in the DB, but the key is stored encrypted - encrypted using Public/Private key crypto.
That is, at its core, enough to do what your requirements say you want. But, what about replay attacks? Possibly overzealous or implausible, but what if I can write stuff into your DB? I could replay the message: Store the exact same ball of encrypted bytes but with different timestamps, and you'd think it was real.
That's exactly one of those protocol thingies: It helps if you include the timestamp, sender, etc all inside the blob to be encrypted - you want a replay attack to be innocuous, and generally, if the message (including the metadata) is the exact, precise same, it should be. Maybe. Usually. It depends on what your users expect and what they'll be using it for. There is no such thing as perfect crypto, after all. But if even that is not acceptable, there are solutions to that too, though the easy route is simply to ensure nobody has raw SQL-level write access to the DB.
If your system gets 'hacked' it'll almost always be in the second-level 'protocol' bits. Can I just call your help desk and inpersonate a user? Can I just say I lost my password and get a new one mailed to me, and 'just' hack the user's email instead? Can I stick a keylogger in their computer? Maybe litter some USB sticks with RAT worms around the parking lot; a RAT worm specifically written to find their key files, catch them in entering the password for this key file, and send it all to me? No 'off the shelf java library' is ever going to protect you against any of this. You can't do security in a 'I dont really know what I am doing, but I at least I know I don't know so I'll make sure to get a community and expert recommended library and try to follow its manual as well as I can and surely I'll be fine!' - kind of fashion. Not if you take it seriously.
Some of the algorithms you should probably use:
BouncyCastle supports ElGamal, a Public/Private key encryption scheme. The idea is that all users have a public and private key; the public key is known to your server (and all users on demand; your server is a clearinghouse for them and will have to vouch for the truth, that is, if you go: "here is the public key for user Foo", you're vouching that this is true, and presumably vouching that the personal info of user Foo on your site is correct. How - that's on you, and has nothing to do with crypto, but with politics and local processes. Do you call them? Do they identify themselves with a passport? What? The private key is known only to them. You'll need to handroll some sort of invalidation scheme. Perhaps users can anoint a few other users - they then get the right to invalidate their key. The idea being, if a user feels their private key is compromised, they ask one of their buddies to log in and authenticate themselves to the system, and tell the system to mark your public key as no longer valid for any further communications.
Note that you'll have to find a way to use that Ed25519 key pair you have if you want to use that for the vouching system as above.
Use AES-256 along with your plane jane basic new SecureRandom() to generate a key for each and every message you want to store in the system. To store a message, you take the data, generate a random key, encrypt the data using that key and the AES-256 algorithm, store the encrypted data, then you encrypt the key using ElGamal and the user's public key, and store that too. To decrypt this data, the user fetches the (with their public key encrypted) key data (which can be public), and the encrypted data (also public), and can undo the job on their end by first using their private key + ElGamal to derive the randomly generated AES-256 key used, and then use that. You don't encrypt the entire message with ElGamal; that's quite slow and not the common way to do it. AES-256 is blazingly fast. But symmetric. You'll need a 'block mode' and a 'padding mode' for your encryption in addition to an algorithm (Which will be AES-256). block mode should probably be GCM; you may read about CBC; that's outdated (worse, and slower). Definitely don't pick ECB, that's straight up insecure. Padding probably doesn't matter, depends, as usual, on so many factors.
You mentioned nothing about signatures. If user "Foo" wants to send a message to user "Bar" in a way that nobody but Bar can read it, all they have to do is the above. But if they do, "Bar" has absolutely no idea who sent it. GCM has some built in support for MACs, which is what you need to tag a message in a way that senders can prove they were, in fact, the sender, and also to tag date and time, though this is not easy; basically you as a server would tag any message with 'I, server, decree, and you are going to have to trust me, that this was present in the DB at this point in time and appeared recently; to me anyway. Signed, server'.
That'll give you a few terms (MAC, GCM, AES-256, ElGamal, Bouncy Castle, signatures, and a few more) to search the internet for and read up on.

It sounds to me that you are developing a chat system.
The way to fulfil your requirements you need to combine two crypto systems.
The first one is a Diffie-Hellman key exchange - in short: each party generates a private/public key pair. The public key is stored on the server. If I try to send a message to Bob I'm using your database for "Bob" and get his public key. Next I'm generating a "shared secret" with my private key and Bob's public key - this shared secret is usually 32 bytes long.
Now the second phase begins - I'm encrypting my message with an AES algorithm (best one could be "GCM"-mode) and save the encrypted message (encoded as Base64-string) in your public database (of course with any hint that the counterpart is me).
Third phase: Bob is getting the encrypted message with the note it's from Michael. Now Bob is searching in the database for Michael's public key, builds the shared secret with his (Bob's) private key and Michael's public. Some kind of magic will happen - the shared secret is the same key I used for encryption. Now Bob is been able to decrypt my message.
Just a note: beware the risks because if Bob will lose his private key (maybe stored on his stolen smartphone) he will no longer read any messages for him, so a backup of his private key is needed.

Related

Where do we store key/passphrase/salt for encryption?

My app needs to encrypt some data (a user session token). Most examples I see around have a method that generates a Key using a passphrase and a salt, like:
public static Key generateKey(char[] passphrase, byte[] salt) {
...
}
My understanding is that we have three options for generating the passphrase:
Have the user enter it every time the app starts (annoying to the user).
Hard-code the passphrase into the app itself. More convenient for the user, but someone can find out what your passphrase is given your app binary.
Randomly generate a passphrase, but then we have to store the generated Key on disk. Now we've just shifted the problem to having to store the key securely on disk, which also seems impossible. If the attacker finds the generated key, big problem.
Option #1 won't work for me. Options #2 and #3 seem inherently flawed, unless I'm grossly misunderstanding how to go about this (hoping that I am). What's the recommended way to do this if we can't go with #1? Do we put in a bunch of obfuscated hoops for an attacker to jump through and hope for the best?
Thanks
"Do we put in a bunch of obfuscated hoops for an attacker to jump through and hope for the best?" Basically yes. The size and number of the hoops being how hard you want to make it.
If you are not using a server, then whatever you do to obsfucate and encrypt your data is reversible. However, you can make it REALLY hard. For example, a technique I used to protect some video assets.
Replaced the first 1024 bytes of the header (it's MP4) with 1024 bytes taken from the middle of one of the apps image assets. I tried several repairers, all of which failed to automagically recover the file - although it can be done manually. Then...
Encrypted the file using a private key which is 256 bytes taken from another image asset.
When the key is extracted, it's hashed through an algorithm which does all kinds of otherwise non-sensical maths to mangle the key.
Used a pre-compile obsfucator.
I've tried myself to reverse engineer this, even knowing how it's done, and it's so hard as to make the effort not worth the result.
There are numerous discussions on SO which summarise as; If you simply want to stop copying, make it difficult (cost vs reward) but otherwise sleep easy because there is ultimately nothing you can do. If the data is commercially sensitive, then a server coupled with system level security (e.g whole device encryption and no root) is required.
You store the salt along with the encrypted data, it is not secret information. You can derive the key on either something the user enters, or some sort of a device property: (hashed) IMEI, MAC address, etc.
Basically, think who are you protecting your data from and why. Since the user needs this, there is not much point trying to protect it from them. If you store this in a private file, other apps cannot read it on a non-rooted phone. If you want to protect it on rooted phones, encryption might help, but as long as the key resides in the app, or is derived based on something on the device, it is only making it harder, not impossible to recover.
Android does have a system-wide keystore service, but it has no public API and is subject to change. You could use that to protect your key(s), if you are willing to take the risk of your app breaking on future versions. Some details here: http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html

Encryption/decryption using shared key in java?

I have customer token which i am sending from one webapplication say app1 to another webapplication say app2. I want to encrypt the customer token
at app1 and decrypt it at app2 using key which is shared at both app1 and app2. i am not getting how to start with this? It would be very
helpful if somebody can point me some sample code or some tutotrial using shared key as there are too much encryption/decryption stuff(like symmetric key, public-private key) on net which has really confused me. Another limitation is that i have really short time for this to go in details. Thanks in advance.
EDIT:- I am looking for simple programme something like given at http://sanjaal.com/java/186/java-encryption/tutorial-java-des-encryption-and-decryption/ but using AES? Not able to find this kind of example in AES using shared key?
I would suggest this :
Have each app of yours assigned a public/private keypair and store the private key securely protected with a password in a secret key. Make sure that this is very secure. Needless to say the public certificate(which contains the public key as well) will be public. Each app will have the public key certificates of all the other app. Now when ever an app wants to communicate with other app ;
First sign(basically encrypting) the token with the sending app's private key. Then encrypt the resulting value with the public key of the app you want to send the data to.
This way the app that receives this value can be assured that no man in the middle will be able to make out what you have sent and also verify that the token has come from a trusted entity.
But if you use a shared key(symmetric key), then if the symmetric key is compromised, then all the apps will be compromised.
Usually you use a asymmetric algorithm (Eg. RSA) to encrypt a symmetric key (Eg. AES) to securely share it with another party and then your subsequent communication is encrypted with the symmetric key. That is VERY basic gist of it but there are a lot more factors to consider.
And I can see yourself getting in to VERY big trouble right now for several reasons.
You don't understand the concepts of cryptography
You are not willing to thoroughly study it
Simply wants to grab some code from the web and use it.
Really short time
I understand that you might not have a choice perhaps your employer/client wants to get this done quickly. But I thoroughly advice you NOT to go ahead unless you know what you are doing. If you are handling sensitive details such as credit card information or other critical customer information, do your self a favor and study cryptograph in depth.
It doesn't matter how strong the cryptographic algorithm is if you use it in an incorrect fashion. So you need to understand HOW to properly use each algorithm and it's advantages/disadvantages.

DSA vs RSA and AES128 vs AES256 encryption in Java

DSA & RSA
It's not about which one is stronger.
I've been researching the subject on the internet and below is the summary of information I've got.
Can you please advise if it is correct or not, and if there are any additional important issues which I don't mention here.
Here I am talking only about DSA vs RSA in application to Java.
My main goal - to use Public key algorithm to send Session key (AES) from client to server and then to check authencity of client.
DSA.
1. In Java you're are supposed to encrypt the file with private key.
2. It means that IT IS a signature - anyone with a public key can read it, but only the owner can sign it.
3. If you try using public key as private and vice versa, you'll run into trouble, because it is not that difficult to guess public key by private.
4. You effectively can't use DSA to send Session key, because everyone will be able to decrypt it.
RSA.
1. In Java you're are supposed to encrypt file with public key.
2. It means that this is best way to deliver secret messages to one specific recepient. Nobody can read it after being signed, except for the owner.
3. If you try switching keys with each other it will bring troubles (the same as above)
4. You can effectively use RSA for a client to send Session key encrypted with Server's open key and then receive confirmation from servers signed with Client's open key.
Based on this I decided to use RSA for my purposes.
AES256 vs AES128
Another unrelated question - do you think that for session encryption without any extremely sensitive data it makes sense to use AES256?
I'd like to, but it creates problems for end user. I know it is very easy to install update to Java which allows 256 bit keys, but the sad truth is that even such simple thing can cut potential userbase by half.
On the other hand - if I don't send sensitive information (like credit card numbers) and each key is used for not more than a few days, maybe AES128 is enough?
Obviously I am going to include the option to use AES256 for those users who are not bothered by the need to install update.
Thanks for any comments!
As you found out, DSA is only a signature algorithm, not a encryption one, and as such not suitable for key exchange.
If you have a online connection (and not just transport from one point to another), you can use Diffie-Hellman (which is based on similar ideas like DSA), and use DSA or RSA in signature mode to authenticate the other side to avoid a man-in-the-middle attack.
Other than that, RSA key exchange is also quite usual (i.e. sending the key AES key encrypted with the RSA key of the server).
For the AES variants, AES-128 should be secure for about any time (i.e. bruteforcing should take longer than you'll live). There is only a larger key variant as the US military wanted to use different levels of security for different stuff. (And also, AES-256 is lately showing some (theoretical) weaknesses which are not in AES-128, which could mean that AES-128 is actually more secure.)
But as Kerrek commented, don't try to invent your own protocol, use existing ones. You will make all mistakes the other ones did before, and add new ones. (You can do your own implementation of these protocols if you want, but it is also often easier and safer to reuse existing implementations, too - there are lots of things to do wrong even with secure protocols, like using bad random numbers.)
For online (two-sided) communication, SSL (or now better its successor TLS) is the way to go. In Java, it is available as the SSLEngine class (if you want to use asynchronous I/O), or with a SSL(Server)SocketFactory (for normal socket read/write). I used this for applet/server communication (for my project fencing-game).
For offline (one-directed) communication (like e-mail) or storage, use the PGP data format (which also can use RSA and AES). (I don't know of an existing Java implementation, though.)
DSA means "Digital Signature Algorithm". It's meant for signatures. You cannot use it to encrypt anything.
AES128 is plenty secure enough for sensitive information. Even the US government allows its use for anything except information classified as TOP SECRET, and that only because of a "better safe than sorry" mentality and considering that such information may still be harmful if decoded 50 years from now. I wouldn't hesitate a second to use it for transmitting credit card numbers (which, after all, expire in less than 10 years).

Complex encryption/decryption model - is this even possible?

Suppose I have a server which is publishing information (e.g. via a message bus) to four parties: A, B, C and D. All traffic can be discovered in encrypted form by any party. In order to make use of the information, obviously it would need to be decrypted:
Party A should be able to read all information (i.e. decrypt information intended for A, B and C)
Party B should be able to read information intended for B and C
Party C should only be able to read information intended for party C
Party D should be able to read information for B and D
Obviously this could be achieved by having completely separate public/private key pairs for each party and then sharing the private keys as per the requirements above. Unfortunately this does not scale nicely to hundreds of parties.
Is there a better way?
EDIT
Basically, what I would like to do is for each person to have their private key and for me to say, when encrypting a message, that it is encrypted with key = A | B | C such that this means that a person with any of key A, B or C can decrypt it. Imagine a trunk which can have n locks fitted to it, any of which can open the trunk.
Imagine a supermarket. Every single shelf is independently stockable. There are a hundred shelf stackers, each of whom stack a number of shelves. These stackers have managers, who can overview the shelves of all of their subordinates. These stock managers have section managers possibly having complex relationships, such as manager A being able to see a subset of manager B's shelves. There are a few store managers who can see everything.
I don't think the scalability problem comes from using public-key crypto. It rather comes from the complexity in your requirement (wanting to have so many configurable groups).
If you are going to send out the same encrypted message to hundreds of parties, and there can be an arbitrary subset of them that are supposed to read it, and you want to be able modify these permissions later, you need to give everyone his own key-pair.
You would then send out the message encrypted symmetrically (with a random session key) along with copies of the session key encrypted for all recipients.
If you see that very often you address the exact same subset, you may extend the validity of those session keys to span multiple messages. Then you do not need to transmit all the keys every time (you should still expire them after some time, though).
None of the shelf stackers, stock managers, section managers or store managers would have any kind of clue about public/private key cryptography
Well, their software/device would handle that.
What you want can be achieved using normal protocols based on public key cryptography. The Bouncy Castle Crypto APIs has support for both OpenPGP and CMS, either of which can work from Scala.
TO set everything up:
Every party is given a public/private key pair.
No one EVER shares the private key. The private key must stay private
Every party knows every other party's public key
The protocols allow encryption using multiple public keys. For example, if you use something like the PGPEncryptedDataGenerator, then you would call the addMethod(PGPPublicKey) method for every recipient you wish to be able to decrypt the message.
There are a lot of nuances to the API's, but the unit tests and examples will really help you navigate them.
Implementation Details
Both protocols work in fundamentally the same way.
Securely generate a random symmetric key
For every recipient, encrypt the symmetric key with the recipient's public key. All of the encrypted public keys are written into a message header.
Encrypt the message using the symmetric key. This becomes the message content.
Recipients reverse the process to decrypt the message
Search message header for key addressed to self.
Use private key to decrypt symmetric key.
Use symmetric key to decrypt the message content.
Here's a way that requires n key exchanges, but keeps the messages themselves as small as for two-party communication.
Assuming that the general form of your problem is:
There are n parties, numbered p_1 through p_n
Messages have a security level m, such that only parties p_1 to p_m can decrypt the message.
You can use this key exchange step:
Generate n AES keys, numbered k_1 to k_n.
Securely give each key k_i to all parties p_1 to p_i.
Then to send a message with security level m, just encrypt it with the key k_m.
One side-effect of this scheme is that party p_b does not have the ability to prevent party p_a from decrypting messages they send if a < b. Hopefully that's okay.
Can you use custom encryption like Blowfish?
In such a case you can share the Blowfish encryption key and store it in a, let's say, a properties file!
When the data arrives, depending on the destination and the key value in properties file you can try decrypting them

How to securely store a PrivateKey in code [duplicate]

This question already has answers here:
How do I securely store encryption keys in java? [closed]
(4 answers)
Closed 7 years ago.
I'm working on a software project where the application will end up being run in an untrusted environment. I have a need to perform some ancillary cryptographic signing (meaning this is not the primary means of securing data), but do not wish to leave the key in plain view as such:
private static final String privateKey = "00AABBCC....0123456789";
What method can I use to reasonably secure this? I'm aware that nothing is full proof, but this will add an extra layer in the security wall.
For clarification: I've got what is essentially a String that I don't wish to have easily pulled out in a debugger or via reflection. I'm aware that decompilation of the class file could essentially render this moot, but that's an acceptable risk.
Obviously storing the key offsite would be ideal, but I can't guarantee Internet access.
It's impossible to secure a key in an untrusted environment. You can obfuscate your code, you can create a key from arbitrary variables, whatever. Ultimately, assuming that you use the standard javax.crypto library, you have to call Mac.getInstance(), and sometime later you'll call init() on that instance. Someone who wants your key will get it.
However, I think the solution is that you tie the key to the environment, not the program. A signature is meant to say that the data originated from a known source, and has not been tampered with since that source provided it. Currently, you're trying to say "guarantee that my program produced the data." Instead, change your requirement to "guarantee that a particular user of my program produced the data." The onus is then shifted to that user to take care of his/her key.
Forget about obscuring it in the code. It will only make your software harder to read, debug and maintain. You'll also be nailed if your software has to go through a security audit.
If you can't put the key in secure storage (securely on disk, secure memory or a passphrase in someones head), don't bother with anything else.
If you're in a *nix environment, storing the key on disk with root/root 400 permissions might be "good enough".
On Windows, you could use the DPAPI to store the data in Microsofts secure memory.
You could also use a lightweight PBE to encrypt the sensitive key and have the user enter the passphrase when the application starts up.
Whose private key is that? The private key is supposed to be private, so it is wrong to distribute it.
First off - good on you for thinking about this problem!
Is it possible to instead generate a private key, communicate with your Certificate Authority and have it sign the key (and manage a CRL as well)?
As an alternative, if this is going to be running on Windows, you can use the Crypto API to securely store a private key that is marked as not-exportable. How you distribute that key securely can be another challenge though.
Can you break the private key out into two parts: store one in your program, then interactively request the second half - when your app starts ?

Categories

Resources