Encrypt RSA private key with AES 256 in Java

I am writing a secure file sharing application in Java. The general architecture is as follows:

  • The user wants to encrypt the file for secure sharing between multiple users.
  • The application generates a random UUID on the client and uses it as an AES 256 password and encrypts the data using the UUID.
  • The UUID is then RSA encrypted with each person’s public key. Once for a general user.
  • Each encrypted UUID packet is stored as part of the file in a user-defined file header.
  • Then the file is uploaded to the server, where others can access it.
  • The user can use his 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 files can be retrieved from several places. The private key will be encrypted with the user-selected password on the client before it is uploaded to the server.

I would like to do this using 256-bit AES encryption. And I would like to do everything without relying on BouncyCastle libraries or any third-party libraries. It should use standard Java 5 libraries, so I decided to use AES 256 and RSA encryption, not something like PGP.

Can someone find something inherently unsafe with this approach or think of a more efficient way to do this?

Edit:

OK, I am updating the question because all the answers that I get say that I am not transferring the private key to the server. The reason I need a secret key on the server is that the user must have access to their data from several clients and several locations (for example, their iphone, their ipad, their work laptop, home computer). They do not want to manage and copy their keys from device to device, which is even more unsafe than storing their keys on our server, because they will simply send them by e-mail at this moment.

+6
source share
4 answers

The scheme you plan is equivalent to CMS (the standard underlying S / MIME) and PGP; in principle, it is safe. In CMS, this mode is called "key transport". You can also use a multiparty "key agreement" with an algorithm such as DH or ECDH.

The only problem is that you are using weakly selected keys for AES.

I can’t think of any reason to use a random UUID that contains nonrandom bits. Just use the regular key generation mechanism in the Java cryptography architecture. Keys, plaintext, and ciphertext should be represented as sequences of bytes, unless you need to place any external storage or transport that only holds text.

Iterable<Certificate> recipients = null; KeyGenerator gen = KeyGenerator.getInstance("AES"); gen.init(256); SecretKey contentEncryptionKey = gen.generateKey(); 

Initialize the AES cipher and let the provider select IV.

 Cipher contentCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); contentCipher.init(Cipher.ENCRYPT_MODE, contentEncryptionKey); AlgorithmParameters params = contentCipher.getParameters(); byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); 

For each recipient, initialize the RSA cipher and encrypt the AES key.

 Cipher keyEncryptionCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); for (Certificate recipient : recipients) { keyEncryptionCipher.init(Cipher.WRAP_MODE, recipient); byte[] encryptedKey = keyEncryptionCipher.wrap(contentEncryptionKey); /* Store the encryptedKey with an identifier for the recipient... */ } /* Store the IV... */ /* Encrypt the file... */ 

Users who select and remember passwords that give 256 bits of effective power are unreasonable. To get this power, you will have to randomly select passwords, encode them as text and write them to a card. If you really need that kind of power, you can check out a smart card-based solution for storing users' RSA keys.

I highly recommend using the CMS library to store your files. This will increase your chances that the protocol you use is secure, the code you use has more reviews, and that other tools, libraries, and systems can interact with encrypted messages. The BouncyCastle API is a bit obscure, but it might be worth exploring it.

