Расшифровка Rijndael / AES с C # на PHP - PullRequest
1 голос
/ 07 декабря 2011

У меня есть следующий код в C #

string s = "hellowld";
byte[] bytes = new UnicodeEncoding().GetBytes(s);
FileStream stream = new FileStream(inputFile, FileMode.Open);
RijndaelManaged managed = new RijndaelManaged();
CryptoStream stream2 = new CryptoStream(stream, managed.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
FileStream stream3 = new FileStream(outputFile, FileMode.Create);
try
{
    int num;
    while ((num = stream2.ReadByte()) != -1)
    {
        stream3.WriteByte((byte) num);
    }
 [....]

Этот фрагмент кода расшифровывает определенный файл и выводит расшифрованную версию. В методе CreateDecryptor из RijndaelManaged я использую пароль как KEY, а также как IV.

Я нашел здесь некоторый код в stackoverflow для PHP, но если я попытаюсь дать ключу и iv тот же массив байтов, как в C #, ничего не произойдет.

$Pass = "hellowld";
$Clear = file_get_contents('./file.dat', FILE_USE_INCLUDE_PATH);

$bytePass=array();
$i = 0;
foreach (str_split($Pass) as $value) {
    $bytePass[$i]=ord($value);
    $i++;
}

echo decryptAES($Clear,$bytePass,$bytePass);

function decryptAES($content,$iv, $key,$aes) {

// Setzt den Algorithmus
switch ($aes) {
    case 128:
       $rijndael = 'rijndael-128';
       break;
    case 192:
       $rijndael = 'rijndael-192';
       break;
    default:
       $rijndael = 'rijndael-256';
}

// Setzt den Verschlüsselungsalgorithmus
// und setzt den Output Feedback (OFB) Modus
$cp = mcrypt_module_open($rijndael, '', 'ofb', '');

 // Ermittelt die Anzahl der Bits, welche die Schlüssellänge des Keys festlegen
$ks = mcrypt_enc_get_key_size($cp);

// Erstellt den Schlüssel, der für die Verschlüsselung genutzt wird
$key = substr(md5($key), 0, $ks);

// Initialisiert die Verschlüsselung
mcrypt_generic_init($cp, $key, $iv);

// Entschlüsselt die Daten
$decrypted = mdecrypt_generic($cp, $content);

// Beendet die Verschlüsselung
mcrypt_generic_deinit($cp);

// Schließt das Modul
mcrypt_module_close($cp);

return trim($decrypted);

}

Мне действительно нужна помощь, как правильно создать код на PHP. Нет необходимости выводить файл на PHP, достаточно строки.

UPDATE : Метод шифрования C # RijndaelManaged по умолчанию - AES-128-CBC. Я изменил свой PHP-код на этот модуль mcrypt ( метод шифрования C # по умолчанию )

ОБНОВЛЕНИЕ 2: Мне удалось создать Java Decryptor, который привел меня к другому. PHP должен использовать заполнение PKCS7.

1 Ответ

1 голос
/ 08 декабря 2011

Ваш код C # на самом деле не выглядит безопасным, поэтому, если вы можете его изменить, см. Ниже несколько советов.Вот ваш PHP-код, модифицированный таким образом, чтобы он мог быть эквивалентен приведенному коду C #.

function decryptAES128CBC($content,$iv, $key) {

    // AES is Rijndael-128
    $rijndael = 'rijndael-128';

    // key size is 128 bit = 16 bytes
    $ks = 16;

    // CBC mode, not OFB
    $cp = mcrypt_module_open($rijndael, '', 'cbc', '');

    // pad key and IV by zeros (this is not a good idea)
    $key = str_pad($key, $ks, "\0");
    $iv = str_pad($key, $iv, "\0");

    // initialize the decryptor with key and IV
    mcrypt_generic_init($cp, $key, $iv);

    // the actual work
    $decrypted = mdecrypt_generic($cp, $content);

    // clean up
    mcrypt_generic_deinit($cp);
    mcrypt_module_close($cp);

    // remove padding, see below
    return unpad($decrypted);
}

Последний unpad предназначен для удаления заполнения, которое, вероятно, было добавлено функцией шифрования для увеличения.размер сообщения до полного количества блоков.Заполнением по умолчанию, используемым RijndaelManaged, является PKCS7-заполнение, которое добавляет количество байтов (от 1 до 16), каждый из которых равен количеству добавленных байтов.В реальной реализации вы должны после дешифрования проверить, что заполнение допустимо (то есть, что все эти байты имеют одно и то же значение), но для «быстрого и грязного» вы можете просто использовать что-то, что проверяет последний байт и удаляет это количество байтов.См. комментарии к mcrypt_decrypt для примера.

Если вы можете изменить свой код C #:

  • Обратите внимание, что этообычно не очень хорошая идея использовать фиксированное значение (на ключ) в качестве вектора инициализации, и использование самого ключа в качестве вектора инициализации также не годится.Используйте случайный вектор инициализации (отправленный вместе с сообщением) или посмотрите следующую точку.

  • Кроме того, обычно вы не хотите использовать (довольно короткий) пароль непосредственно какключ, но вместо этого используйте более длинную фразу-пароль и хэшируйте ее с помощью соли (включенной в сообщение) для получения ключа.Если вы сделаете это, вы также можете получить вектор инициализации из тех же двух частей данных (но таким образом, что они будут разными, используя функцию вывода ключа).Чтобы избежать перебора вашего пароля из зашифрованного файла, используйте здесь функцию медленного хеширования (PBKDF-2 или bcrypt).

...