Python AES CTR до PHP - PullRequest
       18

Python AES CTR до PHP

1 голос
/ 29 апреля 2020

Я пытаюсь сделать это AES CTR шифрование (которое отлично работает в python) в php

работает python

from Crypto.Cipher import AES
import Crypto.Util.Counter
from Crypto.Util import Counter
key = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
encryptkey = bytes(key)
ctr = Counter.new(128)
crypto = AES.new(encryptkey, AES.MODE_CTR, counter=ctr)
text = "E5ZA,K2JV,PA01,J1W3,386S,AGVZ,9O9T,F640,FR20,40LX,D443,1913,031V"
bytetext = bytes(text,'utf-8')
encryptedtext = crypto.encrypt(bytetext)
encryptedtext = encryptedtext.hex()
print(encryptedtext)

мой php попытаться

<?php
function strToHex($string){
    $hex='';
    for ($i=0; $i < strlen($string); $i++){
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}

$bytes = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
$lkey= implode(array_map("chr", $bytes));
$method = "AES-256-CTR";
$password = $lkey;
$data = array("E5ZA", "K2JV", "PA01", "J1W3", "386S", "AGVZ", "9O9T", "F640", "FR20", "40LX", "D443", "1913", "031V");
$string= implode(array_map("chr", $data));
$valid = openssl_encrypt ($string, $method, $password);
echo strToHex($valid)
?>

ошибка и неправильный результат я получаю

Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in /test.php on line 16
387041417471684a6c74437032356f5477673d3d

ожидаемый ответ:

b5682cef66f2adaff0dacb7078f31a773feb86f28614b5ee24e9ee634200a8d6eb177a151eb55003c6cc81b3e9cb6d1a1673a2881ec194370af242d9f1fd5818

Заранее спасибо за вашу помощь

Ответы [ 2 ]

2 голосов
/ 29 апреля 2020

Оба кода дают разные результаты по следующим причинам:

  1. В коде Python счетчику присваивается размер 16 байтов. Начальное значение счетчика равно 1 (по умолчанию). Как уже упоминалось в другом ответе [1] , в коде PHP отсутствует IV. Чтобы получить одинаковый результат в обоих кодах, один и тот же IV должен использоваться в каждом случае.
  2. В коде Python данные разделяются запятыми. Поэтому запятую следует использовать в качестве разделителя при объединении в коде PHP.
  3. В коде PHP данные (относительно последующего шестнадцатеричного кодирования) не должны возвращаться в кодировке Base64, а как необработанные данные, т. е. должен быть установлен флаг OPENSSL_RAW_DATA.
  4. При преобразовании в шестнадцатеричную строку каждое значение должно выводиться с двумя цифрами, т. е. с ведущей 0, если необходимо.

Следующий код PHP содержит необходимые изменения и, следовательно, дает тот же результат, что и код Python:

function strToHex($string){
    $hex='';
    for ($i=0; $i < strlen($string); $i++){
        $hex .= sprintf("%02s",dechex(ord($string[$i])));                        // 4. formatting                                                   
    }
    return $hex;
}

$bytes = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
$lkey= implode(array_map("chr", $bytes));
$method = "AES-256-CTR";
$password = $lkey;
$data = array("E5ZA", "K2JV", "PA01", "J1W3", "386S", "AGVZ", "9O9T", "F640", "FR20", "40LX", "D443", "1913", "031V");
$string= implode(",", $data);                                                    // 2. delimiter
$iv = hex2bin("00000000000000000000000000000001");                               // 1. right IV
$valid = openssl_encrypt ($string, $method, $password, OPENSSL_RAW_DATA, $iv);   // 3. raw data 
echo "Result:             " . strToHex($valid) . "\n";
echo "Result from Python: " . "b5682cef66f2adaff0dacb7078f31a773feb86f28614b5ee24e9ee634200a8d6eb177a151eb55003c6cc81b3e9cb6d1a1673a2881ec194370af242d9f1fd5818" . "\n";

Кстати, вместо strToHex встроенная функция bin2hex можно использовать.

Примечание: Для CTR повторное использование IV под тем же ключом разрушает безопасность [2] . Таким образом, в текущей реализации новый ключ должен использоваться для каждого шифрования (поскольку используется исправление IV). Другой подход заключается в разделении IV на одноразовый номер и счетчик, причем одноразовый номер генерируется случайным образом для каждого шифрования [3] [4] .

1 голос
/ 29 апреля 2020

В openssl_encrypt вам нужен IV, чтобы убедиться, что зашифрованный текст уникален.

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$generatediv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

И после этого

$valid = openssl_encrypt ($string, $method, $password, 0, $generatediv);

Надеюсь, что это работает

...