Кажется, я потратил слишком много времени на это, но...
Ваша проблема в размере блока. TDCP_rijndael эквивалентен MCRYPT_RIJNDAEL_128 (не _256). Однако значение «256» в вызове ciph.Init(...) по-прежнему верно. В остальном он выглядит вполне нормально. То есть, предполагая, что вы используете ansistrings для key/iv или вы используете не-юникод 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);
}
Дельфи:
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;
EDIT 2018 (Воскрешение мертвых...):
В соответствии с просьбой, вот метод кодирования, не проверенный и извлеченный прямо из старого исходного файла, который я нашел.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: ему много лет, он не тестировался в последнее время и не использовался с Delphi 2010. Вероятно, сейчас есть много лучших альтернатив. Используйте на свой риск.
function Base64EncodeBytes(Input: TBytes): TBytes;
var
ilen: integer;
begin
ilen := Length(Input);
SetLength(result, ((ilen + 2) div 3) * 4);
Base64Encode(@Input[0], @result[0], ilen);
end;
person
shunty
schedule
16.08.2011
Data
мне кажется неправильной. Результатом декодирования base64 должны быть произвольные байты, а не строка в кодировке UTF8. - person President James K. Polk   schedule 13.08.2011