适用于 Delphi 和 PHP 的加密/解密函数

Encrypt / decrypt functions that work on Delphi and PHP

由于 GDPR,我正在尝试找到一种处理 encrypt/decrypt 数据的好方法。但是由于我的应用程序同时具有 Delphi 和 PHP 端点,因此我需要具有强加密功能并在这两个端点上工作的函数。

正在搜索 on SO I've found out the following one,但我不知道如何在 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));
}

您找到的代码不是最优的。一旦识别出重复的内容并根据使用 constants over literals 的原则丰富它,就会出现以下 PHP 代码:

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 );
}

我认为这样可以轻松区分所有单个项目以及有多少加密和解密过程是相同的。在 Delphi 或其他语言中执行相同的步骤应该不会那么困难 - 它也可以在两端没有 OpenSSL 的情况下工作。

对于现成的示例以及关于为什么 从不处理文本而只处理字节 的解释,请阅读: