var
vSignSrc, vPrivateKey: string;
begin
vSignSrc:= 'data=<xml><treatment_id>88888</treatment_id><merchant_no>109900040300</merchant_no>'+
'<sub_merchant></sub_merchant><username>张华</username><order_no>12345678901</order_no>'+
'<paytype>2</paytype><trade_type>2</trade_type><total_amt>0.01</total_amt>'+
'<spbill_create_ip>127.0.0.1</spbill_create_ip><paytimeout>6</paytimeout>'+
'<order_subject></order_subject><order_detail>缴费</order_detail>'+
'<auth_code>填入微信二维码上的一串号码(paytype=2刷卡付(B扫C)需要填写本参数)</auth_code>'+
'<remark></remark></xml>&developerId=76555&funcId=P7001';
vPrivateKey:= Memo2.Lines.Text;
vPrivateKey:= vPrivateKey
.Replace('-----BEGIN RSA PRIVATE KEY-----','',[rfReplaceAll])
.Replace('-----END RSA PRIVATE KEY-----','',[rfReplaceAll])
.Replace(#13#10,'',[rfReplaceAll])
.Replace(' ','',[rfReplaceAll]);
with TStringBuilder.Create do
try
Append('-----BEGIN RSA PRIVATE KEY-----');
AppendLine;
while not vPrivateKey.IsEmpty do
begin
Append(vPrivateKey.Substring(0,64));
AppendLine;
vPrivateKey:= vPrivateKey.Substring(64);
end;
Append('-----END RSA PRIVATE KEY-----');
vPrivateKey:= ToString;
finally
Free;
end;
Memo3.Text:= TOpenSSLCipher.Sha1WithRSASign(vSignSrc, TEncoding.UTF8, vPrivateKey)
.Replace('+','%2B',[rfReplaceAll])
.Replace('=','%3D',[rfReplaceAll])
.Replace(#13#10,'',[rfReplaceAll]);
end;
unit OpenSSL.Cipher;
interface
uses
SysUtils,
Classes,
Windows,
NetEncoding,
IdGlobal,
libeay32
{IdSSLOpenSSLHeaders};
type
TOpenSSLCipher = class
private
class procedure LoadLib();
protected
class function RSASign(APEVP_MD: PEVP_MD; const AContent: string; ACotentEncoding: TEncoding; ARSA: PRSA): string; overload;
class function RSASign(APEVP_MD: PEVP_MD; const AContent: string; ACotentEncoding: TEncoding; const APrivateKey: string): string;overload;
class function GetPrivateRSAKey(APBIO: PBIO): PRSA;
public
class function Sha1WithRSASign(const AContent: string; ACotentEncoding: TEncoding; const APrivateKey: string): string;
end;
implementation
class procedure TOpenSSLCipher.LoadLib;
begin
if not Load() then
raise Exception.Create('加载ssl库时出错,请检查ssl库文件是否存在或正确!');
end;
class function TOpenSSLCipher.GetPrivateRSAKey(APBIO: PBIO): PRSA;
begin
Result := PEM_read_bio_RSAPrivateKey(APBIO, nil, nil, nil);
if Result = nil then
raise Exception.Create('生成RSA密钥对象失败');
end;
class function TOpenSSLCipher.RSASign(APEVP_MD: PEVP_MD; const AContent: string; ACotentEncoding: TEncoding; ARSA: PRSA): string;
var
vCtx: EVP_MD_CTX;
vStringStream: TStringStream;
vMemoStream: TMemoryStream;
vHashedDataLen, vSignedDataLen: cardinal;
vHashedData, vSignedData: array [0 .. 10240] of byte;
begin
if ARSA = nil then
raise Exception.Create('RSA签名前出错:RSA密钥为空');
if ACotentEncoding = nil then
ACotentEncoding := TEncoding.UTF8;
vStringStream := TStringStream.Create(AContent, ACotentEncoding);
vMemoStream := TMemoryStream.Create;
try
EVP_MD_CTX_init(@vCtx);
EVP_SignInit(@vCtx, APEVP_MD);
EVP_SignUpdate(@vCtx, @vStringStream.Bytes[0], vStringStream.Size);
EVP_DigestFinal_ex(@vCtx, PIdAnsiChar(@vHashedData[0]), vHashedDataLen);
RSA_sign(APEVP_MD._type, PIdAnsiChar(@vHashedData[0]), vHashedDataLen, PIdAnsiChar(@vSignedData[0]), @vSignedDataLen, ARSA); // 64为SHA1的NID
EVP_MD_CTX_cleanup(@vCtx);
Result := TNetEncoding.Base64.EncodeBytesToString(@vSignedData[0], vSignedDataLen);
finally
vStringStream.Free;
vMemoStream.Free;
end;
end;
class function TOpenSSLCipher.RSASign(APEVP_MD: PEVP_MD; const AContent: string; ACotentEncoding: TEncoding; const APrivateKey: string): string;
var
vP_BioKey: PBIO;
vP_Rsa: PRSA;
vPrivateKeyStream: TStringStream;
begin
LoadLib();
vPrivateKeyStream := TStringStream.Create(APrivateKey, TEncoding.ASCII);
try
vP_BioKey := BIO_new_mem_buf(vPrivateKeyStream.Memory, vPrivateKeyStream.Size);
vP_Rsa := GetPrivateRSAKey(vP_BioKey);
Result := RSASign(APEVP_MD, AContent, ACotentEncoding, vP_Rsa);
BIO_free(vP_BioKey);
finally
vPrivateKeyStream.Free;
end;
end;
class function TOpenSSLCipher.Sha1WithRSASign(const AContent: string; ACotentEncoding: TEncoding; const APrivateKey: string): string;
begin
LoadLib();
Result := RSASign(EVP_sha1(), AContent, ACotentEncoding, APrivateKey);
end;
end.