上周,另一部门需要支援解决数字签名问题。但因为之前也没做过,现学现卖。此方面可参考的中文资料较少,特作分享,方便查阅。
有关数字签名的概念、原理,这里就不做介绍了,请自行google或百度。
利用证书对文件进行签名,从证书来源看,可分为两种:1、软证书:就是将*.pfx文件导入到系统中,这意味着,只要登录到PC中的用户,均可以使用该证书;2、硬证书:通常将证书存放到uKey中(smart card),这样的好处是,只有拥有usb key的人才有权限使用该证书。
USB Key通常支持CryptToAPI——除非特殊安全需要,只公布使用自己的接口,不支持微软接口。由于使用CryptToAPI,使用起来较繁琐,微软提供了CAPICOM组件,方便开发。
不论是硬证书或软证书,只要支持CryptToAPI接口,那么CAPICOM均可使用。为此本次内容以CAPICOM,作为数字签名功能的基础。
动手之前,首先要熟悉数字签名的过程。通过分析,主要是两部分:数字签名(身份标识及防篡改)和数字信封;其实按业务流程,签名之前还有签章的过程(也就是通常的盖章);过程大致如下:
发送方
1、验证证书是否准备好?(若是硬证书,usbkey是否已插入;判断证书是否有效);
2、对文件进行签名;
3、对文件进行数字信封(公钥加密);
4、可选:填入CSP(加密服务提供商,通常是在USB Key当中)信息
接收方:
1、获取文件,读取CSP信息;
2、依据CSP信息,获取相关证书并验证;
3、利用证书进行数字解封;
4、签名验证,确认身份及文件的完整性(是否被篡改);
依据以上分析,程序可这样设计,由于USB Key可能支持CAPICOM,也可能不支持,所以,后续可能会有相应由多种方法去执行签名。可提取接口,来解除这样的依赖。
接口定义如下:
IDigitalIntf = interface(IUNKNOWN)
['{78657307-FD4A-452F-91FF-956379A7F654}']
//验证设备
function VerifyUserAvailable: Boolean;
//签名与数字信封加密
function Pack(const sInPath: string; const sOutPath: string; bOverride: Boolean): Boolean;
//数字信封解密与签名验证
function Unpack(const sInPath: string; const sOutPath: string;
bCreateDirectory: Boolean): Boolean;
//获取数字指纹
function GetThumbPrint: string;
//获取证书信息
function GetCertficateInfo(var ACertInfo: TStampInfo): Boolean;
end;
CAPICOM实现类,构造如下:
TDigital_CAPICOM = class(TInterfacedObject, IDigitalIntf)
private
FProviderName, FStoreName: string;
function GetStoreByName(AStoreName: string): TStore;
protected
FStoreList: TStringList;
ICert: ICertificate;
ICert2: ICertificate2;
FPublicKey: string;//公钥
FPKLength: Integer;//算法长度
FAlgType: string; // 算法类型
{----------------------方法定义-----------------------}
//证书库操作
function OpenStore(AStoreName: string): TStore;
procedure CloseStore;
//获取证书接口
procedure GetCertificate;
//执行文件签名
function SignedFile(const AFileName: s