如何在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
相关产品推荐
相关产品推荐

