У меня есть код, который выглядит примерно так:
$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 могут это увидеть) , кажется, что в примерах здесь используется обрезка, чтобы получить правильную расшифрованную строку.
Фактически оба mcrypt_encrypt()
и mcrypt_decrypt()
а также другие функции en- / decryption (например, mcrypt_generic()
или mdecrypt_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");
В моей реализации 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
Мне пришлось шифровать / дешифровать двоичные данные. К сожалению, 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 …
После 24 часов исследований, наконец, это сработало для меня:
function removePadding($decryptedText){ $strPad = ord($decryptedText[strlen($decryptedText)-1]); $decryptedText= substr($decryptedText, 0, -$strPad); return $decryptedText; }