Что такое ключ дешифрования для java, когда ключ является целым числом в php

Существует существующая система PHP (разработанная другой компанией), которая имеет следующий код шифрования.

$mopen = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', 'cfb', '');
mcrypt_generic_init($mopen, keygenerator(), $iv);
$cipherText = mcrypt_generic($mopen, $imageContent);

В приведенном выше коде вторая строка, второй параметр — тип возврата key.keygenerator() — int между 10-99.

mcrypt_generic_init (ресурс $td, строка $key, строка $iv): int

Мне нужно расшифровать полученные файлы с помощью java. Я использую библиотеку bouncycastle, и мне нужно указать ключ в виде массива байтов. Если генератор ключей () генерирует 32 в качестве ключа. Как я могу указать его в java как жестко закодированное значение. Если я использую следующий код.

String key = "32";
cipher.init(cryptoType, new ParametersWithIV(new KeyParameter(key.getBytes()), iv.trim().getBytes()));

Это дает мне следующую ошибку.

Исключение в потоке main java.lang.IllegalArgumentException: длина ключа не 128/160/192/224/256 бит.


person Yasitha Bandara    schedule 23.09.2020    source источник
comment
32 содержит два символа. Символы содержат два байта. Поэтому вы используете 16-битный ключ, который не поддерживается. Однако обратите внимание, что длина зависит от кодировки по умолчанию.   -  person dan1st    schedule 23.09.2020
comment
да, я получил это. но как добавить ключевое дополнение.   -  person Yasitha Bandara    schedule 23.09.2020
comment
Моя вина в последнем комментарии. Минимум один байт, но может быть и больше, в зависимости от кодировки и используемого символа. Вы можете создать отступ, например, создав большую строку.   -  person dan1st    schedule 23.09.2020
comment
да, сначала я должен выяснить, как PHP использует заполнение клавиш. В противном случае это будет не тот же ключ. Вы, ребята, представляете, что произошло в mcrypt_generic_init() в php.   -  person Yasitha Bandara    schedule 23.09.2020
comment
Не связанное с этим замечание: ограничение ключа целым числом фактически делает его длиной всего 32 бита. Это слишком мало для чего-то серьезного.   -  person Henry    schedule 23.09.2020
comment
Как насчет того, чтобы распечатать ключ, чтобы увидеть реальное значение и ничего не предполагать? Пожалуйста, отредактируйте свое сообщение и добавьте ключ и iv, которые используются (лучше всего - для последующей совместимости с кодом Java - кодировка Base64.   -  person Michael Fehr    schedule 23.09.2020
comment
Тип возвращаемого значения – целое число. keygenerator() возвращает числа или строки? С числами также необходимо учитывать преобразования (например, восьмеричное/десятичное, экспоненциальное представление больших чисел и т. д.). Для цифр (числа в виде строк) было бы проще: PHP дополняет значениями 0 до требуемой длины ключа. MCRYPT_RIJNDAEL_256 поддерживает 3 длины ключа 16, 24 и 32 байта. Если длина ключа находится между ними, PHP переходит к следующей длине ключа с нулевыми значениями.   -  person user 9014097    schedule 23.09.2020
comment
keygenerator() возвращает числа, а не строки. Я имею в виду int, как сказано в руководстве по PHP.   -  person Yasitha Bandara    schedule 23.09.2020
comment
Тогда имело бы смысл опубликовать реализацию keygenerator() или хотя бы сделать некоторые уточнения, например. о диапазоне значений.   -  person user 9014097    schedule 23.09.2020
comment
пожалуйста, воспринимайте это как простое. думаю, генератор ключей () возвращает жестко закодированное значение 32, которое является целым (числом).   -  person Yasitha Bandara    schedule 23.09.2020
comment
Короткие целые числа, такие как 32, преобразуются в строки без каких-либо изменений. На самом деле это должно означать, что PHP использует 16-байтовый ключ, дополненный 14 0-значениями для значения 32, т.е. нет разницы между $key = 32, $key = "32" или $key = "32\0\0\0\0\0\0\0\0\0\0\0\0\0\0". В Java вы должны использовать последнее, то есть шестнадцатеричное кодирование: 33320000000000000000000000000000. Конечно, это ужасно небезопасно.   -  person user 9014097    schedule 23.09.2020
comment
да, это небезопасно. но мы ничего не можем сделать. это существующая система PHP (разработанная другой компанией). нам нужно перенести файлы в нашу систему и расшифровать.   -  person Yasitha Bandara    schedule 23.09.2020


Ответы (2)


MCRYPT_RIJNDAEL_256 поддерживает ключи размером 16, 24 и 32 байта. Если размер ключа находится между ними, заполнение выполняется нулевыми значениями до тех пор, пока не будет достигнута следующая допустимая длина ключа.
Если длина ключа представляет собой двузначное число, следующий допустимый размер ключа составляет 16 байт, поэтому выполняется заполнение. с 14 0-значениями.
То же самое относится к IV, длина которого должна соответствовать размеру блока (32 байта для Rijndael-256). Если он короче, он также дополняется 0-значениями (хотя здесь обычно отображается предупреждение).
Если ключ слишком длинный (больше 32 байт), он будет усечен. То же самое относится и к IV.

Следующий код PHP демонстрирует это:

function encrypt($key, $iv){
    $mopen = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', 'cfb', '');
    mcrypt_generic_init($mopen, $key, $iv);
    $cipherText = mcrypt_generic($mopen, "The quick brown fox jumps over the lazy dog");
    print(base64_encode($cipherText) . "\n");
}

$key = 32; // 0-padded to 16 bytes
$iv = 32;  // 0-padded to 32 bytes (Rijndael-256 blocksize), mostly a warning is displayed
encrypt($key, $iv); // Dgfd2xT2NQ1ULob3mOX+JBPQo57JUIxabtt+TX8wnzYWhKtt/6ltY2Z/yA==

$key = "32";
$iv = "32";
encrypt($key, $iv); // Dgfd2xT2NQ1ULob3mOX+JBPQo57JUIxabtt+TX8wnzYWhKtt/6ltY2Z/yA==

$key = "32\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
$iv = "32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
encrypt($key, $iv); // Dgfd2xT2NQ1ULob3mOX+JBPQo57JUIxabtt+TX8wnzYWhKtt/6ltY2Z/yA==

В коде Java должны быть указаны точный ключ и размер IV. Обратите внимание, что CFB — это режим потокового шифрования, поэтому заполнение не используется. PHP применяет CFB-8 (CFB в 8-битном режиме), который должен быть соответствующим образом указан в коде Java. Следующий код Java/BouncyCastle расшифровывает зашифрованный текст:

import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.RijndaelEngine;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
...
String ciphertextB64 = "Dgfd2xT2NQ1ULob3mOX+JBPQo57JUIxabtt+TX8wnzYWhKtt/6ltY2Z/yA==";
byte[] ciphertext = Base64.getDecoder().decode(ciphertextB64);
byte[] key = "32\0\0\0\0\0\0\0\0\0\0\0\0\0\0".getBytes(StandardCharsets.UTF_8);         
byte[] iv = "32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".getBytes(StandardCharsets.UTF_8);     

BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(new CFBBlockCipher(new RijndaelEngine(256), 8)); // CFB in 8 bit mode
CipherParameters cipherParams = new ParametersWithIV(new KeyParameter(key), iv);
bufferedBlockCipher.init(false, cipherParams);        

byte[] decryptedBuffer = new byte[bufferedBlockCipher.getOutputSize(ciphertext.length)];
int processed = bufferedBlockCipher.processBytes(ciphertext, 0, ciphertext.length, decryptedBuffer, 0);
processed += bufferedBlockCipher.doFinal(decryptedBuffer, processed);

System.out.println(new String(decryptedBuffer, 0, processed, StandardCharsets.UTF_8)); // The quick brown fox jumps over the lazy dog      
person user 9014097    schedule 23.09.2020

Я принимаю ответ Топако. Но то, как я предоставил ключ, немного отличается.

String key = "33320000000000000000000000000000";
byte[] byteKey = new BigInteger(key,16).toByteArray();
cipher.init(cryptoType, new ParametersWithIV(new KeyParameter(byteKey), iv.trim().getBytes()));
person Yasitha Bandara    schedule 23.09.2020
comment
Кодировка, используемая для ключа и IV, зависит от требований/предпочтений. Я выбрал кодировку UTF-8, потому что это простой способ проиллюстрировать расширение ключа PHP, которому здесь уделяется основное внимание. Вместо UTF8 конечно можно использовать любую (желаемую) кодировку, шестнадцатеричную (как в вашем коде), более эффективную Base64 и т.д. - person user 9014097; 23.09.2020