delphi實現數字簽名

delphi實現數字簽名   
git

上週,另外一部門須要支援解決數字簽名問題。但由於以前也沒作過,現學現賣。此方面可參考的中文資料較少,特做分享,方便查閱。      上週,另外一部門須要支援解決數字簽名問題。但由於以前也沒作過,現學現賣。此方面可參考的中文資料較少,特做分享,方便查閱。        有關數字簽名的概念、原理,這裏就不作介紹了,請自行google或百度。        利用證書對文件進行簽名,從證書來源看,可分爲兩種:一、軟證書:就是將*.pfx文件導入到系統中,這意味着,只要登陸到PC中的用戶,都可以使用該證書;二、硬證書:一般將證書存放到uKey中(smart card),這樣的好處是,只有擁有usb key的人才有權限使用該證書。        USB Key一般支持CryptToAPI——除非特殊安全須要,只公佈使用本身的接口,不支持微軟接口。因爲使用CryptToAPI,使用起來較繁瑣,微軟提供了CAPICOM組件,方便開發。        不管是硬證書或軟證書,只要支持CryptToAPI接口,那麼CAPICOM都可使用。爲此本次內容以CAPICOM,做爲數字簽名功能的基礎。                動手以前,首先要熟悉數字簽名的過程。經過分析,主要是兩部分:數字簽名(身份標識及防篡改)和數字信封;其實按業務流程,簽名以前還有簽章的過程(也就是一般的蓋章);過程大體以下:      發送方       一、驗證證書是否準備好?(如果硬證書,usbkey是否已插入;判斷證書是否有效);       二、對文件進行簽名;       三、對文件進行數字信封(公鑰加密);       四、可選:填入CSP(加密服務提供商,一般是在USB Key當中)信息        接收方:      一、獲取文件,讀取CSP信息;      二、依據CSP信息,獲取相關證書並驗證;      三、利用證書進行數字解封;      四、簽名驗證,確認身份及文件的完整性(是否被篡改);      依據以上分析,程序可這樣設計,因爲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,會出現地址錯誤。具體緣由,還待查證。有誰知道的,還請你指點指點。謝謝!算法

相關文章
相關標籤/搜索