Шифрование AES в Java для соответствия с выходом C # - PullRequest
1 голос
/ 06 марта 2019

Я пытаюсь выполнить шифрование AES с использованием JAVA, я сделал несколько попыток, перепробовал много кодов и внес много изменений, чтобы наконец добраться до места, где мой зашифрованный текст совпадает с зашифрованным текстом, созданным с использованием кода C #, НО ЧАСТИЧНО.Последний блок из 32 бит отличается.У меня нет доступа к коду C #, так как это сторонняя служба.Кто-нибудь может подсказать, что мне не хватает?

Упомянутые условия должны использовать:

Использовать 256-битное шифрование AES в режиме CBC и с PKCS5заполнение для шифрования всей строки запроса с использованием вашего первичного ключа и вектора инициализации.(Не включайте дайджест сообщения в строку запроса.) Первичный ключ - это шестнадцатеричная строка из 64 цифр, а вектор инициализации - шестнадцатеричная строка из 32 цифр.

Используемые мной примеры значений:

Aes_IV = 50B666AADBAEDC14C3401E82CD6696D4

Aes_Key = D4612601EDAF9B0852FC0641DC2F273E030FFFFFFDFFDFFFFFFFFBFBFFFFFBBFBBFXBXXXXXXXXXXXXXXXXXXXXXXXXXXF IDF0606105BF

Plain_Text = ss = brock & pw = 123456 & ts = 20190304234431 ( input )

Encrypted_Text = 7643C7B400B9A6A2AD0FCFC40AC1B11E51A038A32C84E5560D92C0C49B3B7E0 A072AF44AADB62FA66F047EACA5C6A018 ( выход )

Мой выход = 7643C7B400B9A6A2AD0FCFC40AC1B11E51A038A32C84E5560D92C0C49B3B7E0 A38E71E5C846BAA6C31F996AB05AFD089

public static String encrypt( String keyMaterial, String unencryptedString, String ivString ) {
    String encryptedString = "";
    Cipher cipher;
    try {
        byte[] secretKey = hexStrToByteArray( keyMaterial );
        SecretKey key = new SecretKeySpec( secretKey, "AES" );
        cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
        IvParameterSpec iv;
        iv = new IvParameterSpec( hexStrToByteArray( ivString ) );
        cipher.init( Cipher.ENCRYPT_MODE, key, iv );
        byte[] plainText = unencryptedString.getBytes( "UTF-8") ;
        byte[] encryptedText = cipher.doFinal( plainText );
        encryptedString = URLEncoder.encode(byteArrayToHexString( encryptedText ),"UTF-8");
    }
    catch( InvalidKeyException | InvalidAlgorithmParameterException | UnsupportedEncodingException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException e ) {
        System.out.println( "Exception=" +e.toString() );
    }
    return encryptedString;
}

Я использовал это для преобразования.

public static byte[] hexStrToByteArray ( String input) {
    if (input == null) return null;
    if (input.length() == 0) return new byte[0];

    if ((input.length() % 2) != 0)
        input = input + "0";

    byte[] result = new byte[input.length() / 2];
    for (int i = 0; i < result.length; i++) {
        String byteStr = input.substring(2*i, 2*i+2);
        result[i] = (byte) Integer.parseInt("0" + byteStr, 16);
    }
    return result;
}
public static String byteArrayToHexString(byte[] ba) {
    String build = "";
    for (int i = 0; i < ba.length; i++) {
        build += bytesToHexString(ba[i]);
    }
    return build;
}
    public static String bytesToHexString ( byte bt) {
    String hexStr ="0123456789ABCDEF";
    char ch[] = new char[2];
    int value = (int) bt;

    ch[0] = hexStr.charAt((value >> 4) & 0x000F);
    ch[1] = hexStr.charAt(value & 0x000F);

    String str = new String(ch);

    return str;
}

Есть предложения, что мне делать, чтобы соответствовать выводам?

1 Ответ

0 голосов
/ 09 марта 2019

Если отличается только последний блок заполнения ECB / CBC, то вы можете быть уверены, что используется другое заполнение блочного шифра. Чтобы проверить, какой заполнитель используется, вы можете попробовать (как это сделал Топако в комментариях под вопросом) или вы можете расшифровать зашифрованный текст без заполнения. Для Java это будет "AES/CBC/NoPadding".

Так что, если вы сделаете это, учитывая ключ (и IV), вы получите следующий вывод в шестнадцатеричном формате:

73733D62726F636B2670773D3132333435362674733D3230313930333034323334343331000000000000000000000000

Очевидно, что это нулевое заполнение.

Заполнение нулями имеет один большой недостаток: если ваш зашифрованный текст заканчивается нулевым байтом, то этот байт можно рассматривать как заполнение и исключение из результата. Обычно это не проблема для открытого текста, состоящего из строки ASCII или UTF-8, но это может быть сложнее для двоичного вывода. Конечно, здесь мы будем предполагать, что строка не использует нулевой терминатор, который, как ожидается, будет присутствовать в зашифрованном текстовом виде.

Есть еще один, меньший недостаток: если ваш обычный текст точно соответствует размеру блока, то заполнение нулями достаточно нестандартно, поэтому возможны два сценария:

  1. заполнение всегда применяется и его необходимо удалить, что означает, что если размер открытого текста ровно в несколько раз превышает размер блока, который по-прежнему равен полному блоку заполнения (так что для AES у вас будет 1..16 байтов с нулевым значением в качестве заполнения);

  2. заполнение применяется только в случае строгой необходимости, что означает, что заполнение не применяется, если размер открытого текста ровно в несколько раз превышает размер блока (поэтому для AES у вас будет 0..15 нулевых байтов) в качестве набивки).

Так что в настоящее время для шифрования вам, возможно, придется проверить, какое из них ожидается / принято. Например. Bouncy Castle - который доступен для C # и Java - всегда (не) пэды, тогда как ужасная библиотека PHP / mcrypt только пэды там, где требуется.

Конечно, вы всегда можете выполнить свой собственный отступ, а затем использовать "NoPadding" для Java. Помните, что вы никогда не распаковываете больше 16 байтов.

Общее предупреждение: шифрование без аутентификации не подходит для безопасности в транспортном режиме.

...