Подтвердить что ты не робот

Должен ли я обрезать расшифрованную строку после mcrypt_decrypt?

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

$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 могут видеть его), кажется, что примеры здесь используют обрезку для получения правильной расшифрованной строки.

4b9b3361

Ответ 1

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

Ниже представлен вывод mcrypt_get_block_size() для каждого из доступных шифров и режимов на моей машине. Очевидно, что функция не учитывает, что такие режимы, как CFB, OFB и CTR, не требуют каких-либо специальных мер для обработки сообщений, длины которых не являются кратными размеру блока, поскольку все они работают с помощью XORing открытого текста с выходом блока шифр (цитата из Википедии). 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");

Ответ 2

В моей реализации 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

Ответ 3

Мне пришлось зашифровать/дешифровать двоичные данные. К сожалению, 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...

Ответ 4

После 24 часов исследований, наконец, это сработало для меня:

function removePadding($decryptedText){
    $strPad = ord($decryptedText[strlen($decryptedText)-1]);
    $decryptedText= substr($decryptedText, 0, -$strPad);
    return $decryptedText;
}