1
votes

I want to ask you some question about security on key in java. My code using RSA and AES for encrypt and decrypt a plainText. And I want to use my own password as a private key(AES) for verifies key(RSA). Because RSA are generate public and private key random. (In real case: private key is input by user and public key store in database for verification.)
This code is work find, but I want to know this code is correct or not? Please advice! Thank you.


My process:
1. generate a symmetric key
2. Encrypt the data with the symmetric key
3. Encrypt the symmetric key with rsa
4. send the encrypted key and the data
5. Decrypt the encrypted symmetric key with rsa
6. decrypt the data with the symmetric key
7. done

import java.io.UnsupportedEncodingException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class AES_RSA {

    private static byte[] key;
    private static SecretKeySpec secretKey;

    public static void main(String[] args){
        try {

            //1. Generate Symmetric Key (AES with 128 bits)
            String password = "123456";
            KeyGenerator generator = KeyGenerator.getInstance("AES");
            generator.init(128); // The AES key size in number of bits

            setKey(password);

            //2. Encrypt plain text using AES
            String plainText = "Please encrypt me urgently...";
            Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            aesCipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());

            //3. Encrypt the key using RSA public key
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(2048);
            KeyPair keyPair = kpg.generateKeyPair();

            PublicKey puKey = keyPair.getPublic();
            PrivateKey prKey = keyPair.getPrivate();

            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.PUBLIC_KEY, puKey);
            byte[] encryptedKey = cipher.doFinal(secretKey.getEncoded()/*Seceret Key From Step 1*/);

            //4. Send encrypted data (byteCipherText) + encrypted AES Key (encryptedKey)
            //5. On the client side, decrypt symmetric key using RSA private key
            cipher.init(Cipher.PRIVATE_KEY, prKey);
            byte[] decryptedKey = cipher.doFinal(encryptedKey);

            //6. Decrypt the cipher using decrypted symmetric key
            SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey.length, "AES");
            Cipher aesCipher1 = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            aesCipher1.init(Cipher.DECRYPT_MODE, originalKey);
            byte[] bytePlainText = aesCipher1.doFinal(byteCipherText);
            String plainText1 = new String(bytePlainText);

            //7. Done! 'Please encrypt me urgently...'
            System.out.println(plainText1);

        }catch (Exception e) {}
    }


    public static void setKey(String myKey)
    {
        MessageDigest sha = null;
        try {
            key = myKey.getBytes("UTF-8");
            sha = MessageDigest.getInstance("SHA-256");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16);
            secretKey = new SecretKeySpec(key, "AES");
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
1
If your code works, you should try code review instead. This is off-topic for StackOverflow.Luke Joshua Park
Also, you don't authenticate your ciphertext at all. Anyone could change it and you wouldn't know. You aren't using this in production right?Luke Joshua Park
@LukeJoshuaPark Does the encrypted secret key need to be authenticated or does it not matter if it's tampered with?Ian Warburton

1 Answers

1
votes

You pseudo-steps are correct, but your description not. For example, you normally keep RSA private key and distribute RSA public key.

But a few suggestions for creating better code.

  1. I suggest to use PKCS5 for creating password-based secret keys rather than a simple hash. Java's PBEKeySpec is a class for generating such secret keys. Here is a small sample code which you can use for your setKey() routine (adjust it as you prefer):

    SecretKeyFactory skf = SecretKeyFactory.getInstance("AES");
    SecretKey key = skf.generateSecret(new PBEKeySpec(password.getBytes("UTF-8"), salt, 10000));
    
  2. Never use ECB mode of operation for encrypting data. In worse case, use CBC with randomized IV.

  3. You got something wrong. RSA private key is kept private on server, but RSA public key is distributed freely between clients(normally). You are doing this in the other way.
  4. This is just a suggestion, but I think it is better to use RSA/ECB/OAEPWithSHA-256AndMGF1Padding rather than RSA/ECB/PKCS1Padding for RSA padding. But I think it is not necessary.
  5. In general, you must add a hash or HMAC for authenticating your encrypted data too. But you don't have any authenticating mechanism right now.

Update: Based on design of your mechanism, you cannot securely add an authentication method for detecting active attacks(such as man-in-the-middle). Check comments from Maarten too.

These are the problems that I found. The most important one is just using RSA key-pair in an incorrect way.