Recent

Author Topic: Why do PHP and Lazarus use openssl_encrypt to encrypt, but get different results  (Read 1931 times)

bills

  • New Member
  • *
  • Posts: 47
Hi.
I try to encrypt a string use PHP and Lazarus respectively. Use openssl_encrypt and same KEY and IV, why the result is different?

The php version is 7.4.3nts.
Php code:
Code: PHP  [Select][+][-]
  1. <?php
  2.  
  3. $DATA = "Hello World_____";
  4. $KEY  = "1234567890______";
  5. $IV   = "______1234567890";
  6.  
  7. function encrypt_CBC($data, $key, $iv) {
  8.     $cipher = "aes-256-cbc";
  9.     $options = OPENSSL_RAW_DATA;
  10.     $paddedData = openssl_encrypt($data, $cipher, $key, $options, $iv);
  11.         return $paddedData;
  12. }
  13.  
  14.  
  15. $CBC = encrypt_CBC($DATA, $KEY, $IV);
  16.  
  17. echo "KEY               : ".$KEY." (".strlen($KEY).")"."<br>";
  18. echo "IV                : ".$IV." (".strlen($IV).")"."<br>";
  19. echo "DATA              : ".$DATA." (".strlen($DATA).")"."<br>";
  20.  
  21. $CBC = base64_encode($CBC);
  22. echo "CBC_BASE64 : ".$CBC." (".strlen($CBC).")"."<br>";
  23.  
  24. ?>

lazarus code:
Code: Pascal  [Select][+][-]
  1. program project_en;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}
  7.   cthreads,
  8.   {$ENDIF}
  9.   Classes, SysUtils, CustApp,
  10.  
  11.   StrUtils,
  12.   IdMultipartFormData,
  13.   IdGlobal, IdCoderMIME, idCoder,
  14.   IdSSLOpenSSL, IdGlobalProtocols, LazUTF8Classes,
  15.   //DCPrijndael, Base64,
  16.   DCPsha1, DCPsha256, DCPcrypt2,
  17.   DCPrijndael, DCPbase64, base64,
  18.   DCPconst, ClpEncoders,
  19.  
  20.   OpenSSL
  21.   { you can add units after this };
  22.  
  23. function BinStr2Hex(S: AnsiString): AnsiString;
  24. var
  25.   i: integer;
  26. begin
  27.   Result := '';
  28.   for i := 1 to Length(S)
  29.     do Result := Result + LowerCase(HexStr(Byte(S[i]), 2));
  30. end;
  31.  
  32. function my_encrypt(Data: string; key, IV: string): string;
  33. var
  34.   Cipher: TDCP_rijndael;
  35.   DataString, encryption_key: ansistring;
  36. begin
  37.   encryption_key := key;
  38.  
  39.   if (Length(encryption_key) < 32) then
  40.     while Length(encryption_key) < 32 do encryption_key := encryption_key + ansichar(0);
  41.   encryption_key := Copy(encryption_key, 1, 32);
  42.  
  43.   DataString := Data;
  44.  
  45.   Cipher := TDCP_rijndael.Create(nil);
  46.   Cipher.CipherMode := cmCBC;
  47.   Cipher.Init(encryption_key[1], Length(encryption_key) * 8, @IV[1]);
  48.   Cipher.EncryptCBC(DataString[1], DataString[1], Length(DataString));
  49.   //Result := EncodeStringBase64(DataString);
  50.   Result := EncodeStringBase64(DataString);
  51.   Cipher.Free;
  52. end;
  53.  
  54.  
  55. var
  56.   Key    : AnsiString;
  57.   IV     : AnsiString;
  58.   Data   : AnsiString;
  59.   CBC    : AnsiString;
  60. begin
  61.   //
  62.   Data := 'Hello World_____';
  63.   Key  := '1234567890______';
  64.   IV   := '______1234567890';
  65.  
  66.   CBC := my_encrypt(Data, Key, IV);
  67.  
  68.   //writeLn('加密:');
  69.   WriteLn('KEY        : ', Key             , ' (', Length(Key) , ')');
  70.   WriteLn('IV         : ', IV              , ' (', Length(IV)  , ')');
  71.   WriteLn('DATA       : ', Data            , ' (', Length(Data), ')');
  72.   //WriteLn('CBC        : ', BinStr2Hex(CBC) , ' (', Length(CBC) , ')');
  73.   //CBC := (CBC);
  74.   WriteLn('CBC_BASE64 : ', CBC             , ' (', Length(CBC) , ')');
  75. end.
  76.  

