RSA и AES для шифрования и дешифрования простого текста (проверка ключа) - PullRequest
0 голосов
/ 05 июня 2018

Я хочу задать вам вопрос о безопасности ключа в Java.Мой код использует RSA и AES для шифрования и дешифрования обычного текста.И я хочу использовать свой собственный пароль в качестве личного ключа (AES) для ключа проверки (RSA).Потому что RSA генерирует случайный открытый и закрытый ключи.(В реальном случае: закрытый ключ вводится пользователем и хранилищем открытого ключа в базу данных для проверки.)
Этот код находится в поиске работы, но я хочу знать, правильный ли этот код или нет?Пожалуйста посоветуй!Спасибо.


Мой процесс:
1. сгенерируйте симметричный ключ
2. Зашифруйте данные с помощью симметричного ключа
3. Зашифруйте симметричный ключ с помощью rsa
4. отправить зашифрованный ключ и данные
5. Расшифровать зашифрованный симметричный ключ с помощью rsa
6. Расшифровать данные с помощью симметричного ключа
7. Выполнено

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 Ответ

0 голосов
/ 05 июня 2018

Вы псевдо-шаги верны, но ваше описание нет.Например, вы обычно сохраняете RSA закрытый ключ и распространяете RSA открытый ключ.

Но есть несколько предложений по созданию лучшего кода.

  1. Я предлагаю использоватьPKCS5 для создания секретных ключей на основе пароля, а не простого хэша.Java PBEKeySpec - это класс для генерации таких секретных ключей.Вот небольшой пример кода, который вы можете использовать для своей подпрограммы setKey() (настройте ее по своему усмотрению):

    SecretKeyFactory skf = SecretKeyFactory.getInstance("AES");
    SecretKey key = skf.generateSecret(new PBEKeySpec(password.getBytes("UTF-8"), salt, 10000));
    
  2. Никогда не используйте режим работы ECB для шифрования данных,В худшем случае используйте CBC с рандомизированным IV.

  3. Вы ошиблись.RSA закрытый ключ хранится на сервере закрытым, но RSA открытый ключ свободно распространяется между клиентами (обычно).Вы делаете это другим способом.
  4. Это всего лишь предложение, но я думаю, что лучше использовать RSA/ECB/OAEPWithSHA-256AndMGF1Padding, а не RSA/ECB/PKCS1Padding для RSA заполнения.Но я думаю, что в этом нет необходимости.
  5. В общем, вы должны добавить хеш или HMAC для аутентификации ваших зашифрованных данных.Но у вас нет никакого механизма аутентификации прямо сейчас.

Обновление: Исходя из конструкции вашего механизма, вы не можете безопасно добавить метод аутентификации для обнаружения активных атак (например, «человек посередине»).Проверьте комментарии от Мартена тоже.

Это проблемы, которые я обнаружил.Наиболее важным из них является просто неправильное использование пары ключей RSA.

...