Intereting Posts
Лучший способ справиться с обработкой сессии в Zend Framework Ссылка на переменную php в html-файле События Календаря Google mySQL вставляет синтаксическую ошибку с цитатой Есть ли способ вернуть HTML в PHP-функцию? (без построения возвращаемого значения в виде строки) Заполнение выпадающих ящиков при одновременном заполнении таблицы Общая ссылка, которая откроет мое приложение или магазин приложений. Страница входа выглядит как не перенаправление на следующую страницу, как я могу это исправить? Неустранимая ошибка: исключить исключение «PDOException» с сообщением «SQLSTATE : автоматически сохранять дату и время с помощью Yii PHP и MySQL – как избежать пароля в исходном коде? PHP pdo экземпляр как частное статическое свойство Простой вопрос чтения XML (PHP) обслуживание различного контента на основе домена в кодеригенере вызов функции php в моем коде с нажатием на изображение

PHP для Delphi и обратно Шифрование-Расшифровка с использованием Rijndael

У меня проблемы с расшифровкой строк, отправленных с PHP на Delphi с использованием шифрования rijndael. Я использую mcrypt на стороне PHP и DCP_rijndael на стороне Delphi.

На данный момент у меня есть код ниже.

PHP:

function encRJ($key, $iv, $data) { $r = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv); $r = base64_encode($r); return $r; } 

И в Delphi:

 function decRJ(Data: string; Key: string; IV: string): string; var ciph: TDCP_rijndael; begin Data := Base64DecodeStr(Data); ciph:= TDCP_rijndael.Create(Self); ciph.Init(Key[1], 256, @IV[1]); ciph.DecryptCBC(Data[1], Data[1], Length(Data)); ciph.Free; Result := Data; end; 

Я попытался использовать несколько блоков в Интернете, реализующих шифр, и выяснил, что большинство людей говорят о компонентах DCP. Тем не менее, мне не удалось заставить его правильно расшифровать. Я попытался использовать байтовые массивы для параметров, AnsiStrings, WideStrings и т. Д., Но, к сожалению, не повезло.

Извините меня, если я упустил что-то действительно очевидное здесь, так как мой ум не в хорошей форме, после нескольких часов поиска.

Я, кажется, слишком долго тратил на это, но …

Ваша проблема – размер блока. TDCP_rijndael эквивалентен MCRYPT_RIJNDAEL_128 (а не _256). Значение «256» в вызове ciph.Init (…) все еще корректно. Кроме этого это выглядит довольно хорошо. То есть, предполагая, что вы используете ansistrings для key / iv или используете не-unicode Delphi.
Для версий Unicode Delphi я бы склонен использовать TBytes и key [0] / iv [0].

Прокладка может все еще быть проблемой. Если это так, то вот что я искал на основе справочных страниц PHP и некоторых проб и ошибок.

PHP:

 function Encrypt($src, $key, $iv) { $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc'); //echo "Block size: " . $block . "\r\n"; $pad = $block - (strlen($src) % $block); $src .= str_repeat(chr($pad), $pad); $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $src, MCRYPT_MODE_CBC, $iv); $r = base64_encode($enc); return $r; } function Decrypt($src, $key, $iv) { $enc = base64_decode($src); $dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $enc, MCRYPT_MODE_CBC, $iv); $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc'); $pad = ord($dec[($len = strlen($dec)) - 1]); return substr($dec, 0, strlen($dec) - $pad); } 

Delphi:

 function DecryptData(Data: string; AKey: AnsiString; AIv: AnsiString): string; var key, iv, src, dest: TBytes; cipher: TDCP_rijndael; slen, pad: integer; begin //key := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AKey)); //iv := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AIv)); key := TEncoding.ASCII.GetBytes(AKey); iv := TEncoding.ASCII.GetBytes(AIv); src := Base64DecodeBytes(TEncoding.UTF8.GetBytes(Data)); cipher := TDCP_rijndael.Create(nil); try cipher.CipherMode := cmCBC; slen := Length(src); SetLength(dest, slen); cipher.Init(key[0], 256, @iv[0]); // DCP uses key size in BITS not BYTES cipher.Decrypt(src[0], dest[0], slen); // Remove the padding. Get the numerical value of the last byte and remove // that number of bytes pad := dest[slen - 1]; SetLength(dest, slen - pad); // Base64 encode it result := TEncoding.Default.GetString(dest); finally cipher.Free; end; end; function EncryptData(Data: string; AKey: AnsiString; AIv: AnsiString): string; var cipher: TDCP_rijndael; key, iv, src, dest, b64: TBytes; index, slen, bsize, pad: integer; begin //key := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AKey)); //iv := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AIv)); key := TEncoding.ASCII.GetBytes(AKey); iv := TEncoding.ASCII.GetBytes(AIv); src := TEncoding.UTF8.GetBytes(Data); cipher := TDCP_rijndael.Create(nil); try cipher.CipherMode := cmCBC; // Add padding. // Resize the Value array to make it a multiple of the block length. // If it's already an exact multiple then add a full block of padding. slen := Length(src); bsize := (cipher.BlockSize div 8); pad := bsize - (slen mod bsize); Inc(slen, pad); SetLength(src, slen); for index := pad downto 1 do begin src[slen - index] := pad; end; SetLength(dest, slen); cipher.Init(key[0], 256, @iv[0]); // DCP uses key size in BITS not BYTES cipher.Encrypt(src[0], dest[0], slen); b64 := Base64EncodeBytes(dest); result := TEncoding.Default.GetString(b64); finally cipher.Free; end; end; 

Функции PHP и Delphi теперь дают мне тот же ответ.

РЕДАКТИРОВАТЬ

Base64DecodeBytes – это немного кода, который я добавил в модуль DCP Base64:

 function Base64DecodeBytes(Input: TBytes): TBytes; var ilen, rlen: integer; begin ilen := Length(Input); SetLength(result, (ilen div 4) * 3); rlen := Base64Decode(@Input[0], @result[0], ilen); // Adjust the length of the output buffer according to the number of valid // b64 characters SetLength(result, rlen); end; 

Ни ваш PHP, ни ваши методы Delphi не указывают какие-либо дополнения. Если разброс по умолчанию отличается, тогда у вас появятся проблемы. Явно укажите PKCS7 (или PKCS5) для обоих.

Комментарий GregS о результате декодирования Base64 верен. Вы предоставляете зашифрованный cyphertext вашему методу decRJ (). Это будут случайные появляющиеся байты. Попытка конвертировать его в UTF-8 будет приводить в действие достаточно, чтобы его нельзя было расшифровать. Входящий cyphertext должен быть преобразован из Base64 direct в массив байтов. Cyphertext не является символьной строкой, поэтому его необходимо преобразовать в Base64 для передачи в виде текста. Это будет текст только после того, как он будет расшифрован обратно в открытый текст.