You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现与给定PHP函数兼容的Delphi AES-256-CBC加解密功能

Delphi与PHP互通的AES-256-CBC加解密实现(适配GDPR合规)

原PHP实现核心逻辑(需1:1对齐)

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

加密流程

  • 生成16字节密码学安全的随机IV
  • 对输入密码做SHA256哈希,取32字节原始二进制值作为AES-256密钥
  • 用AES-256-CBC模式加密明文,输出原始二进制密文
  • 用相同密钥对「密文 + IV」计算SHA256 HMAC,得到32字节原始二进制校验值
  • 按 16字节IV + 32字节HMAC + 变长密文 顺序拼接,最后按参数返回原始二进制、十六进制字符串或Base64字符串

解密流程

  • 按编码类型将输入转换为原始二进制
  • 拆分二进制内容:前16字节为IV,16-48位为HMAC校验值,48位之后为密文
  • 用相同密钥重新计算「密文 + IV」的HMAC,与取出的HMAC做恒定时间比较(防时序攻击),校验失败返回空
  • 校验通过后用AES-256-CBC解密密文,返回明文

Delphi 对应实现(兼容Delphi 10.3及以上版本)

依赖单元:System.SysUtils, System.Hash, System.NetEncoding, System.Cipher, System.Classes

辅助恒定时间比较函数(对齐PHP hash_equals 能力)

function HashEquals(const A, B: TBytes): Boolean;
var
  I, Diff: Byte;
begin
  Result := False;
  if Length(A) <> Length(B) then Exit;
  Diff := 0;
  for I := 0 to Length(A) - 1 do
    Diff := Diff or (A[I] xor B[I]);
  Result := Diff = 0;
end;

加密函数

type
  TEncodingType = (etRaw, etHex, etBase64);

function EncryptString(const PlainText, Password: string; EncodingType: TEncodingType = etBase64): string;
var
  AESKey, IV, CipherText, HMACVal, Combined: TBytes;
  AES: TAESCipher;
  HMAC: THMACSHA256;
begin
  // 计算AES密钥:对密码做SHA256取原始32字节
  AESKey := THashSHA2.GetHashBytes(TEncoding.UTF8.GetBytes(Password), THashSHA2.TSHA2Version.SHA256);
  // 生成16字节随机IV
  SetLength(IV, 16);
  TNRGGenerator.GenerateRandomBytes(IV);
  // AES-256-CBC加密,明文统一转UTF-8
  AES := TAESCipher.Create(AESKey, TAESCipherMode.mCBC, IV);
  CipherText := AES.Encrypt(TEncoding.UTF8.GetBytes(PlainText));
  // 计算HMAC,输入顺序为密文+IV
  HMAC := THMACSHA256.Create(AESKey);
  HMAC.Update(CipherText);
  HMAC.Update(IV);
  HMACVal := HMAC.HashFinal;
  // 拼接IV + HMAC + 密文
  Combined := Concat(IV, HMACVal, CipherText);
  // 按指定编码返回结果
  case EncodingType of
    etRaw: Result := TEncoding.ASCII.GetString(Combined);
    etHex: Result := TBitConverter.ToString(Combined).Replace('-', '').ToLower;
    etBase64: Result := TNetEncoding.Base64.EncodeBytesToString(Combined);
  end;
end;

解密函数

function DecryptString(const CipherText, Password: string; EncodingType: TEncodingType = etBase64): string;
var
  AESKey, RawData, IV, HMACVal, CipherRaw, CalcHMAC: TBytes;
  AES: TAESCipher;
  HMAC: THMACSHA256;
begin
  Result := '';
  // 计算AES密钥
  AESKey := THashSHA2.GetHashBytes(TEncoding.UTF8.GetBytes(Password), THashSHA2.TSHA2Version.SHA256);
  // 输入转原始二进制
  case EncodingType of
    etRaw: RawData := TEncoding.ASCII.GetBytes(CipherText);
    etHex: begin
      SetLength(RawData, Length(CipherText) div 2);
      for var I := 0 to Length(RawData) - 1 do
        RawData[I] := StrToInt('$' + Copy(CipherText, I*2 + 1, 2));
    end;
    etBase64: RawData := TNetEncoding.Base64.DecodeStringToBytes(CipherText);
  end;
  // 最小长度校验:至少包含16字节IV+32字节HMAC
  if Length(RawData) < 48 then Exit;
  // 拆分各段数据
  IV := Copy(RawData, 0, 16);
  HMACVal := Copy(RawData, 16, 32);
  CipherRaw := Copy(RawData, 48, Length(RawData) - 48);
  // HMAC校验
  HMAC := THMACSHA256.Create(AESKey);
  HMAC.Update(CipherRaw);
  HMAC.Update(IV);
  CalcHMAC := HMAC.HashFinal;
  if not HashEquals(CalcHMAC, HMACVal) then Exit;
  // 解密后转UTF-8字符串
  AES := TAESCipher.Create(AESKey, TAESCipherMode.mCBC, IV);
  Result := TEncoding.UTF8.GetString(AES.Decrypt(CipherRaw));
end;

互通验证说明

  • 两端明文统一使用UTF-8编码,Delphi不要直接传入默认UTF-16格式的字符串
  • 密钥计算全程使用原始二进制值,不要转成十六进制或Base64后再传入加密接口
  • HMAC的输入顺序必须为「密文+IV」,顺序调换会导致校验失败
  • 本实现使用密码学安全的随机IV、带完整性校验,符合GDPR对个人数据加密的合规要求

内容的提问来源于stack exchange,提问作者delphirules

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:18:03