Recent

Author Topic: [SOLVED] DCP: encrypt string with PHP and decrypt with Lazarus  (Read 4124 times)

stephanie

  • New Member
  • *
  • Posts: 27
Hello,

I've to process with Lazarus a CSV file created by PHP with an encrypted field. I use Lazarus for years, but I'm not a php programmer (I just have some basic knowledge of PHP).

With Lazarus I already have experience with DCP, which I was currently using with RC4 / SHA1, 3DES / MD5 and more. However I can't find a way to encode a string with PHP that is decryptable with Lazarus, or even with OpenSSL from the terminal (Linux).

On PHP I use a function that works fine with AES-256, I checked by decrypting and getting the original string.

With Lazarus I tried to use DCPrijndael, which I had not used yet, and I can encrypt / decrypt a string correctly, if I don't use initial vector, while if I use an Iv the decrypt differs in two characters with the original string (the other characters are correct).

However PHP and Lazarus seem like separate worlds and I haven't found a way to encrypt on PHP that makes it possible to decrypt with Lazarus. I've also tried to crypt with RC4 / SHA1, that I already use with Lazarus, but PHP and Lazarus seems work differently.

Here is my PHP code:

Code: Pascal  [Select][+][-]
  1. //PHP CODE
  2.   function encrypt_decrypt($action, $string)
  3.   {
  4.      /* =================================================
  5.       * ENCRYPTION-DECRYPTION
  6.       * =================================================
  7.       * ENCRYPTION: encrypt_decrypt('encrypt', $string);
  8.       * DECRYPTION: encrypt_decrypt('decrypt', $string) ;
  9.       * =================================================
  10.       Make sure to create 32 byte secret_key and 16 byte secret_iv  
  11.       * =================================================
  12.       */
  13.      $output = false;
  14.      $encrypt_method = "AES-256-CBC";
  15.      $secret_key = '12345678901234567890123456789012';
  16.      $secret_iv = 'mystring to convert in HEX'; //dca12345678901a3 (HEX --> $iv)
  17.      // hash
  18.      $key = hash('sha256', $secret_key);
  19.      // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
  20.      $iv = substr(hash('sha256', $secret_iv), 0, 16);
  21.      if ($action == 'encrypt') {
  22.          $output = base64_encode(openssl_encrypt($string, $encrypt_method, $key, 0, $iv));
  23.      } else {
  24.          if ($action == 'decrypt') {
  25.              $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
  26.          }
  27.      }
  28.      return $output;
  29.   }
  30.  

Here my Lazarus encrypt code:

Code: Pascal  [Select][+][-]
  1. uses
  2.   DCPrijndael, DCPsha1, DCPsha256, Base64, DCPcrypt2
  3.  
  4. var
  5.   S, T, Z, MyKey, MyIv: AnsiString;
  6.   MyDCP_rijndael: TDCP_rijndael;
  7.  
  8.  
  9. //Encrypt:
  10.   MyDCP_rijndael := TDCP_rijndael.Create (nil);
  11.   S := 'Original string to encrypt';
  12.   MyKey := '12345678901234567890123456789012'; //Password 32 char
  13.   MyIv := 'dca12345678901a3'; //16 char HEX
  14.   try
  15.     MyDCP_rijndael.InitStr(MyKey, TDCP_sha256);
  16.     //MyDCP_rijndael.SetIV(MyIv); //Commented, because sith Iv 2 characters of the string are different with original after crypt and decrypt
  17.     //These 2 rows are commented because the result is the same:
  18.     //MyDCP_rijndael.BlockSize := Length(MyIv); //Should this be also 128? -->  It is the same if 128 or Length(MyIv)
  19.     //MyDCP_rijndael.CipherMode := cmCBC; //Requires DCPcrypt2 in the uses, else error Identifier not found "cmCBC"
  20.     MyDCP_rijndael.EncryptCBC(S[1],S[1],Length(S));
  21.     MyDCP_rijndael.Burn;
  22.     Z := EncodeStringBase64(S);
  23.   except
  24.     Z := 'ERROR';
  25.   end;
  26.   Clipboard.AsText := Z;
  27.   showmessage (Z);
  28.   MyDCP_rijndael.Free;
  29.  

