Рассмотрим следующий код PHP:
<?php
$key = "1234567812345678";
$iv = "1234567812345678";
$data = "Test string";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
$key,
$data,
MCRYPT_MODE_CBC,
$iv);
print "Encoded1: " . base64_encode($encrypted) . "\n";
$key = "12345678123456781234567812345678";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
$key,
$data,
MCRYPT_MODE_CBC,
$iv);
print "Encoded2: " . base64_encode($encrypted) . "\n";
При запуске это дает вывод:
Encoded1: iz1qFlQJfs6Ycp+gcc2z4w==
Encoded2: n3D26h/m8CSH0CE+z6okkw==
Обратите внимание, что я украл первый бит кода из PHP Java AES CBC Шифрование Различные результаты
Теперь — вот вопрос:
В первом случае передаваемый ключ представлял собой строку из 16 символов. Если каждый из отдельных символов интерпретируется как 8-битная величина, это дает 128-битный размер ключа, который можно ожидать. Действительно, код Java, который находится на странице StackOverflow, на которую я ссылался выше, делает именно это и получает тот же результат, что и PHP.
Во втором звонке mcrypt_encrypt
выше, я удвоил длину ключа. mcrypt_encrypt
принимает это с радостью, но выдает другой зашифрованный вывод, чем в первом случае. Поэтому ясно, что он считает это другим ключом — он, например, не берет только первые 128 бит и отбрасывает все прошедшие.
Итак, как же mcrypt_encrypt
обработать строку входного ключа, чтобы придумать 128-битный ключ, который MCRYPT_RIJNDAEL_128
алгоритм требует?
Если это имеет какое-то значение, особенно меня интересует случай, когда передается 32-символьная строка, как в моем втором примере — мне нужно создать соответствующую подпрограмму дешифрования (в Java), поэтому мне нужно выяснить, как ключ фактически генерируется в этом случае. На странице, которую я привел, есть очень хороший Java-код (который работает со всеми моими тестовыми примерами) — мне просто не хватает правильного набора ключевых байтов.
Есть два важных параметра для алгоритма Rijndael. Здесь размер ключа (128-бит, 192-бит и 256-бит), а затем есть размер блока (128-битный, 192-битный и 256-битный). 128
в MCRYPT_RIJNDAEL_128
относится к размеру блока. Размер ключа является переменным.
Когда вы передаете ключи различной длины в MCrypt, он автоматически выберет соответствующий размер ключа, поэтому вы не можете и не можете его установить. MCRYPT_RIJNDAEL_128
это AES (AES-128, AES-192, AES-256). MCRYPT_RIJNDAEL_192
а также MCRYPT_RIJNDAEL_256
больше не AES.
Если код Java выдал результат сопоставления для 128-битного ключа, то он также выдаст результат сопоставления для 256-битного ключа.
MCrypt немного странный. До версии PHP 5.6.0 она имела бы любую длину ключа, а не только 128-битную, 192-битную или 256-битную. Ключ будет заполнен 0x00 байтами до следующей допустимой длины ключа.
Поскольку Java не поддерживает ZeroPadding из коробки, вы должны использовать правильную схему заполнения, такую как заполнение PKCS # 5 / PKCS # 7 в PHP. Этот ответ имеет очень хорошую реализацию этого.
Других решений пока нет …