-2

Due to GDPR I'm trying to find a good method to encrypt/decrypt data. But as my application has both Delphi and PHP endpoints I need functions that have strong encryption and work on both.

Searching on SO I've found out the following one, but I don't know how to do the same functions on Delphi:

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}
AmigoJack
  • 5,234
  • 1
  • 15
  • 31
delphirules
  • 6,443
  • 17
  • 59
  • 108
  • This is a recommendation question, and so is off topic here. Ask here: https://en.delphipraxis.net/ – David Heffernan Oct 06 '21 at 14:23
  • @DavidHeffernan Not really, what i want is to translate the php function above, to Delphi – delphirules Oct 06 '21 at 14:28
  • 1
    [Encrypting and decrypting in PHP + decrypting in Delphi](https://stackoverflow.com/a/65818781/4299358) and [Encrypting in Delphi](https://stackoverflow.com/a/66195352/4299358) using OpenSSL and DEC. It's a shame you didn't link your source and also did not tag your question for PHP and OpenSSL. – AmigoJack Oct 06 '21 at 15:02
  • @AmigoJack Thank you ! – delphirules Oct 06 '21 at 16:50
  • 1
    You should try to avoid encrypting/decrypting strings across multiple programming languages. Why? Encryption/decryption is generally done on RAW data. And since different programming languages handle strings differently stored data block representing string containing same characters in different programming languages might be different. This means that encrypting such even by using exactly same encryption mechanism will yield different results. Not to mention that encoding of your strings might also differ. – SilverWarior Oct 06 '21 at 17:39
  • @silver that's easy, just agree to use UTF8 encoded text – David Heffernan Oct 06 '21 at 18:13
  • 1
    @delphirules OK then, which library are you using in Delphi what is your current code? – David Heffernan Oct 06 '21 at 18:14
  • @DavidHeffernan If it is so easy why there are so many threads about problems with encoding/decoding strings across multiple programming languages? Just in Delphi section of SO there are about half a dozen of such questions every year. Some are even about difficulties doing encryption/decryption of strings across different Delphi versions what not about different programming languages. General guidance of encryption/decryption is to not work with strings but instead with data. And to do so successfully you need to make sure that you use the same data structure first. – SilverWarior Oct 06 '21 at 18:26
  • @DavidHeffernan i'm on Delphi 10.4, i'm trying to use the DCPcrypt Cryptographic Component Library v2.2 to do the same thing the php code above is doing – delphirules Oct 06 '21 at 19:45
  • @SilverWarior Thanks but it's not my choice ; i need to do it due to the customer request, because case a data leak occurs, hackers won't have access to sensitive data because is crypted on the database. But we have end points both in Delphi and PHP – delphirules Oct 06 '21 at 19:46
  • @AmigoJack Please link as reply , i'll accept it – delphirules Oct 06 '21 at 20:28
  • @silvee convert the string to byte array UTF8 encoded and encrypt that. Simples. – David Heffernan Oct 06 '21 at 21:16

2 Answers2

3

The code you found is not optimal. Once identifying what is repeating and enriching it with the principle of using constants over literals the following PHP code emerges:

define( 'ALGO_SECRET',  'sha256' );  // SHA-256 = 32 bytes; https://en.wikipedia.org/wiki/SHA-2
define( 'ALGO_MSGAUTH', 'sha256' );
define( 'ALGO_SSL',     'aes-256-cbc' );
define( 'SALT',         'Bedrock Hordes Staples' );  // https://en.wikipedia.org/wiki/Salt_(cryptography)

function encrypt( $plainbytes, $secretkey ) {
  // Preparations
  $hash=        hash( ALGO_SECRET, $secretkey. SALT, true );  // true = return bytes
  $iv=          openssl_random_pseudo_bytes( 16 );  // 16 bytes; https://en.wikipedia.org/wiki/Initialization_vector

  // Actual encryption of the payload
  $cipherbytes= openssl_encrypt( $plainbytes, ALGO_SSL, $hash, OPENSSL_RAW_DATA, $iv );

  // Adding a modification detection to the encrypted data in front of it; https://en.wikipedia.org/wiki/HMAC
  $hmac=        hash_hmac( ALGO_MSGAUTH, $cipherbytes. $iv, $hash, true );  // true = return bytes
  return $iv. $hmac. $cipherbytes;  // 16 + 32 + ? = 48 bytes minimum
}

function decrypt( $allbytes, $secretkey ) {
  // Preparations
  $hash=        hash( ALGO_SECRET, $secretkey. SALT, true );  // Same as in encryption
  $iv=          substr( $allbytes,  0, 16 );  // Cut into 3 pieces again
  $hmac=        substr( $allbytes, 16, 32 );
  $cipherbytes= substr( $allbytes, 48 );

  // Both extracted and recalculated modification detection values must match
  $hmac_recalc= hash_hmac( ALGO_MSGAUTH, $cipherbytes. $iv, $hash, true );  // Same as in encryption
  if( !hash_equals( $hmac_recalc, $hmac ) ) return null;  // Not equal? Payload must be considered tampered/modified/corrupted.

  // Actual decryption of the payload
  return openssl_decrypt( $cipherbytes, ALGO_SSL, $hash, OPENSSL_RAW_DATA, $iv );
}

I consider this to ease telling apart all the single items and how much of the encryption and decryption process is the same. It shouldn't be that difficult to do the same steps in Delphi or another language - it would also work without OpenSSL on both ends.

For ready-to-use examples but also explanations on why to never handle texts but instead only bytes have a read on:

AmigoJack
  • 5,234
  • 1
  • 15
  • 31
0

I tried DCPrijndael in Delphi and openssl_decrypt in php but for some reason it didn't work as expected.

After much trial and error, I finally used TDCP_rijndael.EncryptCFB8bit in Delphi code and openssl_decrypt with "aes-128-cfb8" parameter in php to decode same data and all worked just great.

Btw, I have manually padded data with ZEROs, so I used OPENSSL_ZERO_PADDING in decrypt function.

Shadab Mozaffar
  • 111
  • 1
  • 2