前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Delphi 编写 数字签名验证 并获取签名信息

Delphi 编写 数字签名验证 并获取签名信息

作者头像
战神伽罗
发布2020-06-16 16:06:48
2K0
发布2020-06-16 16:06:48
举报

一个客户想通过编程实现验证程序自身的数字签名来确保程序的完整性,防范病毒感染以及防止一些无聊人士的修改(通过十六进制编辑器替换一些版权、网址、LOGO..); 为此我做了一个数字签名验证的小例子,其中也有获取签名者信息的方法,以满足“自验证”的需求。

示例:

\
\

WinAPI: • 安全编录(CAT)   CryptCATAdminReleaseCatalogContext   CryptCATCatalogInfoFromContext   CryptCATAdminEnumCatalogFromHash   CryptCATAdminCalcHashFromFileHandle   CryptCATAdminReleaseContext   CryptCATAdminAcquireContext • 验证文件的签名(主API)   WinVerifyTrust • 获取签名信息   WTHelperProvDataFromStateData • 获取证书名字信息   CertGetNameString 代码: { * by: HouSoft * site: www.yryz.net * created: 2012/02/03 } unit Unit1; interface uses Windows, Sysutils, jwaWinCrypt, WinTrustApi; procedure Test; implementation procedure PrintCertChain(pCertChain: PCERT_SIMPLE_CHAIN); var I: Integer; sBuf: string; begin // 开启指针运算 {$POINTERMATH ON} // // 输出书链元素 for I := pCertChain^.cElement - 1 downto 0 do begin SetLength(sBuf, 1024); SetLength(sBuf, CertGetNameString( pCertChain^.rgpElement[I].pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, // 简单名字 0, nil, PChar(sBuf), Length(sBuf)) - 1); WriteLn(#9, StringOfChar(' ', 2 * (pCertChain^.cElement - I - 1)), sBuf); end; end; procedure OutSignerInfo(hWVTStateData: THANDLE); var provData: PCRYPT_PROVIDER_DATA; LSysTime: TSystemTime; begin // 获取签名信息 // http://msdn.microsoft.com/ZH-CN/library/windows/desktop/aa388429(v=vs.85).aspx provData := WTHelperProvDataFromStateData(hWVTStateData); if (provData <> nil) and (provData^.pasSigners <> nil) then begin // 采用安全编录(CAT)签名 if provData^.pPDSip^.psSipCATSubjectInfo <> nil then begin WriteLn('安全编录: '); WriteLn(#9, provData^.pPDSip^.psSipCATSubjectInfo^.pwsFileName); WriteLn(''); end; /// 注意: provData^.pasSigners 是数组, 但常见的都是一个元素,so... // 时间戳 if provData^.pasSigners^.pasCounterSigners <> nil then begin FileTimeToSystemTime(provData^.pasSigners^.pasCounterSigners^.sftVerifyAsOf, LSysTime); WriteLn('时间戳: '); WriteLn(#9, FormatDateTime('yyyy-MM-dd hh:mm:ss', SystemTimeToDateTime(LSysTime))); WriteLn(''); WriteLn('时间戳证书链: '); PrintCertChain(provData^.pasSigners^.pasCounterSigners^.pChainContext^.rgpChain[0]); WriteLn(''); end; WriteLn('签名者证书链:'); PrintCertChain(provData^.pasSigners^.pChainContext^.rgpChain[0]); WriteLn(''); end; end; function SignVerify(FileName: string): Boolean; var aByteHash: array [0 .. 255] of Byte; iByteCount: Integer; hCatAdminContext: HCatAdmin; WTrustData: WINTRUST_DATA; WTDCatalogInfo: WINTRUST_CATALOG_INFO; WTDFileInfo: WINTRUST_FILE_INFO; CatalogInfo: CATALOG_INFO; hFile: THANDLE; hCatalogContext: THANDLE; swFilename: WideString; swMemberTag: WideString; ilRet: Longint; I: Integer; begin Result := False; if not FileExists(FileName) then Exit; swFilename := FileName; ZeroMemory(@CatalogInfo, SizeOf(CatalogInfo)); ZeroMemory(@WTDFileInfo, SizeOf(WTDFileInfo)); ZeroMemory(@WTDCatalogInfo, SizeOf(WTDCatalogInfo)); ZeroMemory(@WTrustData, SizeOf(WTrustData)); hCatalogContext := 0; hCatAdminContext := 0; try // 先查询安全编目 if not CryptCATAdminAcquireContext(@hCatAdminContext, nil, 0) then Exit; hFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hFile = INVALID_HANDLE_VALUE then Exit; iByteCount := SizeOf(aByteHash); // 文件哈希函数计算的 CryptCATAdminCalcHashFromFileHandle(hFile, @iByteCount, @aByteHash, 0); for i := 0 to iByteCount - 1 do begin swMemberTag := swMemberTag + IntToHex(aByteHash[i], 2); end; CloseHandle(hFile); // 枚举目录包含一个指定的哈希 hCatalogContext := CryptCATAdminEnumCatalogFromHash(hCatAdminContext, @aByteHash, iByteCount, 0, nil); // 准备验证参数 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa388205(v=vs.85).aspx WTrustData.dwUIChoice := WTD_UI_NONE; WTrustData.fdwRevocationChecks := WTD_REVOKE_NONE; WTrustData.dwStateAction := WTD_STATEACTION_VERIFY; // 获取信息后需要手动 WTD_STATEACTION_CLOSE WTrustData.dwProvFlags := WTD_REVOCATION_CHECK_NONE; if hCatalogContext = 0 then // 未找到包含此文件的安全编目 begin WTDFileInfo.cbStruct := SizeOf(WTDFileInfo); WTDFileInfo.pcwszFilePath := PWideChar(swFilename); WTrustData.cbStruct := SizeOf(WTrustData); WTrustData.dwUnionChoice := WTD_CHOICE_FILE; WTrustData.union.pFile := @WTDFileInfo; end else begin CryptCATCatalogInfoFromContext(hCatalogContext, @CatalogInfo, 0); WTDCatalogInfo.cbStruct := SizeOf(WTDCatalogInfo); WTDCatalogInfo.pcwszCatalogFilePath := CatalogInfo.sCatalogFile; WTDCatalogInfo.pcwszMemberFilePath := PWideChar(swFilename); WTDCatalogInfo.pcwszMemberTag := PWideChar(swMemberTag); WTrustData.cbStruct := SizeOf(WTrustData); WTrustData.dwUnionChoice := WTD_CHOICE_CATALOG; WTrustData.union.pCatalog := @WTDCatalogInfo; // WriteLn(CatalogInfo.sCatalogFile); end; // 验证 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa388208(v=vs.85).aspx ilRet := WinVerifyTrust(INVALID_HANDLE_VALUE, @WINTRUST_ACTION_GENERIC_VERIFY_V2, @WTrustData); Result := ilRet = 0; // 输出签名信息 OutSignerInfo(WTrustData.hWVTStateData); // 释放 WTrustData.dwStateAction := WTD_STATEACTION_CLOSE; WinVerifyTrust(INVALID_HANDLE_VALUE, @WINTRUST_ACTION_GENERIC_VERIFY_V2, @WTrustData); finally if hCatAdminContext > 0 then begin if hCatalogContext > 0 then CryptCATAdminReleaseCatalogContext(hCatAdminContext, hCatalogContext, 0); CryptCATAdminReleaseContext(hCatAdminContext, 0); end; end; end; procedure Test; begin if ParamCount < 1 then begin WriteLn('请输入要验证的文件名!'); Exit; end; if SignVerify(ParamStr(1)) then WriteLn('签名有效.') else WriteLn('签名无效.'); end; end.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档