delphi实现数字签名

ⅰ亾dé卋堺 提交于 2019-12-02 21:23:32

delphi实现数字签名   

上周,另一部门需要支援解决数字签名问题。但因为之前也没做过,现学现卖。此方面可参考的中文资料较少,特作分享,方便查阅。      上周,另一部门需要支援解决数字签名问题。但因为之前也没做过,现学现卖。此方面可参考的中文资料较少,特作分享,方便查阅。        有关数字签名的概念、原理,这里就不做介绍了,请自行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,也可能不支持,所以,后续可能会有相应由多种方法去执行签名。可提取接口,来解除这样的依赖。      接口定义如下: [delphi] view plaincopyprint? 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;    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实现类,构造如下: [delphi] view plaincopyprint? 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: string;      EncodeType: CAPICOM_ENCODING_TYPE): Boolean;    //验证文件签名    function VerifySign(const AFileName: string): Boolean;    //附加签名信息    function AppendSignedContent(const AFileName, ASignedContent: string): Boolean;    //分解签名信息    function ExtractSignedContent(const AFileName: string): string;    {-----------------------------------------------------}    {---------------------属性定义------------------------}    //CSP提供商    property ProviderName : string read FProviderName;    //证书存放位置    property StoreName : string read FStoreName;    {-----------------------------------------------------}   public    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;      constructor Create(const StoreName, ProviderName: string); virtual;    destructor Destroy; override;   end;    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: string;      EncodeType: CAPICOM_ENCODING_TYPE): Boolean;    //验证文件签名    function VerifySign(const AFileName: string): Boolean;    //附加签名信息    function AppendSignedContent(const AFileName, ASignedContent: string): Boolean;    //分解签名信息    function ExtractSignedContent(const AFileName: string): string;    {-----------------------------------------------------}    {---------------------属性定义------------------------}    //CSP提供商    property ProviderName : string read FProviderName;    //证书存放位置    property StoreName : string read FStoreName;    {-----------------------------------------------------}  public    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;    constructor Create(const StoreName, ProviderName: string); virtual;    destructor Destroy; override;  end; 其实现代码去除了关键信息: [delphi] view plaincopyprint?   [delphi] view plaincopyprint? function TDigital_CAPICOM.AppendSignedContent(const AFileName,    ASignedContent: string): Boolean;   var    msSrc, ms1: TMemoryStream;    iLen: Integer;    sSignedData, sLength: string;    BDA: TByteDynArray;   begin    if not FileExists(AFileName) then      raise Exception.Create('文件"' + AFileName + '"不存在');    //拼接签名信息      sLength := IntToStr(Length(ASignedContent));    sLength := FillChars(sLength, HashString_Length);    sSignedData := HYMSignature + sLength + ASignedContent;    BDA:= String2Byte(sSignedData);    iLen := Length(sSignedData);        msSrc := TMemoryStream.Create;    ms1 := TMemoryStream.Create;    try      msSrc.LoadFromFile(AFileName);      ms1.Write(BDA[0], iLen); //写入文件头信息      ms1.Write(msSrc.Memory^, msSrc.Size); //把文件内容附加上      ms1.SaveToFile(AFileName);    finally      ms1.Free;      msSrc.Free;    end;    Result := True;   end;     procedure TDigital_CAPICOM.CloseStore;   var    vStore: TStore;    iCnt: Integer;   begin    try      for iCnt := 0 to FStoreList.Count - 1 do      begin        vStore := TStore(FStoreList.Objects[iCnt]);        vStore.Disconnect;      end;    except      raise Exception.Create('关闭密钥库失败!');    end;   end;     constructor TDigital_CAPICOM.Create(const StoreName, ProviderName: string);   begin    CoInitialize(nil);    FProviderName:= ProviderName;    FStoreName := StoreName;    FStoreList:= TStringlist.create;    GetCertificate;   end;     destructor TDigital_CAPICOM.Destroy;   begin    FStoreList.Free;    ICert := nil;    ICert2:= nil;    CoUninitialize;    inherited;   end;     function TDigital_CAPICOM.ExtractSignedContent(    const AFileName: string): string;   var    fs: TFileStream;    iHeadLen, iContentLen, iPos: Integer;    sContentLength: string;    ms: TMemoryStream;    BDA_Head, BDA_Cont: TByteDynArray;   begin    Result := '';    if not FileExists(AFileName) then      raise Exception.Create('文件"' + AFileName + '"不存在');      iHeadLen := Length(HYMSignature) + HashString_Length;    SetLength(BDA_Head, iHeadLen);    ms:= TMemoryStream.Create;    ms.LoadFromFile(AFileName);    fs := TFileStream.Create(AFileName, fmCreate);    try      ms.Position:= 0;      ms.Read(BDA_Head[0], iHeadLen);      sContentLength := Byte2String(BDA_Head); //含有长度信息      iPos := Pos(HYMSignature, sContentLength);      if iPos > 0 then      begin        //取得长度        iContentLen := StrToInt(Copy(sContentLength, Length(HYMSignature) + 1, MaxInt));        SetLength(BDA_Cont, iContentLen);        ms.Read(BDA_Cont[0], iContentLen);        Result := Byte2String(BDA_Cont);        //该位置之后的内容为真正需要的        fs.CopyFrom(ms, ms.Size - ms.Position); //读取文件内容去除文件头部分        fs.Position := 0;      end    finally      ms.Free;      fs.Free;    end;   end;     function TDigital_CAPICOM.GetCertficateInfo(    var ACertInfo: TStampInfo): Boolean;   var    iCnt: Integer;   begin    Result := True;    if ICert <> nil then    begin      ACertInfo.PKAlg := FAlgType;      ACertInfo.PKLength := FPKLength;      for iCnt := 0 to Length(FPublicKey) - 1 do      begin        ACertInfo.PKContent[iCnt] := FPublicKey[iCnt + 1];      end;      ACertInfo.EndDate:= ICert.ValidToDate;      ACertInfo.DispachTime:= ICert.ValidFromDate;    end    else      result:= False;   end;     procedure TDigital_CAPICOM.GetCertificate;   var    vStore: TStore;    iCnt: Integer;    IBaseIntf: IInterface;    ICert2Dsp: ICertificate2Disp;   begin    if ICert2 = nil then    begin      vStore := OpenStore(FStoreName);      for iCnt := 1 to vStore.Certificates.Count do      begin        IBaseIntf := vStore.Certificates.Item[iCnt];        try          if IBaseIntf.QueryInterface(ICertificate2Disp, ICert2Dsp) = 0          then          begin            //确认硬件是否连接            if ICert2Dsp.HasPrivateKey then            begin              //确认是否为指定CSP提供商              if ((FProviderName = CSPProvider_ePass) and                  ((ICert2Dsp.PrivateKey.ProviderName = CSPProvider_ePass_1K) or                   (ICert2Dsp.PrivateKey.ProviderName = CSPProvider_ePass_3K)))                 or (ICert2Dsp.PrivateKey.ProviderName = FProviderName)              then              begin                IBaseIntf.QueryInterface(IID_ICertificate2, ICert2);                IBaseIntf.QueryInterface(IID_ICertificate, ICert);                FPublicKey:= ICert2Dsp.publickey.EncodedKey.Format(True);                FPKLength:= ICert2Dsp.publickey.Length;                FAlgType:= ICert2Dsp.publickey.Algorithm.FriendlyName;              end;            end;          end;        except          //某些不支持CAPICOM的,会出现异常          ICert2 := nil;        end;      end;    end;   end;     function TDigital_CAPICOM.GetStoreByName(AStoreName: string): TStore;   var    i: integer;   begin    i := FStoreList.IndexOf(AStoreName);    if i >= 0 then      result := FStoreList.Objects[i] as Tstore    else      result := nil;   end;     function TDigital_CAPICOM.GetThumbPrint: string;   begin    Result := '';    if ICert <> nil then      Result := ICert.Thumbprint;   end;     function TDigital_CAPICOM.OpenStore(AStoreName: string): TStore;   var    vStore: TStore;   begin    vStore := self.GetStoreByName(AStoreName);    if vStore = nil then    try      vStore := TStore.Create(nil);      //默认为从CurrenUser读取, 后续可能会是CAPICOM_SMART_CARD_USER_STORE 智能卡      vStore.Open(CAPICOM_CURRENT_USER_STORE, AStoreName,         CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED or CAPICOM_STORE_OPEN_INCLUDE_ARCHIVED         or CAPICOM_STORE_OPEN_EXISTING_ONLY);      self.FStoreList.AddObject(AStoreName, vStore);    except     on E:exception do      raise exception.Create('无法打开密钥库!'+E.Message);    end;    Result := vStore;   end;     function TDigital_CAPICOM.Pack(const sInPath, sOutPath: string;    bOverride: Boolean): Boolean;   var    EnvelopedData: IEnvelopedData;    BUFFER: WideString;    FileStm: TFileStream;    iP, oP: string;   begin    ip:= StringReplace(sInPath, '\\', '\', [rfReplaceAll]);    op:= StringReplace(sOutPath, '\\', '\', [rfReplaceAll]);    Result := True;    EnvelopedData := CoEnvelopedData.Create;    //指定采用的CSP算法类型    EnvelopedData.Algorithm.Name := Algorithm;    //指定加密长度    EnvelopedData.Algorithm.KeyLength := EnLength;    try      //获取证书接口      GetCertificate;      //目前sInPath是一个文件夹,先压缩,再解密      Files2ZipArchive(ip, op, RZipPassWd);      //执行签名      SignedFile(op, CAPICOM_ENCODE_BASE64);      //获取要加密的内容      FileStm := TFileStream.Create(sOutPath, fmOpenRead);      try        Pointer(Buffer):= SysAllocStringByteLen (nil, FileStm.Size);        FileStm.ReadBuffer(Pointer(Buffer)^, FileStm.Size);        EnvelopedData.Content:= Buffer;      finally        FileStm.Free;      end;      //基于64位编码加密      EnvelopedData.Recipients.Add(ICert2);      Buffer:= EnvelopedData.Encrypt(CAPICOM_ENCODE_BASE64);      //输出加密内容      FileStm := TFileStream.Create(sOutPath, fmCreate);      try        FileStm.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer)));      finally        FileStm.Free;      end;    except      Result := False;    end;   end;     function TDigital_CAPICOM.SignedFile(const AFileName: string;    EncodeType: CAPICOM_ENCODING_TYPE): Boolean;   var    Signer: ISigner2;    SignedData: ISignedData;    HashString: string;    SignedContent: WideString;   begin    Result := True;    try      GetCertificate;      //获取文件哈希值      HashString:= GetFileHash(AFileName);      //构建 签名者      Signer := CoSigner.Create;      Signer.Certificate := ICert2;      //构建 数据签名对象      SignedData := CoSignedData.Create;      //执行签名      SignedData.Content:= HashString;      SignedContent := SignedData.Sign(Signer, False, EncodeType);      //附加签名信息      AppendSignedContent(AFileName, SignedContent);    except      Result := False;    end;   end;     function TDigital_CAPICOM.Unpack(const sInPath, sOutPath: string;    bCreateDirectory: Boolean): Boolean;   var    EnvelopedData: IEnvelopedData;    BUFFER: WideString;    FileStm: TFileStream;    vDecryptFileName: string;   begin    Result := True;    EnvelopedData := CoEnvelopedData.Create;    //指定采用的CSP算法类型    EnvelopedData.Algorithm.Name := Algorithm;    //指定加密长度    EnvelopedData.Algorithm.KeyLength := EnLength;    try      //获取数字证书接口      GetCertificate;      //关联证书以解密      EnvelopedData.Recipients.Add(ICert2);      //获取加密内容      FileStm := TFileStream.Create(sInPath, fmOpenRead );      try        Pointer(Buffer):= SysAllocStringByteLen (nil, FileStm.Size);        FileStm.ReadBuffer(Pointer(Buffer)^, FileStm.Size);      finally        FileStm.Free;      end;      //解密      EnvelopedData.Decrypt(Buffer);      Buffer:= EnvelopedData.Content;      //输出解密内容      vDecryptFileName:= sOutPath + ExtractFileName(sInPath);      FileStm := TFileStream.Create(vDecryptFileName, fmCreate);      try        FileStm.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer)));      finally        FileStm.Free;      end;      //验证签名      VerifySign(vDecryptFileName);      //因为有压缩,再解压   ZipArchive2Files      ZipArchive2Files(vDecryptFileName, sOutPath, RZipPassWd);      DeleteFile(PAnsiChar(vDecryptFileName));    except      Result := False;    end;   end;     function TDigital_CAPICOM.VerifySign(const AFileName: string): Boolean;   var    SignedData: ISignedData;    HashString: WideString;    ASignedContent: string;   begin    Result := True;    try      GetCertificate;      //先获取签名信息,因为会做信息分离,还原出加上签名前的数据      ASignedContent:= ExtractSignedContent(AFileName);      //获取文件哈希值      HashString:= GetFileHash(AFileName);      //构建 数据签名对象      SignedData := CoSignedData.Create;      SignedData.Content := HashString;      //执行检查      SignedData.Verify(ASignedContent, False, CAPICOM_VERIFY_SIGNATURE_ONLY);    except      Result := False;      Raise Exception.Create('数字签名校验失败!');    end;   end;     function TDigital_CAPICOM.VerifyUserAvailable: Boolean;   begin    Result := False;    if (ICert2 <> nil) and ICert2.HasPrivateKey then      Result:= True;   end;   function TDigital_CAPICOM.AppendSignedContent(const AFileName,  ASignedContent: string): Boolean; var  msSrc, ms1: TMemoryStream;  iLen: Integer;  sSignedData, sLength: string;  BDA: TByteDynArray; begin  if not FileExists(AFileName) then    raise Exception.Create('文件"' + AFileName + '"不存在');  //拼接签名信息    sLength := IntToStr(Length(ASignedContent));  sLength := FillChars(sLength, HashString_Length);  sSignedData := HYMSignature + sLength + ASignedContent;  BDA:= String2Byte(sSignedData);  iLen := Length(sSignedData);    msSrc := TMemoryStream.Create;  ms1 := TMemoryStream.Create;  try    msSrc.LoadFromFile(AFileName);    ms1.Write(BDA[0], iLen); //写入文件头信息    ms1.Write(msSrc.Memory^, msSrc.Size); //把文件内容附加上    ms1.SaveToFile(AFileName);  finally    ms1.Free;    msSrc.Free;  end;  Result := True; end; procedure TDigital_CAPICOM.CloseStore; var  vStore: TStore;  iCnt: Integer; begin  try    for iCnt := 0 to FStoreList.Count - 1 do    begin      vStore := TStore(FStoreList.Objects[iCnt]);      vStore.Disconnect;    end;  except    raise Exception.Create('关闭密钥库失败!');  end; end; constructor TDigital_CAPICOM.Create(const StoreName, ProviderName: string); begin  CoInitialize(nil);  FProviderName:= ProviderName;  FStoreName := StoreName;  FStoreList:= TStringlist.create;  GetCertificate; end; destructor TDigital_CAPICOM.Destroy; begin  FStoreList.Free;  ICert := nil;  ICert2:= nil;  CoUninitialize;  inherited; end; function TDigital_CAPICOM.ExtractSignedContent(  const AFileName: string): string; var  fs: TFileStream;  iHeadLen, iContentLen, iPos: Integer;  sContentLength: string;  ms: TMemoryStream;  BDA_Head, BDA_Cont: TByteDynArray; begin  Result := '';  if not FileExists(AFileName) then    raise Exception.Create('文件"' + AFileName + '"不存在');    iHeadLen := Length(HYMSignature) + HashString_Length;  SetLength(BDA_Head, iHeadLen);  ms:= TMemoryStream.Create;  ms.LoadFromFile(AFileName);  fs := TFileStream.Create(AFileName, fmCreate);  try    ms.Position:= 0;    ms.Read(BDA_Head[0], iHeadLen);    sContentLength := Byte2String(BDA_Head); //含有长度信息    iPos := Pos(HYMSignature, sContentLength);    if iPos > 0 then    begin      //取得长度      iContentLen := StrToInt(Copy(sContentLength, Length(HYMSignature) + 1, MaxInt));      SetLength(BDA_Cont, iContentLen);      ms.Read(BDA_Cont[0], iContentLen);      Result := Byte2String(BDA_Cont);      //该位置之后的内容为真正需要的      fs.CopyFrom(ms, ms.Size - ms.Position); //读取文件内容去除文件头部分      fs.Position := 0;    end  finally    ms.Free;    fs.Free;  end; end; function TDigital_CAPICOM.GetCertficateInfo(  var ACertInfo: TStampInfo): Boolean; var  iCnt: Integer; begin  Result := True;  if ICert <> nil then  begin    ACertInfo.PKAlg := FAlgType;    ACertInfo.PKLength := FPKLength;    for iCnt := 0 to Length(FPublicKey) - 1 do    begin      ACertInfo.PKContent[iCnt] := FPublicKey[iCnt + 1];    end;    ACertInfo.EndDate:= ICert.ValidToDate;    ACertInfo.DispachTime:= ICert.ValidFromDate;  end  else    result:= False; end; procedure TDigital_CAPICOM.GetCertificate; var  vStore: TStore;  iCnt: Integer;  IBaseIntf: IInterface;  ICert2Dsp: ICertificate2Disp; begin  if ICert2 = nil then  begin    vStore := OpenStore(FStoreName);    for iCnt := 1 to vStore.Certificates.Count do    begin      IBaseIntf := vStore.Certificates.Item[iCnt];      try        if IBaseIntf.QueryInterface(ICertificate2Disp, ICert2Dsp) = 0        then        begin          //确认硬件是否连接          if ICert2Dsp.HasPrivateKey then          begin            //确认是否为指定CSP提供商            if ((FProviderName = CSPProvider_ePass) and                ((ICert2Dsp.PrivateKey.ProviderName = CSPProvider_ePass_1K) or                 (ICert2Dsp.PrivateKey.ProviderName = CSPProvider_ePass_3K)))               or (ICert2Dsp.PrivateKey.ProviderName = FProviderName)            then            begin              IBaseIntf.QueryInterface(IID_ICertificate2, ICert2);              IBaseIntf.QueryInterface(IID_ICertificate, ICert);              FPublicKey:= ICert2Dsp.publickey.EncodedKey.Format(True);              FPKLength:= ICert2Dsp.publickey.Length;              FAlgType:= ICert2Dsp.publickey.Algorithm.FriendlyName;            end;          end;        end;      except        //某些不支持CAPICOM的,会出现异常        ICert2 := nil;      end;    end;  end; end; function TDigital_CAPICOM.GetStoreByName(AStoreName: string): TStore; var  i: integer; begin  i := FStoreList.IndexOf(AStoreName);  if i >= 0 then    result := FStoreList.Objects[i] as Tstore  else    result := nil; end; function TDigital_CAPICOM.GetThumbPrint: string; begin  Result := '';  if ICert <> nil then    Result := ICert.Thumbprint; end; function TDigital_CAPICOM.OpenStore(AStoreName: string): TStore; var  vStore: TStore; begin  vStore := self.GetStoreByName(AStoreName);  if vStore = nil then  try    vStore := TStore.Create(nil);    //默认为从CurrenUser读取, 后续可能会是CAPICOM_SMART_CARD_USER_STORE 智能卡    vStore.Open(CAPICOM_CURRENT_USER_STORE, AStoreName,       CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED or CAPICOM_STORE_OPEN_INCLUDE_ARCHIVED       or CAPICOM_STORE_OPEN_EXISTING_ONLY);    self.FStoreList.AddObject(AStoreName, vStore);  except   on E:exception do    raise exception.Create('无法打开密钥库!'+E.Message);  end;  Result := vStore; end; function TDigital_CAPICOM.Pack(const sInPath, sOutPath: string;  bOverride: Boolean): Boolean; var  EnvelopedData: IEnvelopedData;  BUFFER: WideString;  FileStm: TFileStream;  iP, oP: string; begin  ip:= StringReplace(sInPath, '\\', '\', [rfReplaceAll]);  op:= StringReplace(sOutPath, '\\', '\', [rfReplaceAll]);  Result := True;  EnvelopedData := CoEnvelopedData.Create;  //指定采用的CSP算法类型  EnvelopedData.Algorithm.Name := Algorithm;  //指定加密长度  EnvelopedData.Algorithm.KeyLength := EnLength;  try    //获取证书接口    GetCertificate;    //目前sInPath是一个文件夹,先压缩,再解密    Files2ZipArchive(ip, op, RZipPassWd);    //执行签名    SignedFile(op, CAPICOM_ENCODE_BASE64);    //获取要加密的内容    FileStm := TFileStream.Create(sOutPath, fmOpenRead);    try      Pointer(Buffer):= SysAllocStringByteLen (nil, FileStm.Size);      FileStm.ReadBuffer(Pointer(Buffer)^, FileStm.Size);      EnvelopedData.Content:= Buffer;    finally      FileStm.Free;    end;    //基于64位编码加密    EnvelopedData.Recipients.Add(ICert2);    Buffer:= EnvelopedData.Encrypt(CAPICOM_ENCODE_BASE64);    //输出加密内容    FileStm := TFileStream.Create(sOutPath, fmCreate);    try      FileStm.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer)));    finally      FileStm.Free;    end;  except    Result := False;  end; end; function TDigital_CAPICOM.SignedFile(const AFileName: string;  EncodeType: CAPICOM_ENCODING_TYPE): Boolean; var  Signer: ISigner2;  SignedData: ISignedData;  HashString: string;  SignedContent: WideString; begin  Result := True;  try    GetCertificate;    //获取文件哈希值    HashString:= GetFileHash(AFileName);    //构建 签名者    Signer := CoSigner.Create;    Signer.Certificate := ICert2;    //构建 数据签名对象    SignedData := CoSignedData.Create;    //执行签名    SignedData.Content:= HashString;    SignedContent := SignedData.Sign(Signer, False, EncodeType);    //附加签名信息    AppendSignedContent(AFileName, SignedContent);  except    Result := False;  end; end; function TDigital_CAPICOM.Unpack(const sInPath, sOutPath: string;  bCreateDirectory: Boolean): Boolean; var  EnvelopedData: IEnvelopedData;  BUFFER: WideString;  FileStm: TFileStream;  vDecryptFileName: string; begin  Result := True;  EnvelopedData := CoEnvelopedData.Create;  //指定采用的CSP算法类型  EnvelopedData.Algorithm.Name := Algorithm;  //指定加密长度  EnvelopedData.Algorithm.KeyLength := EnLength;  try    //获取数字证书接口    GetCertificate;    //关联证书以解密    EnvelopedData.Recipients.Add(ICert2);    //获取加密内容    FileStm := TFileStream.Create(sInPath, fmOpenRead );    try      Pointer(Buffer):= SysAllocStringByteLen (nil, FileStm.Size);      FileStm.ReadBuffer(Pointer(Buffer)^, FileStm.Size);    finally      FileStm.Free;    end;    //解密    EnvelopedData.Decrypt(Buffer);    Buffer:= EnvelopedData.Content;    //输出解密内容    vDecryptFileName:= sOutPath + ExtractFileName(sInPath);    FileStm := TFileStream.Create(vDecryptFileName, fmCreate);    try      FileStm.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer)));    finally      FileStm.Free;    end;    //验证签名    VerifySign(vDecryptFileName);    //因为有压缩,再解压   ZipArchive2Files    ZipArchive2Files(vDecryptFileName, sOutPath, RZipPassWd);    DeleteFile(PAnsiChar(vDecryptFileName));  except    Result := False;  end; end; function TDigital_CAPICOM.VerifySign(const AFileName: string): Boolean; var  SignedData: ISignedData;  HashString: WideString;  ASignedContent: string; begin  Result := True;  try    GetCertificate;    //先获取签名信息,因为会做信息分离,还原出加上签名前的数据    ASignedContent:= ExtractSignedContent(AFileName);    //获取文件哈希值    HashString:= GetFileHash(AFileName);    //构建 数据签名对象    SignedData := CoSignedData.Create;    SignedData.Content := HashString;    //执行检查    SignedData.Verify(ASignedContent, False, CAPICOM_VERIFY_SIGNATURE_ONLY);  except    Result := False;    Raise Exception.Create('数字签名校验失败!');  end; end; function TDigital_CAPICOM.VerifyUserAvailable: Boolean; begin  Result := False;  if (ICert2 <> nil) and ICert2.HasPrivateKey then    Result:= True; end;        另外,还需要一个管理类,目的是解除依赖,这里就不说明了。       功能的实现,通过google,不论你了解或不了解,都可以得到较多信息,帮助实现。更多的还是在于怎么去设计?怎么让后续的开发人员更容易维护?        这里面有个与证书接口相关的问题,比如在GetCertificate,里面有判断PrivateKey,必须使用Disp接口,直接用ICertificate,会出现地址错误。具体原因,还待查证。有谁知道的,还请你指点指点。谢谢!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!