JAVA отдельный ключ AES, вектор инициализации и данные из зашифрованного файла с этими 3 комбинациями, используемыми во время шифрования - PullRequest
0 голосов
/ 16 апреля 2019

Я создал зашифрованный файл с комбинацией AES-шифрования, вектора инициализации и исходных данных. Таким образом, мой зашифрованный файл содержит более 3 элементов в зашифрованном виде. Теперь во время дешифрования я застреваю при разделении всех этих трех элементов снова, более того, мне приходится использовать длину ключа AES, жестко закодированную во время дешифрования, которая была сгенерирована во время шифрования.

public static void encrypt() throws Exception {

        // RSA with ECB mode
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, generatePublicKey(readKeysFromFile("My_public.pub")));

        // AES key generator
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128, srandom);
        SecretKey skey = kgen.generateKey();

        // Initialization vector 16 byte
        byte[] iv = new byte[128/8];
        srandom.nextBytes(iv);
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {
            {
                byte[] b = cipher.doFinal(skey.getEncoded());
                out.write(b);
                System.err.println("AES Key Length: " + b.length);
            }

            out.write(iv);
            System.err.println("IV Length: " + iv.length);

            Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
            ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);

            File inputDataFile = new File("dataFile.xml");
            try (DataInputStream in = new DataInputStream(new FileInputStream(inputDataFile))) {
                byte[] buffer = new byte[(int)inputDataFile.length()];
                in.readFully(buffer);
                in.close();
                byte[] encryptedData = ci.doFinal(buffer);
                out.write(encryptedData);
                out.close();
            }
        }

    }


public static void decryptRSAAES() throws Exception {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, generatePrivateKey(readKeysFromFile("My_private.key")));

        File file2 = new File("dataFile.enc");
        RandomAccessFile raf = new RandomAccessFile(file2, "r");

        // length of AES key 
        byte[] c = new byte[384];

        // read the AES key from file
        raf.read(c, 0 , 384);
        byte[] fileContent = Files.readAllBytes(file2.toPath());
        byte[] keyb = cipher.doFinal(c);
        SecretKeySpec skey = new SecretKeySpec(keyb, "AES");

        // read the initializatoin vector
        byte[] iv = new byte[128/8];
        raf.seek(384);
        raf.read(iv);
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        raf.seek(400);

        Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
        try (FileOutputStream out = new FileOutputStream("decryptedFileTest"+".xml")){

            byte[] decryptedData = ci.doFinal(fileContent);
            out.write(decryptedData);
            out.close();
            //processDecryptFile(ci, in, out);
        }
    }

Фактический результат: дешифрованный файл создается с использованием ключа AES и исходных простых данных

Ожидаемый результат: записывать только исходные простые данные в вывод, удаляя AES и вектор инициализации.

1 Ответ

1 голос
/ 16 апреля 2019

Давайте упростим это и используем функции, недавно появившиеся в классах InputStream Java:

public static void encrypt(RSAPublicKey publicKey) throws Exception {

    try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {

        // --- RSA using PKCS#1 v1.5 padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        // --- AES key generator
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        SecretKey skey = kgen.generateKey();

        // --- write encrypted AES key
        byte[] encryptedSKey = cipher.doFinal(skey.getEncoded());
        out.write(encryptedSKey);

        // --- Initialization vector 16 byte
        SecureRandom srandom = new SecureRandom();
        byte[] iv = new byte[128/8];
        srandom.nextBytes(iv);
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        // --- write IV
        out.write(iv);


        // --- initialize AES cipher
        Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);

        // --- convert file by copying to memory
        try (FileInputStream in = new FileInputStream("dataFile.xml")) {
            byte[] buffer = in.readAllBytes();
            byte[] encryptedData = ci.doFinal(buffer);
            out.write(encryptedData);
        }
    }
}


public static void decrypt(RSAPrivateKey privateKey) throws Exception {

    try (FileInputStream in = new FileInputStream("dataFile" + ".enc")) {

        // --- RSA using PKCS#1 v1.5 padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        // --- read encrypted AES key
        byte[] encryptedSKey = in.readNBytes(determineEncryptionSizeInBytes(privateKey));

        byte[] decryptedSKey = cipher.doFinal(encryptedSKey);
        SecretKey skey = new SecretKeySpec(decryptedSKey, "AES");

        // --- Initialization vector 16 byte
        byte[] iv = in.readNBytes(128 / Byte.SIZE);
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        // --- initialize AES cipher
        Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ci.init(Cipher.DECRYPT_MODE, skey, ivspec);

        // --- convert file by copying to memory
        File outputDataFile = new File("dataFile.xml2");
        try (FileOutputStream out = new FileOutputStream(outputDataFile)) {
            byte[] buffer = in.readAllBytes();
            byte[] decryptedData = ci.doFinal(buffer);
            out.write(decryptedData);
        }
    }
}

private static int determineEncryptionSizeInBytes(RSAPrivateKey privateKey) {
    return (privateKey.getModulus().bitLength() + Byte.SIZE - 1) / Byte.SIZE;
}

public static void main(String[] args) throws Exception {
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(384 * Byte.SIZE);
    KeyPair pair = kpg.generateKeyPair();
    encrypt((RSAPublicKey) pair.getPublic());
    decrypt((RSAPrivateKey) pair.getPrivate());
}

Как видите, код теперь очень похож на зеркальное отображение. Я просто скопировал код шифрования и затем внес в него изменения. Как вы можете видеть, теперь он использует меньше классов, полагаясь на InputStream#readAllBytes() (начиная с Java 9) и InputStream#readNBytes() (начиная с Java 11).

Обратите внимание, что обычно вы хотите передавать файл, используя меньший буфер. Поскольку весь открытый текст и зашифрованный текст в настоящее время буферизуются, ваше приложение использует гораздо больше памяти, чем требуется. Для шифрования данных с использованием потоков вы можете использовать CipherInputStream и CipherOutputStream.

Нет необходимости говорить, что обработка исключений нуждается в улучшении, я просто нашел лучший способ решить вашу текущую проблему. Пожалуйста, взгляните еще раз, когда у вас все работает (работайте, работайте правильно, оптимизируйте).

...