The php result is:
Code: [Select]
KEY : 1234567890______ (16)
IV : ______1234567890 (16)
DATA : Hello World_____ (16)
CBC_BASE64 : iZ6o4g04RAztnChNd1FQf96qBsa0T2IIsg18I0HoRNU= (44)

The lazarus result is:
Code: [Select]
KEY        : 1234567890______ (16)
IV         : ______1234567890 (16)
DATA       : Hello World_____ (16)
CBC_BASE64 : iZ6o4g04RAztnChNd1FQfw== (24)


Zvoni

  • Hero Member
  • *****
  • Posts: 2747
AnsiString vs. WideString?

Is Lazarus interpreting the underscore as whitespace?

Your result is equal for this
iZ6o4g04RAztnChNd1FQf

Try just "Hello World" without underscore in both
« Last Edit: July 12, 2024, 02:37:55 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

paweld

  • Hero Member
  • *****
  • Posts: 1268
Because the string before encryption must end with a character from 1 to 16 depending on how many characters are needed to padding to multiples of 16.
Code: Pascal  [Select][+][-]
  1. program project_en;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, DCPcrypt2, DCPrijndael, Base64;
  7.  
  8.   function BinStr2Hex(S: Ansistring): Ansistring;
  9.   var
  10.     i: Integer;
  11.   begin
  12.     Result := '';
  13.     for i := 1 to Length(S) do Result := Result + LowerCase(HexStr(Byte(S[i]), 2));
  14.   end;
  15.  
  16.   function my_encrypt(Data: String; key, IV: String): String;
  17.   var
  18.     Cipher: TDCP_rijndael;
  19.     DataString, encryption_key: Ansistring;
  20.     l, i: Integer;
  21.   begin
  22.     encryption_key := key;
  23.  
  24.     if (Length(encryption_key) < 32) then
  25.       while Length(encryption_key) < 32 do encryption_key := encryption_key + Ansichar(0);
  26.     encryption_key := Copy(encryption_key, 1, 32);
  27.  
  28.     l := 16 - (Length(Data) mod 16);
  29.     for i := 1 to l do
  30.       Data := Data + Chr(l);
  31.  
  32.     DataString := Data;
  33.  
  34.     Cipher := TDCP_rijndael.Create(nil);
  35.     Cipher.CipherMode := cmCBC;
  36.     Cipher.Init(encryption_key[1], Length(encryption_key) * 8, @IV[1]);
  37.     Cipher.EncryptCBC(DataString[1], DataString[1], Length(DataString));
  38.     Result := EncodeStringBase64(DataString);
  39.     Cipher.Free;
  40.   end;
  41.  
  42.  
  43. var
  44.   Key: Ansistring;
  45.   IV: Ansistring;
  46.   Data: Ansistring;
  47.   CBC: Ansistring;
  48. begin
  49.  
  50.   Data := 'Hello World_____';
  51.   Key := '1234567890______';
  52.   IV := '______1234567890';
  53.  
  54.   CBC := my_encrypt(Data, Key, IV);
  55.  
  56.   WriteLn('KEY        : ', Key, ' (', Length(Key), ')');
  57.   WriteLn('IV         : ', IV, ' (', Length(IV), ')');
  58.   WriteLn('DATA       : ', Data, ' (', Length(Data), ')');
  59.   WriteLn('CBC_BASE64 : ', CBC, ' (', Length(CBC), ')');
  60.   readln;
  61. end.
result:
Code: [Select]
KEY        : 1234567890______ (16)
IV         : ______1234567890 (16)
DATA       : Hello World_____ (16)
CBC_BASE64 : iZ6o4g04RAztnChNd1FQf96qBsa0T2IIsg18I0HoRNU= (44)
Best regards / Pozdrawiam
paweld

Thaddy

  • Hero Member
  • *****
  • Posts: 16194
  • Censorship about opinions does not belong here.
I can't help but smile, paweld. On the spot! Well done!.

Question to OP ( bills ) is of course why are you using two different libraries that do the same thing? Openssl does the same as dcpcrypt in this case. Should not be there at all.
Mixing up libraries makes mistakes in your code, especially when you do not fully understand what you are doing.
That is not bad, that is why this forum is here. Don't feel offended.
[edit] although I "offend" some people on purpose...you are not one of them.
« Last Edit: July 12, 2024, 05:36:33 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

