Looks like a encoding problem with diffrent character sets. Check the character sets you use in delphi and php. I can imagine that your strings are latin-1 in delphi and UTF-8 in php. And because of that some strange symbols appears.
AES crypt Delphi/PHP corrupted output
Question
I encrypt some data in Delphi and send it via GET to PHP script which decrypts it and adds result to MySQL database. The problem is it sometimes adds one "�" or more "���" at the end of data. Here is the code:
const
URL = 'http://127.0.0.1/script.php?data=';
PACK_SEPARATOR = '|';
KeySize = 32;
BlockSize = 16;
function aes_encrypt(const Data: string; const Key: string; const IV: string) : string;
var
Cipher : TDCP_rijndael;
tempData, tempKey, tempIV : string;
begin
tempKey := PadWithZeros(Key,KeySize);
tempIV := PadWithZeros(IV,BlockSize);
tempData := PadWithZeros(Data,BlockSize);
Cipher := TDCP_rijndael.Create(nil);
if Length(Key) <= 16 then
Cipher.Init(tempKey[1],128,@tempIV[1])
else if Length(Key) <= 24 then
Cipher.Init(tempKey[1],192,@tempIV[1])
else
Cipher.Init(tempKey[1],256,@tempIV[1]);
Cipher.EncryptCBC(tempData[1],tempData[1],Length(tempData));
Cipher.Free;
FillChar(tempKey[1],Length(tempKey),0);
Result := Base64EncodeStr(tempData);
end;
function PadWithZeros(const str : string; size : integer) : string;
var
origsize, i : integer;
begin
Result := str;
origsize := Length(Result);
if ((origsize mod size) <> 0) or (origsize = 0) then
begin
SetLength(Result,((origsize div size)+1)*size);
for i := origsize+1 to Length(Result) do
Result[i] := #0;
end;
end;
function HTTPEncode(const AStr: String): String;
const
NoConversion = ['A'..'Z','a'..'z','*','@','.','_','-'];
var
Sp, Rp: PChar;
begin
SetLength(Result, Length(AStr) * 3);
Sp := PChar(AStr);
Rp := PChar(Result);
while Sp^ <> #0 do
begin
if Sp^ in NoConversion then
Rp^ := Sp^
else
if Sp^ = ' ' then
Rp^ := '+'
else
begin
FormatBuf(Rp^, 3, '%%%.2x', 6, [Ord(Sp^)]);
Inc(Rp,2);
end;
Inc(Rp);
Inc(Sp);
end;
SetLength(Result, Rp - PChar(Result));
end;
packedData := Memo1.Lines.Text + PACK_SEPARATOR + Edit1.Text + PACK_SEPARATOR + Edit2.Text;
encryptedData := aes_encrypt(packedData, KEY, IV);
encryptedData := HTTPEncode(encryptedData);
serverMsg := DownloadFile(URL+encryptedData);
'packedData' length before encryption is about 133. After encryption about 200 so it isn't break some servers GET data limit.
Now PHP code:
function aes_decrypt($dataToDecrypt, $key, $iv)
{
$decoded = base64_decode($dataToDecrypt);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $decoded, MCRYPT_MODE_CBC, $iv);
return $decrypted;
}
$packedData = aes_decrypt($_GET['data'], KEY, IV);
$unpacked = explode(PACK_SEPARATOR, $packedData);
$smth1 = $unpacked[0];
$smth2 = $unpacked[1];
$smth3 = $unpacked[2];
$params = array(':thing' => $somevar, ':data1' => $smth1, ':data2' => $smth2, ':data3' => $smth3);
$query = $pdo->prepare('UPDATE one_table SET somedata1 = :data1 , somedata2 = :data2 , somedata3 = :data3 WHERE something = :thing LIMIT 1');
$success = $query->execute($params);
I spend really many hours trying to resolve this problem. Some time ago I had problems with encrypted PHP output with binary data, the problem was aes_decrypt function so I changed it into you can see above. Right now I don't know where is the problem. Delphi encrypt, PHP decrypt or in sending data via GET? Thank you for any help you are able to provide.
Solution
OTHER TIPS
This is my Delphi XE3 and PHP code :
Delphi XE3 code :
uses IdHash, IdCoderMIME, IdHashMessageDigest,
DCPrijndael, DCPbase64;
function xBase64Encode(const Input: string): AnsiString;
begin
result := TIdEncoderMIME.EncodeString(Input, TEncoding.UTF8);
end;
function xBase64Decode(const Input: AnsiString): string;
begin
result := TIdDecoderMIME.DecodeString(Input, TEncoding.UTF8);
end;
function PadWithZeros(const str: AnsiString; size: integer): AnsiString;
var
origsize, i: integer;
begin
Result := str;
origsize := Length(Result);
if ((origsize mod size) <> 0) or (origsize = 0) then
begin
SetLength(Result, ((origsize div size) + 1) * size);
for i := origsize + 1 to Length(Result) do
Result[i] := #0;
end;
end;
function AES_Rijndael_Encript(xData, xKey, xIV: string): string;
var
Cipher: TDCP_rijndael;
B64, Data, Key, IV: AnsiString;
begin
B64 := xBase64Encode(xData);
// Pad Key, IV and Data with zeros as appropriate
Key := PadWithZeros(AnsiString(xKey), KeySize);
IV := PadWithZeros(AnsiString(xIV), BlockSize);
Data := PadWithZeros(B64, BlockSize);
// Create the cipher and initialise according to the key length
Cipher := TDCP_rijndael.Create(nil);
if Length(AnsiString(xKey)) <= 16 then
Cipher.Init(Key[1], 128, @IV[1])
else if Length(AnsiString(xKey)) <= 24 then
Cipher.Init(Key[1], 192, @IV[1])
else
Cipher.Init(Key[1], 256, @IV[1]);
// Encrypt the data
Cipher.EncryptCBC(Data[1], Data[1], Length(Data));
// Free the cipher and clear sensitive information
Cipher.Free;
FillChar(Key[1], Length(Key), 0);
// Display the Base64 encoded result
Result := Base64EncodeStr(Data);
end;
function AES_Rijndael_Decript(xData, xKey, xIV: string): string;
var
Cipher : TDCP_rijndael;
Data, Key, IV : ansistring;
xResult : string;
begin
// Pad Key and IV with zeros as appropriate
Key := PadWithZeros(ansistring(xKey),KeySize);
IV := PadWithZeros(ansistring(xIV),BlockSize);
// Decode the Base64 encoded string
Data := Base64DecodeStr(ansistring(xData));
// Create the cipher and initialise according to the key length
Cipher := TDCP_rijndael.Create(nil);
if Length(ansistring(xKey)) <= 16 then
Cipher.Init(Key[1],128,@IV[1])
else if Length(ansistring(xKey)) <= 24 then
Cipher.Init(Key[1],192,@IV[1])
else
Cipher.Init(Key[1],256,@IV[1]);
// Decrypt the data
Cipher.DecryptCBC(Data[1],Data[1],Length(Data));
// Free the cipher and clear sensitive information
Cipher.Free;
FillChar(Key[1],Length(Key),0);
// Display the result
Result := Data;
xResult := Trim(Data);
Result := xBase64Decode(xResult);
end;
How to user function :
boxKey.Text := 'gmAetc4EydWJg2TcnH34';
boxIV.Text := 'AHsq3SCN7usJzqLi';
Memo2.Lines.Text := AES_Rijndael_Encript(Memo1.Lines.Text, boxKey.Text, boxIV.Text);
Memo1.Lines.Text := AES_Rijndael_Decript(Memo2.Lines.Text, boxKey.Text, boxIV.Text);
PHP code :
public function AES_Rijndael_Decript($data) {
$key = 'gmAetc4EydWJg2TcnH34';
$iv = 'AHsq3SCN7usJzqLi';
return base64_decode(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($data), MCRYPT_MODE_CBC, $iv));
}
public function AES_Rijndael_Encript($data) {
$key = 'gmAetc4EydWJg2TcnH34';
$iv = 'AHsq3SCN7usJzqLi';
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,$key,base64_encode($data),MCRYPT_MODE_CBC,$iv));
}