Должен ли я обрезать расшифрованную строку после mcrypt_decrypt? - PullRequest
12 голосов
/ 30 июня 2009

У меня есть код, который выглядит примерно так:

$cipher_alg = MCRYPT_RIJNDAEL_128;
$decrypted_string = mcrypt_decrypt($cipher_alg, $key, 
$encrypted_string , MCRYPT_MODE_CBC, trim(hex2bin(trim($hexiv))));

Я переживаю, что в процессе декодирования mcrypt_decrypt будет вводить пустой пробел или нулевые символы сзади или перед $decrypted_string.

Так я должен урезать это?

Примечание: я мог бы запустить код и выяснить это. Но так как я никогда не смогу запустить достаточно примеров, чтобы доказать (или опровергнуть) свою точку зрения, мне нужны некоторые конкретные и теоретические ответы, вероятно основанные на внутренней работе алгоритма mcrypt_decrypt. Еще одна причина, по которой я спрашиваю, заключается в том, что я верю, что это поможет другим.

Примечание 2: Несмотря на ответ ниже (теперь удален и его видят только 10K пользователей) , похоже, что примеры здесь используют обрезку для получения правильная расшифрованная строка.

Ответы [ 4 ]

18 голосов
/ 30 июня 2009

На самом деле оба mcrypt_encrypt() и mcrypt_decrypt(), а также другие функции кодирования / дешифрования (например, mcrypt_generic() или mdecrypt_generic()) do дополняет параметр $data до длины n * <<blocksize>>. Символ заполнения является символом NUL (\x0 или \0), тогда как <<blocksize>> зависит от используемых режимов шифрования и блочного шифрования. Вы должны взглянуть на Режимы работы блочного шифра и Заполнение (криптография) .

Ниже выводится mcrypt_get_block_size() для каждого из доступных шифров и режимов на моей машине. Очевидно, что функция не учитывает, что такие режимы, как CFB, OFB и CTR не требуют каких-либо специальных мер для обработки сообщений, длина которых не кратна размеру блока, поскольку все они работают путем XOR-преобразования открытого текста с выводом блочного шифра (цитата из Википедии). CBC, который используется в вашем примере, всегда требует, чтобы последний блок был дополнен перед шифрованием.

cast-128
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
gost
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
rijndael-128
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
twofish
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
arcfour
    cbc: not supported
    cfb: not supported
    ctr: not supported
    ecb: not supported
    ncfb: not supported
    nofb: not supported
    ofb: not supported
    stream: 1 bytes
cast-256
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
loki97
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
rijndael-192
    cbc: 24 bytes
    cfb: 24 bytes
    ctr: 24 bytes
    ecb: 24 bytes
    ncfb: 24 bytes
    nofb: 24 bytes
    ofb: 24 bytes
    stream: not supported
saferplus
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
wake
    cbc: not supported
    cfb: not supported
    ctr: not supported
    ecb: not supported
    ncfb: not supported
    nofb: not supported
    ofb: not supported
    stream: 1 bytes
blowfish-compat
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
des
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
rijndael-256
    cbc: 32 bytes
    cfb: 32 bytes
    ctr: 32 bytes
    ecb: 32 bytes
    ncfb: 32 bytes
    nofb: 32 bytes
    ofb: 32 bytes
    stream: not supported
serpent
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
xtea
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
blowfish
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
enigma
    cbc: not supported
    cfb: not supported
    ctr: not supported
    ecb: not supported
    ncfb: not supported
    nofb: not supported
    ofb: not supported
    stream: 1 bytes
rc2
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
tripledes
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported

Следовательно, вам нужно rtrim() вывод функций дешифрования, чтобы получить исходную строку, если ваш шифр работает с блоками фиксированной длины:

$output = rtrim($decrypted, "\0");
8 голосов
/ 03 марта 2010

В моей реализации TripleDES я обнаружил, что расшифрованная строка дополняется символами \ 5 или \ 6. Это не ожидаемые символы \ 0 или \ 4, упомянутые выше или в примерах PHP.net. Чтобы определить значение ASCII символа заполнения, используйте функцию ord () . ord () работает с одним символом, поэтому используйте str_split (), чтобы разбить строку или получить прямой доступ к символу с помощью записи массива - $ string [5].

Окончательный результат обрезки - trim($decrypt, "\0..\32");

Итоговый результат кода -

    $key        = "encryption key";
    $encrypt    = base64_decode($encrypt);
    $iv_size    = mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ECB);
    $iv         = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $decrypt    = mcrypt_decrypt(MCRYPT_3DES, $key, $encrypt, MCRYPT_MODE_ECB, $iv);
    $final      = trim($decrypt, "\0..\32"); // removes potential null padding
4 голосов
/ 02 октября 2014

Мне пришлось шифровать / дешифровать двоичные данные. К сожалению, trim может разбить двоичные данные и обрезать допустимые биты, равные нулевому символу.

Чтобы обеспечить одинаковый размер двоичных данных до и после шифрования, Rocket Hazmat разместил здесь отличный ответ: Как мне расшифровать двоичные данные, заканчивающиеся символами NUL в PHP?

Резюме:

// PKCS7 Padding
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$pad = $blocksize - (strlen($data) % $blocksize);
$data .= str_repeat(chr($pad), $pad);

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_ECB);


/*  Then somewhere else in your code */
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_ECB);

// PKCS7 Padding
$strPad = ord($decrypted[strlen($decrypted)-1]);
$newData = substr($decrypted, 0, -$strPad);

Я не уверен относительно использования ECB против CBC ...

0 голосов
/ 22 декабря 2017

После 24 часов исследований у меня наконец получилось:

function removePadding($decryptedText){
    $strPad = ord($decryptedText[strlen($decryptedText)-1]);
    $decryptedText= substr($decryptedText, 0, -$strPad);
    return $decryptedText;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...