Ключ шифрования OpenSSL и IV отличается от ключа, сгенерированного из программы Java - PullRequest
0 голосов
/ 30 сентября 2018

Я изменяю программу Java для расшифровки пароля, зашифрованного OpenSSL.Теперь я получаю следующее исключение

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:991)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2222)
    at test.TestAesDecrypt.main(TestAesDecrypt.java:107)

При просмотре различных ссылок понял, что это из-за разницы в сгенерированном ключе.Ключ и iv, используемые в OpenSSL и программе, отличаются.Они создаются внутри OpenSSL и программой.

Если я жестко закодировал ключ OpenSSL и iv для программирования, расшифровка работает.

Пароль для шифрования - helloworld!

Ключ доступа - TIKpasskey001002.Оригинальная программа от здесь .

Как я могу разрешить то же самое?

C:\WINDOWS\system32>C:\OpenSSL-Win64\bin\openssl.exe aes-256-cbc -salt -in D:\Misc\tryouts\encryption3\password.txt -out D:\Misc\tryouts\encryption3\enpassfile.encr -pass file:D:\Misc\tryouts\encryption3\passkeyfile.txt -p
salt=E68886B9E9C2ACD8
key=5F9A0BAF409AF8F9B9FECA9008508A91CEEE86B3A334EC6E00D08A7A8B8372C5
iv =FF3EC566671077A5CC7F0695F8CC590B

C:\WINDOWS\system32>C:\OpenSSL-Win64\bin\openssl.exe aes-256-cbc -d -salt -in D:\Misc\tryouts\encryption3\enpassfile.encr -out D:\Misc\tryouts\encryption3\decpassfile.dcr -pass file:D:\Misc\tryouts\encryption3\passkeyfile.txt -p
salt=E68886B9E9C2ACD8
key=5F9A0BAF409AF8F9B9FECA9008508A91CEEE86B3A334EC6E00D08A7A8B8372C5
iv =FF3EC566671077A5CC7F0695F8CC590B

Values from Java Program:
Values from Java Program:
Encrypted cipher: 53616C7465645F5FE68886B9E9C2ACD84CB17D3CA8FEFC54E189766B97E815BD
Encrypted cipher via Apache Commons Hex: 53616c7465645f5fe68886b9e9c2acd84cb17d3ca8fefc54e189766b97e815bd
Pass Key: 54494B706173736B6579303031303032
Pass Key: TIKpasskey001002

keyValue: 6F16A5F5DA36A6A479CEBFAB6A8258D490A0A3994D204AC1AFD338AF7B4D4306
keyValue via Apache Commons Hex: 6f16a5f5da36a6a479cebfab6a8258d490a0a3994d204ac1afd338af7b4d4306
IV: E19C6128D0851D09F7E01F34061C88E3
IV via Apache Commons Hex: e19c6128d0851d09f7e01f34061c88e3

Программа

import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;

public class TestAesDecrypt {

    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[] getBytes(String inputFile) {

        String outputFile = inputFile;
        File infile = new File(outputFile);

        byte[] readBytes = null;
        try {

            readBytes = IOUtils.toByteArray(new FileInputStream(infile));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return readBytes;
    }

    public static void main(final String[] args) throws Exception {

        final byte[] pass = getBytes("D:\\\\Misc\\\\tryouts\\\\encryption3\\\\passkeyfile.txt");
        final byte[] magic = "Salted__".getBytes(StandardCharsets.US_ASCII);
        final String inFile = "D:\\Misc\\tryouts\\encryption3\\enpassfile.encr";

        final byte[] inBytes = Files.readAllBytes(Paths.get(inFile));// decoder.decode(source);

        System.out.println("Encrypted cipher: " + bytesToHex(inBytes));
        System.out.println("Encrypted cipher via Apache Commons Hex: " + Hex.encodeHexString(inBytes));

        System.out.println("Pass Key: " + bytesToHex(pass));
        System.out.println("Pass Key: " + new String(pass));

        final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, magic.length);
        if (!Arrays.equals(shouldBeMagic, magic)) {
            System.out.println("Bad magic number");
            return;
        }

        final byte[] salt = Arrays.copyOfRange(inBytes, magic.length, magic.length + 8);

        final byte[] passAndSalt = concat(pass, salt);

        byte[] hash = new byte[0];
        byte[] keyAndIv = new byte[0];
        for (int i = 0; i < 3; i++) {
            final byte[] data = concat(hash, passAndSalt);
            final MessageDigest md = MessageDigest.getInstance("MD5");
            hash = md.digest(data);
            keyAndIv = concat(keyAndIv, hash);
        }

        final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
        final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);

        /*
         * Key and IV from OpenSSL command -p 
         * final byte[] keyValue =
         * javax.xml.bind.DatatypeConverter.parseHexBinary(
         * "5F9A0BAF409AF8F9B9FECA9008508A91CEEE86B3A334EC6E00D08A7A8B8372C5"); final
         * byte[] iv = javax.xml.bind.DatatypeConverter.parseHexBinary(
         * "FF3EC566671077A5CC7F0695F8CC590B");
         */

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");

        System.out.println("IV: " + bytesToHex(iv));
        System.out.println("IV via Apache Commons Hex: " + Hex.encodeHexString(iv));

        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        /**** EXCEPTION OCCURS HERE START *****/
        final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
        /**** EXCEPTION OCCURS HERE STOP *****/
        final String clearText = new String(clear, StandardCharsets.ISO_8859_1);
        System.out.println(clearText);
    }

    private static byte[] concat(final byte[] a, final byte[] b) {
        final byte[] c = new byte[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }
}

1 Ответ

0 голосов
/ 01 октября 2018

В дополнение к удалению CRLF из значения пароля согласно комментарию reinier :

Вы, очевидно, используете OpenSSL 1.1.0 или выше, что изменил хеш , используемый по умолчанию в enc PBKDF / PBE, с MD5 на SHA256 .См. man enc (может потребоваться специальный раздел, такой как 1ssl) в системе Unixy, которой, по-видимому, нет, или в Интернете в разделе ИСТОРИЯ, и, возможно, Функция пароля к ключу, совместимая с OpenSSLкоманды? .Обратите внимание, что в SHA256 вам нужно только 2 блока, а не 4 в PBKDF.

К вашему сведению, вам не нужно копировать фрагменты массива;и SecretKeySpec, и IvParameterSpec имеют перегрузки конструктора, которые используют часть массива байтов, а не весь массив.А ключ AES-256 составляет 32 байта (по крайней мере, в Java), и это то, что вы кодировали, хотя и комментировали по-другому.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...