and here my Lazarus decrypt code:

Code: Pascal  [Select][+][-]
  1. uses
  2.   DCPrijndael, DCPsha1, DCPsha256, Base64, DCPcrypt2
  3.  
  4. var
  5.   S, T, Z, MyKey, MyIv: AnsiString;
  6.   MyDCP_rijndael: TDCP_rijndael;
  7.  
  8. //Decrypt:
  9.   MyDCP_rijndael := TDCP_rijndael.Create (nil);
  10.  
  11.   S := 'Original string to decrypt';
  12.   T := DecodeStringBase64(S);
  13.  
  14.   MyKey := '12345678901234567890123456789012'; //Password 32 char
  15.   MyIv := 'dca12345678901a3'; //16 char HEX
  16.  
  17.   try
  18.     MyDCP_rijndael.InitStr(MyKey, TDCP_sha256);
  19.     //MyDCP_rijndael.SetIV(MyIv); //Commented, because sith Iv 2 characters of the string are different with original after crypt and decrypt
  20.     //These 2 rows are commented because the result is the same:
  21.     //MyDCP_rijndael.BlockSize := Length(MyIv); //Should this be also 128? -->  It the same if 128 or Length(MyIv)
  22.     //MyDCP_rijndael.CipherMode := cmCBC; //Requires DCPcrypt2 in the uses, else error Identifier not found "cmCBC"
  23.     MyDCP_rijndael.DecryptCBC(T[1],T[1],Length(T));
  24.     MyDCP_rijndael.Burn;
  25.     Z := T;
  26.   except
  27.     Z := 'ERROR';
  28.   end;
  29.   Clipboard.AsText := Z;
  30.   showmessage (Z);
  31.   MyDCP_rijndael.Free;
  32.  

I can choose any other crypt algorithm, the important thing is that it can encrypt with PHP and decrypt with Lazarus.

Thanks for any help.

Best regards,

Stephanie
« Last Edit: April 30, 2022, 12:20:24 pm by stephanie »


stephanie

  • New Member
  • *
  • Posts: 27
Re: DCP: encrypt string with PHP and decrypt with Lazarus
« Reply #2 on: April 30, 2022, 12:20:05 pm »
Thanks for the reply. I had searched in the forum, but I couldn't find a working code for me, but I hadn't seen the post:

https://forum.lazarus.freepascal.org/index.php/topic,57776.msg429932.html#msg429932

which allowed me to solve the problem.

I had to change the PHP code, because I still can't find a Lazarus code to decrypt the previous PHP code (that uses also a SHA-256 hash).

I modified the procedure to avoid writing the Iv value at the end of the encrypted string (with only a Base64 encoding).

I can't understand why a double DecodeStringBase64 is needed on the string to be decrypted, however that's what it takes to make the code working.

The result returns a string with at the end one or more non-printable characters (Ord <32), that I cancel.

This code now works correctly, it is necessary to insert DCPcrypt2 in the uses cause.

PHP Code (encrypt):

Code: Pascal  [Select][+][-]
  1.   function MyEncrypt ($data, $key, $iv)
  2.   {
  3.      //Remove the base64 encoding from our key
  4.      $encryption_key = base64_decode($key);
  5.     //Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
  6.     $encrypted = openssl_encrypt($data, 'AES-256-CBC', $encryption_key, 0, $iv);
  7.     //The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
  8.     return base64_encode($encrypted);
  9.   }
  10.  

Lazarus code (decrypt):