bills

  • New Member
  • *
  • Posts: 47
Because the string before encryption must end with a character from 1 to 16 depending on how many characters are needed to padding to multiples of 16.
Code: Pascal  [Select][+][-]
  1. program project_en;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, DCPcrypt2, DCPrijndael, Base64;
  7.  
  8.   function BinStr2Hex(S: Ansistring): Ansistring;
  9.   var
  10.     i: Integer;
  11.   begin
  12.     Result := '';
  13.     for i := 1 to Length(S) do Result := Result + LowerCase(HexStr(Byte(S[i]), 2));
  14.   end;
  15.  
  16.   function my_encrypt(Data: String; key, IV: String): String;
  17.   var
  18.     Cipher: TDCP_rijndael;
  19.     DataString, encryption_key: Ansistring;
  20.     l, i: Integer;
  21.   begin
  22.     encryption_key := key;
  23.  
  24.     if (Length(encryption_key) < 32) then
  25.       while Length(encryption_key) < 32 do encryption_key := encryption_key + Ansichar(0);
  26.     encryption_key := Copy(encryption_key, 1, 32);
  27.  
  28.     l := 16 - (Length(Data) mod 16);
  29.     for i := 1 to l do
  30.       Data := Data + Chr(l);
  31.  
  32.     DataString := Data;
  33.  
  34.     Cipher := TDCP_rijndael.Create(nil);
  35.     Cipher.CipherMode := cmCBC;
  36.     Cipher.Init(encryption_key[1], Length(encryption_key) * 8, @IV[1]);
  37.     Cipher.EncryptCBC(DataString[1], DataString[1], Length(DataString));
  38.     Result := EncodeStringBase64(DataString);
  39.     Cipher.Free;
  40.   end;
  41.  
  42.  
  43. var
  44.   Key: Ansistring;
  45.   IV: Ansistring;
  46.   Data: Ansistring;
  47.   CBC: Ansistring;
  48. begin
  49.  
  50.   Data := 'Hello World_____';
  51.   Key := '1234567890______';
  52.   IV := '______1234567890';
  53.  
  54.   CBC := my_encrypt(Data, Key, IV);
  55.  
  56.   WriteLn('KEY        : ', Key, ' (', Length(Key), ')');
  57.   WriteLn('IV         : ', IV, ' (', Length(IV), ')');
  58.   WriteLn('DATA       : ', Data, ' (', Length(Data), ')');
  59.   WriteLn('CBC_BASE64 : ', CBC, ' (', Length(CBC), ')');
  60.   readln;
  61. end.
result:
Code: [Select]
KEY        : 1234567890______ (16)
IV         : ______1234567890 (16)
DATA       : Hello World_____ (16)
CBC_BASE64 : iZ6o4g04RAztnChNd1FQf96qBsa0T2IIsg18I0HoRNU= (44)

Thank you @paweld.
This gives exactly the same encryption result, which perfectly explains my question.

paweld

  • Hero Member
  • *****
  • Posts: 1268
