encrypt files at rest, properly - java

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.

Related

Standard way to Encrypt Data using Public key in Java

My application has to publish a file to several clients over a common channel. I have been doing below process to encrypt it
Generating a symmetric key to encrypt the data.
then encrypting this key with RSA public key and publish it.
Considering all the clients of this application have application's RSA public key, is there any standard format to encrypt a file before publishing it?
Apparently, there are several standard formats for encryption. One of the most popular standard format is Cryptographic Message Syntax (CMS). Also refer to specs for CMS at Internet Standard. This format is widely used for for S/MIME mail message security.
Bouncy Castle APIs provides a wonderful support for this. BC's bcmail-jdkNN-MMM.jar is the Bouncy Castle SMIME/CMS library which is of your use. It is a package for processing RFC 3852 Cryptographic Message Syntax (CMS) objects - also referred to as PKCS#7 (formerly RFC 2630, 3369), and also dealing with S/MIME objects (RFC 3851).
Another popular standard format, XML Encryption format. end-to-end security for applications that require secure exchange of structured data. XML itself is the most popular technology for structuring data, and therefore XML-based encryption is the natural way to handle complex requirements for security in data interchange applications.

Can I implement end-to-end encryption in Java?

I'm creating a web service that stores a list of users with their public keys online, as well as encrypted messages. My end goal was end-to-end encryption.
I initially thought this would be pretty easy -- "Oh, OpenSSL and RSA private/public key asymmetric encryption is great." False. RSA will only encrypt a tiny bit of data, presumably to pass a regular, symmetric key back and forth.
Okay, so I tried to find solutions online. Most of them either ended without a functioning example or pointed at using the command line, all of which seemed excessive and incomplete.
Is there a way to use end-to-end encryption on data with asymmetric keys, or is it all a personal pipe dream? OpenSSL in PHP has a way to do this already, and it's kludgy but it works.
Is there some method I'm missing here?
The common way to encrypt larger amount of data with a asymmetric keys (eg. RSA) is by use of hybrid encryption. In hybrid encryption you mix symmetric and asymmetric encryption. First you generated a random symmetric key, that is used to encrypt the data. Then you encrypt the symmetric key with the asymmetric key. The encrypted data + the encrypted random key are then put together and makes up the full encrypted data.
The openssl_seal() in PHP you refer to, uses hybrid encryption where the symmetric algorithm is RC4. How data is encoded and put together in the encrypted files have been defined by the openssl implementation, and might not necessarily be the way you would want to do it. PGP, as an other example of hybrid encryption, uses it's own way of packing the data.
In any case, hybrid encryption is not something you get out of the box in java, and you typically need to implement each of the encryption + packaging steps yourself, or use one of the libraries that implements there version of this. An example of doing it yourself is this Java code I found that can decrypt messages encrypted with the above mentioned openssl_seal().
An example of using a library for hybrid encryption, could be using the PGP support in Bouncy Castle.
Ebbe's answer is very good, however this question was highly ranked in Google in my attempt to try and find a decent hybrid encryption library (Bouncy Castle's documentation is non-existent and not straight-forward, and GnuPG for Java relies on the OS and is not fully tested). So I thought I'd add on to Ebbe's answer for the weary traveller.
If you can use them, JWTs (JavaScript Web Tokens) could be handy for this. It's also an IETF Standard. There are two different types:
JWS, which is a signed JWT. Plain-text message, but you can verify its authenticity. Which has its own IETF Standard
JWE, which is an encrypted JWT. Which also has its own IETF Standard
Support for JWEs are unfortunately a bit poor at this point in time. However this should hopefully improve. At this point in time (2017-04-11), the only Java JWT library that supports JWEs is BitBucket's Jose4j.
I'm not really sure what you're trying to en- and decrypt, but GnuPG for Java might be a good choice.
It supports public and private keys and can en- and decrypt bigger files and data.

How to convert between PGP keyrings and Java keystore files?

I am currently working on an Android app that talks to a server process on a remote machine. The installation packages for both the Android client and server need to be cryptographically signed; the Android client with a Java Keystore File (JKS) and the server with a PGP key from a keyring file. If possible, I would like to reduce the dependencies by signing both packages with the same key, but neither signing tool supports the opposite file format.
Is it possible to convert a PGP keyring file into a JKS file? Or alternatively, is it possible to convert a JKS file into a PGP keyring file? If so, how?
Edit for clarification: The idea here is to use a single cryptographic key as input for two different signing tools. The tools do not know about each other; it's just some random key to them. I do not want to sign an Android package with PGP, or the server installation package with Android's signing tool, as either would make the output unreadable to the end user.
While it might be theoretically possible there are certainly no tools to do that. If you would want to write one yourself there are a lot of hurdles to overcome. On a low level view there are many different ways to sign data (even if you restrict yourself to RSA, there are still many standards and parameters to choose from). On a high level view such key files and their front end abstractions of certificates or simply "keys" on the pgp side contain a lot meta information like a validity period, ownership information and so on. If you could actually deal with the low crypto problems then you still have to define some translation from one set of meta data to the other.
Also from a cryptographic point of view any key reuse is strongly frowned upon. There are many ways typically sound primitives can break apart if they are used in an unintended way. Certainly the authors and implementers of the algorithms behind the Android tools and the PGP tools did not imagine their tools to be used with such cross generated keys.

Encryption in Dropbox-like Java application

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.

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.

Categories

Resources