(I can't remember if Java 5 supports "RSA / ECB / OAEPWithSHA-512AndMGF1Padding", if so, you should use this instead of PKCS1Padding.)

+2
source

The big problem with this is the use of UUIDs. Although UUIDs (sort of) are guaranteed to be unique, pretty much what they contain is pretty predictable; significant amounts remain constant across all UUIDs generated on the same machine. Thus, if a person gains access to (for example) his own key, they probably can quite easily guess many other people.

The other part, which is problematic, stores the user's secret keys on the server. This makes the rest of the circuit relatively fragile, since access to these keys obviously gives access to all other data. It also (apparently) means that you usually decrypt the data on the server, so when the user accesses this data over the network, it must either be re-encrypted for transmission, or decrypted on the user's computer, or else you will transfer the data to clarity (thus, most of the encryption will be useless).

Edit: Regarding how I think I will do this:

I will have a list of public keys on the server. When a client wants to share a file with some other clients, he receives the public keys for these clients from the server. Then it generates a secure random key and encrypts the data using this key. It then encrypts the random key using the public keys of all the other clients that must have access to the data. Put them together in a stream and transfer them to the server. Other clients can then download the stream, decrypt the key with their private key, and use it to decrypt the data itself.

This means that each client’s private key remains truly confidential - he should never leave his car in any form. All they have ever had to share with the rest of the world is their public key (which by definition should not cause security problems).

In this case, two obvious lines of attack relate to the random number generator and to the RSA itself. For a random number generator, I would use Java SecureRandom - this is exactly the purpose for which it was intended, and if the memory is served, it has been carefully studied, and significant interruptions in it look rather unlikely.

I will not try to comment on the security of the RSA itself. At the moment, I think your main problem is with the protocol, not with the encryption algorithm. Suffice it to say that if the RSA were significantly broken, you obviously need to change your code, but you will have many companies.

This way, the client will almost certainly keep their private keys. I like smart cards for this job, but there are many alternatives. In terms of server and protocol, this is no longer a factor, though.

Editing 2: Regarding working with multiple devices, I think that I just consider each device as a separate user with its own public / private key pair. I would then (possibly) combine them with the actual users, so I can easily select "Joe Blow" to give him access on all his devices - but with a hierarchical display, I could also quite easily restrict access to a subset of them, so if I want to share it with Joe in his office car, but he is sensitive enough so that I don’t want him to go where someone could look over his shoulder while he looks at him, I can easily do it too .

This makes life easier for users, but retains the same basic security model (i.e. private keys remain private).

+5
source

OK, this question requires a discussion of the protocol, so it does not fully comply with stackoverflow standards. However, let's see if we can make any comments :):

  • PGP Bouncy Castle libraries are very licensed, so you can even copy them to a subpackage inside your code;
  • In addition to PGP, there are also other standard container formats, such as CMS or XML encryption, although the latter may not be such a good general purpose format;
  • Instead of UUIDs, I highly recommend using a well-matched PRNG such as the Java JCE "SHA1PRNG" to create AES keys. I see no strong reason why you should rely on something like a UUID in your circuit;
  • AES keys must consist of random bits in order to have enough entropy, thinking of them as "passwords" leading into a trap: you cannot use String as a secure AES key;
  • The user will have to trust your application and server, you act as a trusted third party: you can send user passwords to your server, you can send incorrect public keys to users, etc. etc ..>
  • Your scheme is not protected from any person in medium attacks (and many argue that this cannot be done without using SSL)
  • Instead of direct password encryption, you should encrypt the RSA secret key, for example, PBKDF2 password-based encryption;
  • Try adding integrity protection for encryption starting with Java 7, you can use AES in GCM mode, it's worth it.
+1
source

It all depends on how “secure” you want encryption to be. RSA is obviously a well-documented / accepted standard for PKI. At the same time, when you provide plaintext, as well as encrypted text, it greatly facilitates the hacker to decrypt encrypted text that knows part of the plaintext. Here you do just that. Although you only transmit the encrypted UUID, having the same unencrypted text encrypted with multiple keys gives the attacker a significant understanding of the payload. In addition, if the hacked one is actually one of the recipients, it can decode the UUID and thereby automatically knows the plaintext, which is encrypted with the public keys of other users.

This is unlikely to be an important issue for you, but I just thought that I would point out a security risk.

I'm not quite sure why you need to store the user's private key. In addition, using a simple password to encrypt the private key, you basically reduced the overall security of the entire system to the strength of the user password. Finally, if the user loses his password, he is a toast; There is no way to recover data.

I did something similar in the past, but saved the results in the database. However, I used the BouncyCastle libraries at the time, so I don’t know how to do this without them.

-1
source

Source: https://habr.com/ru/post/920710/


All Articles