dll开发环境: Delphi XE 10.1 Berlin
exe开发环境: Delphi 6
前提文章: Delphi RSA加解密(一)
目录
1. 概述
2. 准备工作
2.1 下载DEMO程序
2.2 字符编码说明
3. Cryption.dll封装
3.1 接口概况
3.2 uPub.pas单元代码
3.3 uInterface.pas单元代码
3.4 特别注意
4. 主程序模拟
4.1 程序目录结构说明
4.2 建立VCL应用程序
4.3 接口引入单元
4.4 接口加密验证
5. 结语
1. 概述
公司用D6来编写三方接口,当前做某银行转账接口,采用RSA算法。在上一篇文章Delphi RSA加解密(一)中在网上找到了解决方案。
D6版本低了,所有只有采用XE 10.1来封装dll。当前加密算法基于opelSSL,则依赖"libeay32.dll", 由于HIS程序目录下已有该dll,担心替换libeay32.dll会影响相关功能,特进行了特殊处理。
2. 准备工作
2.1 下载DEMO程序
在前提文章中提到了大佬分享的Demo. 下载后会发现bin目录有libeay32.dll。 这个文件很关键,后来我调试中,我使用XE 10.1对应的libeay32.dll文件,加密是不成功的。 但使用Demo的libeay32.dll进行加解密是正常的。
2.2 字符编码说明
原Demo的Delphi版本不确定,至少是D2010以后,版本太多了。
悲催的是,我只有XE 10.1,下了Demo后进行部分调整。
3. Cryption.dll封装
3.1 接口概况
该dll开发工具我使用Delphi XE 10.1 Berlin版本.
新建一个静态DLL工程,将原Demo的三个单元RSAOpenSSL.pas、libeay32.pas、EncdDecd_suman.pas拷贝到当前rsa目录下. 并加入当前dll工程. 另新建一个uPub.pas公共单元,新建一个uInterface.pas单元。工程目录如下
具体代码在后面,相信当前还在使用Delphi的,应该已能看懂的。
3.2 uPub.pas单元代码
unit uPub;
interface
uses
System.SysUtils, System.Classes, qaes, qstring, IdHashMessageDigest, IdHash;
type
TMD5= class(TIdHashMessageDigest5);
TAppPara = class
public
class function AppPath: string;
class function AppName: string;
end;
TFilePath = class(TAppPara)
public
class function IniFile: string;
end;
//写日志
procedure systemLog(Msg: AnsiString);
implementation
procedure systemLog(Msg: AnsiString);
var
F: TextFile;
FileName: string;
ExeRoad: string;
begin
try
ExeRoad := ExtractFilePath(ParamStr(0));
if ExeRoad[Length(ExeRoad)] = '\' then
SetLength(ExeRoad, Length(ExeRoad) - 1);
if not DirectoryExists(ExeRoad + 'log') then
begin
CreateDir(ExeRoad + '\log');
end;
FileName := ExeRoad + '\log\DLL_Log' + FormatDateTime('YYMMDD', NOW) + '.txt';
if not FileExists(FileName) then
begin
AssignFile(F, FileName);
ReWrite(F);
end
else
AssignFile(F, FileName);
Append(F);
Writeln(F, FormatDateTime('HH:NN:SS.zzz ', Now) + Msg);
CloseFile(F);
except
//可能在事务中调用,避免意外
Exit;
end;
end;
{ TAppPara }
class function TAppPara.AppName: string;
begin
Result := ExtractFileName(ParamStr(0));
end;
class function TAppPara.AppPath: string;
begin
Result := ExtractFilePath(ParamStr(0));
end;
{ TFilePath }
class function TFilePath.IniFile: string;
begin
Result := AppPath + 'set.ini';
end;
end.
3.3 uInterface.pas单元代码
需要注意,由于D6版本低,此处参数使用PAnsiChar。
unit uInterface;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, EncdDecd, Qjson,
RSAOpenSSL;
var
FRSAOpenSSL : TRSAOpenSSL;
//----------------------------------测试部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//测试
function dll_test: Byte; stdcall;
function dll_chinese_test(sIn: AnsiString; var sOut: PAnsiChar): Byte; stdcall;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//----------------------------------加密部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//RSA 加密 初始化
function dll_rsa_init(pubFile, priFile: PAnsiChar): Byte; stdcall;
//RSA SHA1加密
function dll_sha1_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
//RSA SHA256加密
function dll_sha256_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
//RSA SHA512加密
function dll_sha512_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
//RSA SHA1WITHRSA 加密
function dll_sha1withrsa_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
//RSA SHA256WITHRSA 加密
function dll_sha256withrsa_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
//RSA SHA512WITHRSA 加密
function dll_sha512withrsa_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
//RSA 加密 释放
function dll_rsa_uninit: Byte; stdcall;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
implementation
uses uPub, qaes;
//----------------------------------测试部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//测试
function dll_test: Byte; stdcall;
begin
Result:= 1;
end;
function dll_chinese_test(sIn: AnsiString; var sOut: PAnsiChar): Byte; stdcall;
begin
result:= 0;
sOut:= PAnsiChar(sIn);
Result:= 1;
end;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//RSA 加密 初始化
function dll_rsa_init(pubFile, priFile: PAnsiChar): Byte; stdcall;
begin
result:= 0;
if (not FileExists(priFile))
or (not FileExists(pubFile)) then
Exit;
if not Assigned(FRSAOpenSSL) then
FRSAOpenSSL := TRSAOpenSSL.Create(AnsiString(pubFile), AnsiString(priFile));
Result:= 1;
end;
//RSA SHA1加密
function dll_sha1_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
var
sAnsiStr: AnsiString;
sOut: AnsiString;
begin
result:= 0;
sAnsiStr:= UTF8Encode(sIN);
sOut:= FRSAOpenSSL.SHA1(sAnsiStr);
pOut:= PAnsiChar(sOut);
Result:= 1;
end;
//RSA SHA256加密
function dll_sha256_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
var
sAnsiStr: AnsiString;
sOut: AnsiString;
begin
result:= 0;
sAnsiStr:= UTF8Encode(sIN);
sOut:= FRSAOpenSSL.SHA256(sAnsiStr);
pOut:= PAnsiChar(sOut);
Result:= 1;
end;
//RSA SHA512加密
function dll_sha512_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
var
sAnsiStr: AnsiString;
sOut: AnsiString;
begin
result:= 0;
sAnsiStr:= UTF8Encode(sIN);
sOut:= FRSAOpenSSL.SHA512(sAnsiStr);
pOut:= PAnsiChar(sOut);
Result:= 1;
end;
//RSA SHA1WITHRSA 加密
function dll_sha1withrsa_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
var
sAnsiStr: AnsiString;
sOut: AnsiString;
begin
result:= 0;
sAnsiStr:= UTF8Encode(sIn);
sOut:= FRSAOpenSSL.SHA1_Sign_PK(sAnsiStr);
pOut:= PAnsiChar(sOut);
Result:= 1;
end;
//RSA SHA256WITHRSA 加密
function dll_sha256withrsa_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
var
sAnsiStr: AnsiString;
sOut: AnsiString;
begin
result:= 0;
sAnsiStr:= UTF8Encode(sIn);
sOut:= FRSAOpenSSL.SHA256_Sign_PK(sAnsiStr);
pOut:= PAnsiChar(sOut);
Result:= 1;
end;
//RSA SHA512WITHRSA 加密
function dll_sha512withrsa_encrypt(sIn: PAnsiChar; var pOut: PAnsiChar): Byte; stdcall;
var
sAnsiStr: AnsiString;
sOut: AnsiString;
begin
result:= 0;
sAnsiStr:= UTF8Encode(sIn);
sOut:= FRSAOpenSSL.SHA512_Sign_PK(sAnsiStr);
pOut:= PAnsiChar(sOut);
Result:= 1;
end;
//RSA 加密 释放
function dll_rsa_uninit: Byte; stdcall;
begin
Result:= 0;
if Assigned(FRSAOpenSSL) then
FreeAndNil(FRSAOpenSSL);
Result:= 1;
end;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
end.
3.4 特别注意
在第四章我提到了程序目录(原因请看4.1),而libeay32.pas单元的第1290行,这个里引入了libeay32.dll,但是在,在我当前设计的目录里,Cryption.dll是和libeay32.dll放在程序目录下的bin目录下,通过Demo程序调用的话,程序认定的目录其实是程序根目录,所以在这里必须特殊处理下,加入路劲:
const
LIBEAY_DLL_NAME = 'bin\libeay32.dll';
如果编写dll与主程序同一个目录,不担心加密的libeay32.dll影响的话,就放在程序目录下就可以了。
4. 主程序模拟
注意: SHA1WITHRSA、SHA256WITHRSA、SHA512WITHRSA需要公私钥的支持.
4.1 程序目录结构说明
在文章开始部分,我已说明使用Demo的libeay32.dll可能与主程序原本的libeay32.dll冲突,所以,第三章封装的Cryptiond.dll和libeay32.dll,以及可能用到的公私钥文件,我一起放在程序的某个目录下。
bin目录如下所示
4.2 建立VCL应用程序
丢下控件,界面如图所示:
主要是初始化时候,我指定了公私钥文件,就像Demo里窗体创建一样。
主窗体代码如下:
unit uFrmMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, EncdDecd;
type
TForm2 = class(TForm)
btn1: TButton;
btn2: TButton;
btn3: TButton;
btn4: TButton;
btn5: TButton;
btn6: TButton;
btn7: TButton;
btn8: TButton;
lbl1: TLabel;
lbl2: TLabel;
mmo_in: TMemo;
mmo_out: TMemo;
procedure btn1Click(Sender: TObject);
procedure btn8Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure btn5Click(Sender: TObject);
procedure btn3Click(Sender: TObject);
procedure btn4Click(Sender: TObject);
procedure btn6Click(Sender: TObject);
procedure btn7Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
priFile: AnsiString;
pubFile: AnsiString;
end;
var
Form2: TForm2;
iRet: Byte;
implementation
uses uCryption;
{$R *.dfm}
procedure TForm2.btn1Click(Sender: TObject);
begin
iRet:= 0;
pubFile:= 'bin\apprsakey.pub';
priFile:= 'bin\apprsakey.pri';
iRet:= dll_rsa_init(PChar(pubFile), PChar(priFile));
if iRet<> 1 then
ShowMessage('初始化失败!')
end;
procedure TForm2.btn8Click(Sender: TObject);
begin
iRet:= 0;
iRet:= dll_rsa_uninit;
if iRet= 1 then
ShowMessage('释放成功!')
else
ShowMessage('释放失败!')
end;
procedure TForm2.btn2Click(Sender: TObject);
var
pOut: PChar;
sIn: string;
begin
sIn:= StringReplace(mmo_in.Lines.Text,#13#10,'',[rfIgnoreCase,rfReplaceAll]);
iRet:= 0;
pOut:= nil;
iRet:= dll_sha1_encrypt(PChar(sIn), pOut);
if iRet=1 then
mmo_out.Lines.Add(pOut)
else
ShowMessage('dll_sha1_encrypt加密失败!');
pOut:= nil;
end;
procedure TForm2.btn5Click(Sender: TObject);
var
pOut: PChar;
sIn: string;
begin
sIn:= StringReplace(mmo_in.Lines.Text,#13#10,'',[rfIgnoreCase,rfReplaceAll]);
iRet:= 0;
pOut:= nil;
iRet:= dll_sha1withrsa_encrypt(PChar(sIn), pOut);
if iRet=1 then
mmo_out.Lines.Add(pOut)
else
ShowMessage('dll_sha1withrsa_encrypt加密失败!');
pOut:= nil;
end;
procedure TForm2.btn3Click(Sender: TObject);
var
pOut: PChar;
sIn: string;
begin
sIn:= StringReplace(mmo_in.Lines.Text,#13#10,'',[rfIgnoreCase,rfReplaceAll]);
iRet:= 0;
pOut:= nil;
iRet:= dll_sha256_encrypt(PChar(sIn), pOut);
if iRet=1 then
mmo_out.Lines.Add(pOut)
else
ShowMessage('dll_sha256_encrypt加密失败!');
pOut:= nil;
end;
procedure TForm2.btn4Click(Sender: TObject);
var
pOut: PChar;
sIn: string;
begin
sIn:= StringReplace(mmo_in.Lines.Text,#13#10,'',[rfIgnoreCase,rfReplaceAll]);
iRet:= 0;
pOut:= nil;
iRet:= dll_sha512_encrypt(PChar(sIn), pOut);
if iRet=1 then
mmo_out.Lines.Add(pOut)
else
ShowMessage('dll_sha512_encrypt加密失败!');
pOut:= nil;
end;
procedure TForm2.btn6Click(Sender: TObject);
var
pOut: PChar;
sIn: string;
begin
sIn:= StringReplace(mmo_in.Lines.Text,#13#10,'',[rfIgnoreCase,rfReplaceAll]);
iRet:= 0;
pOut:= nil;
iRet:= dll_sha256withrsa_encrypt(PChar(sIn), pOut);
if iRet=1 then
mmo_out.Lines.Add(pOut)
else
ShowMessage('dll_sha256withrsa_encrypt加密失败!');
pOut:= nil;
end;
procedure TForm2.btn7Click(Sender: TObject);
var
pOut: PChar;
sIn: string;
begin
sIn:= StringReplace(mmo_in.Lines.Text,#13#10,'',[rfIgnoreCase,rfReplaceAll]);
iRet:= 0;
pOut:= nil;
iRet:= dll_sha512withrsa_encrypt(PChar(sIn), pOut);
if iRet=1 then
mmo_out.Lines.Add(pOut)
else
ShowMessage('dll_sha512withrsa_encrypt加密失败!');
pOut:= nil;
end;
end.
4.3 接口引入单元
需要注意dllName是按目录指定dll位置.
unit uCryption;
interface
uses
Classes;
const
dllName= 'bin\Cryption.dll';
function dll_chinese_test(sIn: AnsiString; var sOut: PAnsiChar): Byte; stdcall; external dllName;
//RSA 加密 初始化
function dll_rsa_init(pubFile, priFile: PChar): Byte; stdcall; external dllName;
//RSA SHA1加密
function dll_sha1_encrypt(sIn: PChar; var pOut: PChar): Byte; stdcall; external dllName;
//RSA SHA256加密
function dll_sha256_encrypt(sIn: PChar; var pOut: PChar): Byte; stdcall; external dllName;
//RSA SHA512加密
function dll_sha512_encrypt(sIn: PChar; var pOut: PChar): Byte; stdcall; external dllName;
//RSA SHA1WITHRSA 加密
function dll_sha1withrsa_encrypt(sIn: PChar; var pOut: PChar): Byte; stdcall; external dllName;
//RSA SHA256WITHRSA 加密
function dll_sha256withrsa_encrypt(sIn: PChar; var pOut: PChar): Byte; stdcall; external dllName;
//RSA SHA512WITHRSA 加密
function dll_sha512withrsa_encrypt(sIn: PChar; var pOut: PChar): Byte; stdcall; external dllName;
//RSA 加密 释放
function dll_rsa_uninit: Byte; stdcall; external dllName;
implementation
end.
4.4 接口加密验证
在线SHA1 SHA-1在线加密工具 与Demo加密对比
在线SHA256 sha256在线解密 在线加密 与Demo加密对比
在线SHA512可验证 sha512在线解密 在线加密 与Demo加密对比
另 SHA1WITHRSA、SHA256WITHRSA、SHA512WITHRSA在线验证不好找
后面我本地写个对照下看看,后面补充.
5. 结语
仅供参考。