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

如何在Delphi中实现PHP openssl_public_decrypt的公钥解密功能?

关于PHP openssl_public_decrypt的原理与Delphi实现方案

原理说明

RSA非对称加密的核心是密钥对的双向运算逻辑,并非公钥只能加密、私钥只能解密:

  • 常规加密传输:公钥加密,私钥解密
  • 身份验证/签名:私钥加密(生成签名值),公钥解密(验证签名有效性)

PHP的openssl_private_encrypt本质是用私钥对数据做"签名式加密",对应的openssl_public_decrypt就是用公钥还原该数据,以此确认数据由持有对应私钥的主体生成,底层直接调用OpenSSL的RSA_public_decrypt函数实现。

Delphi实现方案

1. 使用TMS Cryptography组件

TMS组件可通过签名验证逻辑实现公钥解密私钥加密的数据(私钥加密=签名,公钥解密=验签还原原文):

uses
  TMSCryptographyLib;

function DecryptWithPublicKey(const AEncryptedData: TBytes; const APublicKey: string): string;
var
  RSA: TTMSCRSA;
  PlainText: TBytes;
begin
  RSA := TTMSCRSA.Create(nil);
  try
    RSA.LoadPublicKeyFromString(APublicKey);
    // 匹配PHP openssl_private_encrypt默认的PKCS1填充与SHA1哈希
    if RSA.VerifySignature(AEncryptedData, PlainText, TTMSCHashSHA1, TTMSCRSAPadding.PKCS1) then
      Result := TEncoding.UTF8.GetString(PlainText)
    else
      Result := '';
  finally
    RSA.Free;
  end;
end;

注意:若PHP端调用openssl_private_encrypt时指定了其他填充方式(如OPENSSL_NO_PADDING),需同步调整Delphi端的填充参数。

2. 直接调用OpenSSL API实现

直接调用OpenSSL底层的RSA_public_decrypt函数,与PHP逻辑完全对齐:

uses
  SysUtils, Classes;

const
  LIB_EAY = 'libcrypto-1_1.dll'; // 根据OpenSSL版本调整(32/64位需与Delphi项目匹配)
  RSA_PKCS1_PADDING = 1;

type
  PRSA = Pointer;

function RSA_new: PRSA; cdecl; external LIB_EAY;
function RSA_free(r: PRSA): Integer; cdecl; external LIB_EAY;
function PEM_read_RSA_PUBKEY(bio: Pointer; r: PPRSA; cb: Pointer; u: Pointer): PRSA; cdecl; external LIB_EAY;
function BIO_new_mem_buf(buf: Pointer; len: Integer): Pointer; cdecl; external LIB_EAY;
function BIO_free(b: Pointer): Integer; cdecl; external LIB_EAY;
function RSA_public_decrypt(flen: Integer; const from: PByte; to: PByte; r: PRSA; padding: Integer): Integer; cdecl; external LIB_EAY;

function DecryptWithOpenSSLPublicKey(const AEncryptedData: TBytes; const APublicKey: string): string;
var
  RSA: PRSA;
  BIO: Pointer;
  PlainText: TBytes;
  DecryptedLen: Integer;
  PubKeyBytes: TBytes;
begin
  Result := '';
  RSA := RSA_new;
  if not Assigned(RSA) then Exit;
  try
    PubKeyBytes := TEncoding.ASCII.GetBytes(APublicKey);
    BIO := BIO_new_mem_buf(@PubKeyBytes[0], Length(PubKeyBytes));
    if not Assigned(BIO) then Exit;
    try
      if not Assigned(PEM_read_RSA_PUBKEY(BIO, @RSA, nil, nil)) then Exit;
      SetLength(PlainText, RSA_size(RSA));
      DecryptedLen := RSA_public_decrypt(Length(AEncryptedData), @AEncryptedData[0], @PlainText[0], RSA, RSA_PKCS1_PADDING);
      if DecryptedLen > 0 then
      begin
        SetLength(PlainText, DecryptedLen);
        Result := TEncoding.UTF8.GetString(PlainText);
      end;
    finally
      BIO_free(BIO);
    end;
  finally
    RSA_free(RSA);
  end;
end;

注意:公钥需为标准PEM格式(包含-----BEGIN PUBLIC KEY-----与-----END PUBLIC KEY-----头尾部)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:57:20