Code: Pascal  [Select][+][-]
  1. uses
  2.   DCPrijndael, Base64, DCPcrypt2  
  3.  
  4. function DecryptAES256CBC(const MyString, MyKey, MyIv: AnsiString): AnsiString;
  5. var
  6.   S, T, Z: AnsiString;
  7.   MyDCP_rijndael: TDCP_rijndael;
  8.   k: SmallInt;
  9. begin
  10.   Result := ''; //Default
  11.   S := '';
  12.   T := '';
  13.   Z := '';
  14.   try
  15.     S := DecodeStringBase64(DecodeStringBase64(MyString));
  16.     T := DecodeStringBase64(MyKey);
  17.     if (Length(T) < 32) then
  18.       while Length(T) < 32 do T := T + AnsiChar(0);
  19.     T := Copy(T, 1, 32);
  20.     MyDCP_rijndael := TDCP_rijndael.Create (nil);
  21.     MyDCP_rijndael.CipherMode := cmCBC;
  22.     MyDCP_rijndael.Init(T[1], Length(T) * 8, @MyIv[1]);
  23.     MyDCP_rijndael.DecryptCBC(S[1], S[1], Length(S));
  24.     for k := 1 to Length(S) do if (Ord(S[k]) >= 32) then Z := Z + S[k];
  25.     Result := Z;
  26.     MyDCP_rijndael.Free;
  27.   except
  28.     Result := '';
  29.   end;
  30. end;  
  31.  

Thanks for the help, I hope this code can be useful to others.

Sorry for my bad English.

Best regards,

Stephanie
« Last Edit: April 30, 2022, 01:31:12 pm by stephanie »

nummer8

  • Full Member
  • ***
  • Posts: 124
Re: [SOLVED] DCP: encrypt string with PHP and decrypt with Lazarus
« Reply #3 on: April 30, 2022, 03:05:54 pm »
Well-done!
Thanks for sharing.

stephanie

  • New Member
  • *
  • Posts: 27
Re: [SOLVED] DCP: encrypt string with PHP and decrypt with Lazarus
« Reply #4 on: April 30, 2022, 04:00:59 pm »
Update: the CipherMode property set is non necessary, so the DCPcrypt2 in the uses clause can be omitted.

PHP Code (encrypt):

Code: Pascal  [Select][+][-]
  1.   function MyEncrypt ($data, $key, $iv)
  2.   {
  3.      //Remove the base64 encoding from our key
  4.      $encryption_key = base64_decode($key);
  5.     //Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
  6.     $encrypted = openssl_encrypt($data, 'AES-256-CBC', $encryption_key, 0, $iv);
  7.     //Return value
  8.     return base64_encode($encrypted);
  9.   }
  10.  

Lazarus Code (decrypt):

Code: Pascal  [Select][+][-]
  1. uses
  2.   DCPrijndael, Base64  
  3.  
  4. function DecryptAES256CBC(const MyString, MyKey, MyIv: AnsiString): AnsiString;
  5. var
  6.   S, T, Z: AnsiString;
  7.   MyDCP_rijndael: TDCP_rijndael;
  8.   k: SmallInt;
  9. begin
  10.   Result := ''; //Default
  11.   S := '';
  12.   T := '';
  13.   Z := '';
  14.   if (MyString = '') or (MyKey = '') or (MyIv = '') then exit;
  15.   try
  16.     S := DecodeStringBase64(DecodeStringBase64(MyString));
  17.     T := DecodeStringBase64(MyKey);
  18.     if (Length(T) < 32) then
  19.       while Length(T) < 32 do T := T + AnsiChar(0);
  20.     T := Copy(T, 1, 32);
  21.     MyDCP_rijndael := TDCP_rijndael.Create (nil);
  22.     //MyDCP_rijndael.CipherMode := cmCBC; //Works, but non necessary, it can be commented (CipherMode requires DCPcrypt2 in the uses clause)
  23.     MyDCP_rijndael.Init(T[1], Length(T) * 8, @MyIv[1]);
  24.     MyDCP_rijndael.DecryptCBC(S[1], S[1], Length(S));
  25.     for k := 1 to Length(S) do
  26.       if (Ord(S[k]) >= 32) then Z := Z + S[k];
  27.     Result := Z;
  28.     MyDCP_rijndael.Free;
  29.   except
  30.     Result := '';
  31.   end;
  32. end;  
  33.  

Best regards,

Stephanie

 

TinyPortal © 2005-2018