C++利用csp进行签名和验签的例子

来源:互联网 发布:企鹅的小毛毛 知乎 编辑:程序博客网 时间:2024/06/10 05:17

#define _WIN32_WINNT 0x0400
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <wincrypt.h>

void HandleError(char *s);

void Test(){
 HCRYPTPROV hProv;
 BYTE *pbBuffer=(BYTE *)"the data  be hashed and signed.";
 DWORD dwBufferLen=strlen((char *)pbBuffer)+1; //待签名的数据长度
 HCRYPTHASH hHash;   //哈希句柄
 HCRYPTKEY  hKey;    //签名密钥句柄
 HCRYPTKEY  hPubKey; //公钥句柄
 BYTE *pbKeyBlob;    //保存密钥blob缓冲区指针
 BYTE *pbSignature;  //保存签名值的缓冲区指针
 DWORD dwSigLen;     //签名的长度
 DWORD dwBlobLen;    //数据长度
 DWORD i;
 
 //------------------------------------------------------------------
 //---------打开csp句柄-----------------------------------
 if(CryptAcquireContext(
  &hProv,
  "test",//使用容器名为test的密钥
  NULL,
  PROV_RSA_FULL,
  0))
 {
  printf("打开句柄成功!/n");
 }
 else//失败,可能是容器不存在
 {
  if(!CryptAcquireContext(
   &hProv,
   "test",
   NULL,
   PROV_RSA_FULL,
   CRYPT_NEWKEYSET ))//创建test容器
  {
   HandleError("调用CryptAcquireContext失败。");
  }
 }
 //-------------csp句柄打开完成------------------------------
 //-------------获得签名密钥句柄-----------------------------
 if(CryptGetUserKey(
  hProv,
  AT_SIGNATURE,
  &hKey))
 {
  printf("获得签名密钥句柄成功/n");
 }
 else
 {
  printf("获得签名句柄失败,产生一个新的RSA密钥对。/n");
  if(!CryptAcquireContext(
   &hProv,
   "test",
   NULL,
   PROV_RSA_FULL,
   0))
  {
   HandleError("调用CryptAcquireContext 失败。");
  }
  //产生一对RSA密钥
  if(!CryptGenKey(hProv,2,CRYPT_EXPORTABLE|0x04000000,&hKey))
  {
   HandleError("调用CryptGenKey失败。");
  }
 }
 //--------------获得签名密钥句柄完成-----------------------------------------------
  
 //导出明文公钥,签名接收者可使用此公钥验证签名
  //----------获取明文公钥----------------------------------------------------------------
     if(CryptExportKey(
   hKey,
   NULL,
   PUBLICKEYBLOB,
   0,
   NULL,
   &dwBlobLen)) //第一次调用只得到数据长度
  {
   printf("导出公钥,获得公钥的长度成功 /n");
  }
  else
  {
   HandleError("调用CryptExportKey失败。");
  }
  //------------------------------------------------------------
  //为pbKeyBlob申请内存
  if(pbKeyBlob=(BYTE*)malloc(dwBlobLen))
  {
   ;
  }
  else
  {
   HandleError("内存不够了,/n");
  }
  //--------------------------------------------------------------
  //第二次调用将导出公钥,并保存到pbKeyBlob内存中
  if(CryptExportKey(
   hKey,
   NULL,
   PUBLICKEYBLOB,
   0,
   pbKeyBlob,
   &dwBlobLen))
  {
   printf("导出公钥,获得公钥数据成功!/n");
  }
  else
  {
   HandleError("调用CryptExportKey失败。");
  }
        //------------------获取明文公钥完成-------------------------------------------------

        //------------------ 利用哈希句柄进行签名------------------------------
  //创建哈希句柄,指定哈希算法,这里采用CALG_SHA1,即sha1算法
  if(CryptCreateHash(
   hProv,
   CALG_SHA1,
   0,
   0,
   &hHash))
  {
   printf("创建哈希句柄成功。/n");
  }
  else
  {
   HandleError("调用CryptCreateHash失败.");
  }
  //--------对数据计算哈希获得摘要-----------------------------------
  if(CryptHashData(
   hHash,
   pbBuffer, //对输入的数据进行hash运算,保存输出后的hash摘要数据
   dwBufferLen,
   0))
  {
   printf("计算哈希成功/n");
  }
  else
  {
   HandleError("调用CryptHashData失败。");
  }
  //--------对摘要计算签名,第一次调用获得签名后数据的长度-----------
  dwSigLen=0;
  if(CryptSignHash(
   hHash,
   AT_SIGNATURE,
   NULL,
   0,
   NULL,
   &dwSigLen))
  {
   printf("签名值的长度为%d /n",dwSigLen);
  }
  else
  {
   HandleError("调用CryptSignHash失败。");
  }
  if(pbSignature=(BYTE*)malloc(dwSigLen))
  {
   ;
  }
  else
  {
   HandleError("内存不够啦。");
  }
  //-----------对hash对象签名------------------------------------------
  if(CryptSignHash(
   hHash,
   AT_SIGNATURE,
   NULL,
   0,
   pbSignature,
   &dwSigLen))
  {
   printf("数据签名成功!/n");
  }
  else
  {
   HandleError("调用cryptSignHash失败。");
  }
  //------------数字签名完成-------------------------------------------

        //------------输出签名数据-------------------------------------------
  printf("签名值:/n");
  for(i=0; i<dwSigLen; i++)
  {
   if((i%16==0)&&(i!=0))
   {
    printf("/n");
   }
   printf("%2.2x",pbSignature[i]);
  }
  printf("/n");
  printf("签名成功。/n/n");
  //---------释放资源--------------
  //销毁哈希对象
  if(hHash)
   CryptDestroyHash(hHash);
        //-------------------------------
  //========================================================================
       //-----------以下为验证签名-------------------
       //首先把公钥导入得到公钥句柄,使用公钥验证签名
  //========================================================================

         //----------------把公钥导入到csp------------------------------------
  if(CryptImportKey(
   hProv,
   pbKeyBlob,
   dwBlobLen,
   0,
   0,
   &hPubKey))
  {
    printf("导入公钥成功。/n");
  }
  else
  {
    HandleError("导入CryptImportKey失败。");
  }
  //--------------公钥导入完成---------------------------------------------------------

  //--------------创建hash对象--------------------------------------------
  if(CryptCreateHash(
   hProv,
   CALG_SHA1,
   0,
   0,
   &hHash))
  {
    printf("创建哈希对象成功 /n");
  }
  else
  {
    HandleError("调用CryptCreateHash失败");
  }
  //--------------创建hash对象完成-----------------------------------------------------------
  
  //--------------计算哈希-----------------------------------
  if(CryptHashData(
   hHash,
   pbBuffer,
   dwBufferLen,
   0))
  {
     printf("数据哈希完成./n");
  }
  else
  {
    HandleError("调用CryptHashData失败");
  }
  //--------------数据哈希完成-------------------------------
  
  //--------------验证签名-----------------------------------
  if(CryptVerifySignature(
   hHash,
   pbSignature,
   dwSigLen,
   hPubKey,
   NULL,
   0))
  {
    printf("验证签名成功。/n");
  }
  else
  {
    HandleError("签名验证失败,签名无效");
  }
  //--------------签名验证完成-----------------------------------
  //释放签名对象
  if(pbSignature)
   free(pbSignature);

  //------------  释放资源---------------------------------------
  //销毁哈希对象
  if(hHash)
      CryptDestroyHash(hHash);
  //销毁句柄对象
        if(hProv)
   CryptReleaseContext(hProv,0);
      //---------------释放资源完成-------------------------------------
 }
 

 //出错处理函数
 void HandleError(char *s)
 {
    printf("本程序在运行时有错误发生。/n");
 printf("%s/n",s);
 printf("错误码:%x/n",GetLastError());
 printf("程序退出/n");
 exit(1);
 }
//--------------------------------------------------------------------------------
 int main(){
  Test();
  return 0;
 }
 //-----------签名完成---------------------------

原创粉丝点击