I am writing a secure file sharing application in Java. The general architecture looks like this:
- User wishes to encrypt a file for secure sharing between multiple users.
- The application generates a random UUID on the client and uses this as the AES 256 password, and encrypts the data with the UUID.
- The UUID is then RSA encrypted with each person’s public key. Once per shared user.
- Each encrypted UUID packet is stored as part of the file in a custom file header.
- The file is then uploaded to a server where others can access it.
- The user’s can each use their private key to read the AES encryption key and decrypt the file.
Here is the catch. The user’s private key must be encrypted and stored on our servers in our database so that the files can be accessed from multiple locations. The private key will be encrypted with a user selected password on the client prior to being uploaded to the server.
I would like to do this using AES 256 bit encryption. And I would like to do the entire thing without relying on BouncyCastle libraries or any 3rd party libraries. It needs to use the standard Java 5 libraries, which is why I have chosen to use AES 256 encryption and RSA rather than something like PGP.
Can anyone find anything inherently insecure with this approach, or think of a more efficient way to do this?
Edit:
OK, I’m updating the question because all of the answers I am getting are suggesting that I not transmit the private key to the server. The reason I need the private key on the server is because the user’s need to be able to access their data from multiple clients and multiple locations (ie: their iphone, their ipad, their work laptop, their home pc). They do not want to have to manage and copy their keys from device to device, which is even more insecure than storing their keys on our server because they would just end up emailing them to themselves at that point.
The scheme you outline is equivalent to CMS (the standard underlying S/MIME) and PGP; fundamentally, it is secure. In CMS, this mode is called “key transport”. You could also use multi-party “key agreement,” with an algorithm like DH or ECDH.
The only problem is that you are using poorly chosen keys for AES.
I can’t think of any reason to use a random UUID, which contains non-random bits. Just use the normal key generation mechanism of the Java Cryptography Architecture. Keys, plaintext, and ciphertext should all be represented as byte sequences, unless you need to accommodate some external storage or transport that only accommodates text.
Initialize the AES cipher and let the provider choose an IV.
For each recipient, initialize the RSA cipher and encrypt the AES key.
Having users select and remember passwords that give 256 bits of effective strength is unreasonable. To get that strength, you’d have to randomly choose passwords, encode them as text, and have users write them down on a card. If you really need that much strength, you could check out a smart-card–based solution for storing the users’ RSA keys.
I’d highly recommend using a CMS library to store your files. It will increase your chances that the protocol you’re using is safe, the code you are using has had more review, and that other tools, libraries, and systems can inter-operate with the encrypted messages. BouncyCastle’s API is a little obscure, but it might be worth learning it.
(I can’t remember if Java 5 supports “RSA/ECB/OAEPWithSHA-512AndMGF1Padding”; if it does, you should use that instead of PKCS1Padding.)