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.

Was it helpful?

Solution

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.

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));        
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top