You can also use CryptoLib4Pascal: https://github.com/Xor-el/CryptoLib4Pascal , which padding the strings itself.
Code: Pascal  [Select][+][-]
  1. program project_en;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, Base64, ClpCipherUtilities, ClpParametersWithIV, ClpIParametersWithIV, ClpIBufferedCipher, ClpParameterUtilities;
  7.  
  8.   function BinStr2Hex(S: Ansistring): Ansistring;
  9.   var
  10.     i: Integer;
  11.   begin
  12.     Result := '';
  13.     for i := 1 to Length(S) do Result := Result + LowerCase(HexStr(Byte(S[i]), 2));
  14.   end;
  15.  
  16.   function my_encrypt(Data: String; key, IV: String): String;
  17.   var
  18.     KeyBytes, IVBytes, Buf, InBuf: TBytes;
  19.     KeyParametersWithIV: IParametersWithIV;
  20.     cipher: IBufferedCipher;
  21.     LBlockSize, LBufStart, Count: Integer;
  22.     DataString, encryption_key: Ansistring;
  23.   begin
  24.     encryption_key := key;
  25.  
  26.     if (Length(encryption_key) < 32) then
  27.       while Length(encryption_key) < 32 do encryption_key := encryption_key + Ansichar(0);
  28.     encryption_key := Copy(encryption_key, 1, 32);
  29.  
  30.     DataString := Data;
  31.  
  32.     SetLength(KeyBytes, Length(encryption_key));
  33.     Move(encryption_key[1], KeyBytes[0], Length(encryption_key));
  34.     SetLength(IVBytes, Length(IV));
  35.     Move(IV[1], IVBytes[0], Length(IV));
  36.     SetLength(InBuf, Length(DataString));
  37.     Move(DataString[1], InBuf[0], Length(DataString));
  38.     cipher := TCipherUtilities.GetCipher('RIJNDAEL/CBC/PKCS7');
  39.     KeyParametersWithIV := TParametersWithIV.Create(TParameterUtilities.CreateKeyParameter('AES', KeyBytes), IVBytes);
  40.     cipher.Init(True, KeyParametersWithIV);
  41.     LBlockSize := cipher.GetBlockSize;
  42.     SetLength(Buf, Length(InBuf) + LBlockSize);
  43.     LBufStart := 0;
  44.     Count := cipher.ProcessBytes(InBuf, 0, Length(DataString), Buf, LBufStart);
  45.     Inc(LBufStart, Count);
  46.     Count := cipher.DoFinal(Buf, LBufStart);
  47.     Inc(LBufStart, Count);
  48.     SetLength(Buf, LBufStart);
  49.     SetLength(DataString, LBufStart);
  50.     Move(Buf[0], DataString[1], LBufStart);
  51.     Result := EncodeStringBase64(DataString);
  52.   end;
  53.  
  54.  
  55. var
  56.   Key: Ansistring;
  57.   IV: Ansistring;
  58.   Data: Ansistring;
  59.   CBC: Ansistring;
  60. begin
  61.  
  62.   Data := 'Hello World_____';
  63.   Key := '1234567890______';
  64.   IV := '______1234567890';
  65.  
  66.   CBC := my_encrypt(Data, Key, IV);
  67.  
  68.   WriteLn('KEY        : ', Key, ' (', Length(Key), ')');
  69.   WriteLn('IV         : ', IV, ' (', Length(IV), ')');
  70.   WriteLn('DATA       : ', Data, ' (', Length(Data), ')');
  71.   WriteLn('CBC_BASE64 : ', CBC, ' (', Length(CBC), ')');
  72.   readln;
  73. end.
Best regards / Pozdrawiam
paweld

wp

  • Hero Member
  • *****
  • Posts: 12466
although I "offend" some people on purpose...
You should not do that.

bills

  • New Member
  • *
  • Posts: 47
You can also use CryptoLib4Pascal: https://github.com/Xor-el/CryptoLib4Pascal , which padding the strings itself.

Thank you!
I tested your code and got the correct result.

Code: Pascal  [Select][+][-]
  1. program project_en;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}
  7.   cthreads,
  8.   {$ENDIF}
  9.   Classes, SysUtils, CustApp,
  10.  
  11.   StrUtils,
  12.   //IdMultipartFormData,
  13.   //IdGlobal, IdCoderMIME, idCoder,
  14.   //IdSSLOpenSSL, IdGlobalProtocols, LazUTF8Classes,
  15.   //DCPrijndael, Base64,
  16.   DCPsha1, DCPsha256, DCPcrypt2,
  17.   DCPrijndael, DCPbase64, base64,
  18.   DCPconst, ClpEncoders,
  19.  
  20.   ClpCipherUtilities, ClpParametersWithIV, ClpIParametersWithIV,
  21.   ClpIBufferedCipher, ClpParameterUtilities,
  22.  
  23.  
  24.   OpenSSL
  25.   { you can add units after this };
  26.  
  27. // encrypt function 1
  28. function my_encrypt1(Data: string; key, IV: string): string;
  29. var
  30.   Cipher: TDCP_rijndael;
  31.   DataString, encryption_key: ansistring;
  32.   l, i: Integer;
  33. begin
  34.   l := 16 - (Length(Data) mod 16);
  35.   for i := 1 to l do
  36.     Data := Data + Chr(l);
  37.   DataString := Data;
  38.  
  39.   encryption_key := key;
  40.   if (Length(encryption_key) < 32) then
  41.     while Length(encryption_key) < 32 do encryption_key := encryption_key + ansichar(0);
  42.   encryption_key := Copy(encryption_key, 1, 32);
  43.  
  44.   Cipher := TDCP_rijndael.Create(nil);
  45.   Cipher.CipherMode := cmCBC;
  46.   Cipher.Init(encryption_key[1], Length(encryption_key) * 8, @IV[1]);
  47.   Cipher.EncryptCBC(DataString[1], DataString[1], Length(DataString));
  48.   Result := EncodeStringBase64(DataString);
  49.   Cipher.Free;
  50. end;
  51.  
  52. // encrypt function 2
  53. function my_encrypt2(Data: String; key, IV: String): String;
  54. var
  55.   KeyBytes, IVBytes, Buf, InBuf: TBytes;
  56.   KeyParametersWithIV: IParametersWithIV;
  57.   cipher: IBufferedCipher;
  58.   LBlockSize, LBufStart, Count: Integer;
  59.   DataString, encryption_key: Ansistring;
  60. begin
  61.   encryption_key := key;
  62.  
  63.   if (Length(encryption_key) < 32) then
  64.     while Length(encryption_key) < 32 do encryption_key := encryption_key + Ansichar(0);
  65.   encryption_key := Copy(encryption_key, 1, 32);
  66.  
  67.   DataString := Data;
  68.  
  69.   SetLength(KeyBytes, Length(encryption_key));
  70.   Move(encryption_key[1], KeyBytes[0], Length(encryption_key));
  71.   SetLength(IVBytes, Length(IV));
  72.   Move(IV[1], IVBytes[0], Length(IV));
  73.   SetLength(InBuf, Length(DataString));
  74.   Move(DataString[1], InBuf[0], Length(DataString));
  75.   cipher := TCipherUtilities.GetCipher('RIJNDAEL/CBC/PKCS7');
  76.   KeyParametersWithIV := TParametersWithIV.Create(TParameterUtilities.CreateKeyParameter('AES', KeyBytes), IVBytes);
  77.   cipher.Init(True, KeyParametersWithIV);
  78.   LBlockSize := cipher.GetBlockSize;
  79.   SetLength(Buf, Length(InBuf) + LBlockSize);
  80.   LBufStart := 0;
  81.   Count := cipher.ProcessBytes(InBuf, 0, Length(DataString), Buf, LBufStart);
  82.   Inc(LBufStart, Count);
  83.   Count := cipher.DoFinal(Buf, LBufStart);
  84.   Inc(LBufStart, Count);
  85.   SetLength(Buf, LBufStart);
  86.   SetLength(DataString, LBufStart);
  87.   Move(Buf[0], DataString[1], LBufStart);
  88.   Result := EncodeStringBase64(DataString);
  89. end;
  90.  
  91.  
  92. var
  93.   Key    : AnsiString;
  94.   IV     : AnsiString;
  95.   Data   : AnsiString;
  96.   CBC1, CBC2    : AnsiString;
  97. begin
  98.   //
  99.   Data := 'Hello World';
  100.   Key  := '1234567890______';
  101.   IV   := '______1234567890';
  102.  
  103.   CBC1 := my_encrypt1(Data, Key, IV);    //EncodeUrl(my_encrypt
  104.   CBC2 := my_encrypt2(Data, Key, IV);    //EncodeUrl(my_encrypt
  105.  
  106.   //writeLn('加密:');
  107.   WriteLn('KEY        : ', Key             , ' (', Length(Key) , ')');
  108.   WriteLn('IV         : ', IV              , ' (', Length(IV)  , ')');
  109.   WriteLn('DATA       : ', Data            , ' (', Length(Data), ')');
  110.   //WriteLn('CBC        : ', BinStr2Hex(CBC) , ' (', Length(CBC) , ')');
  111.   //CBC := (CBC);
  112.   WriteLn('CBC1_BASE64 : ', CBC1             , ' (', Length(CBC1) , ')');
  113.   WriteLn('CBC2_BASE64 : ', CBC2             , ' (', Length(CBC2) , ')');
  114.  
  115.  
  116. end.
  117.  

Code: [Select]
KEY        : 1234567890______ (16)
IV         : ______1234567890 (16)
DATA       : Hello World (11)
CBC1_BASE64 : xxIF/qPw4Nz2FBumiTBH+Q== (24)
CBC2_BASE64 : xxIF/qPw4Nz2FBumiTBH+Q== (24)

 

TinyPortal © 2005-2018