下面代码实现了调用CSP实现数据的签名和验签,函数中有些细节没有处理好,但总体流程上应该是没有问题的,测试通过:
//本程序通过调用CSP实现签名及验签功能
#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>
#define IN
#define OUT
/*****************************************************
*函数名:SignHash
*功 能:对一段数据进行哈稀签名,并导出公钥
*入 参:IN BYTE* pData, //欲进行哈稀签名的数据
IN DWORD dwDataLen, //数据长度
*出 参:OUT BYTE** pSignature, //哈稀签名数据的地址,使用完后由调用者释放
OUT DWORD* dwSigLen, //签名实际长度
OUT BYTE** pPublicKey, //公钥数据的地址,使用完后由调用者释放
OUT DWORD* dwPubKeyLen);//公钥实际长度
*返回值:BOOL,TRU为签名成功,FALSE为签名失败
******************************************************/
BOOL SignHash(IN BYTE* pData, IN DWORD dwDataLen, OUT BYTE** pSignature, OUT DWORD* dwSigLen, OUT BYTE** pPublicKey, OUT DWORD* dwPubKeyLen);
/*****************************************************
*函数名:VerifySignature
*功 能:对一段数据进行签名验证
*入 参:IN BYTE* pData, //欲进行哈稀验证的数据
IN DWORD dwDataLen, //数据长度
IN BYTE* pSignature, //签名
IN DWORD dwSigLen, //签名长度
IN BYTE* pPublicKey, //公钥
IN DWORD dwPublicKeyLen);//公钥长度
*出 参:无
*返回值:BOOL,TRU为验证签名成功,FALSE为验证签名失败
******************************************************/
BOOL VerifySignature(IN BYTE* pData, IN DWORD dwDataLen, IN BYTE* pSignature, IN DWORD dwSigLen, IN BYTE* pPublicKey, IN DWORD dwPublicKeyLen);
int _tmain(int argc, CHAR* argv[])
{
CHAR* pData = (CHAR*)"35704uoifhroqfoierfqqe7r89qre";
BYTE* pSignature = NULL;
DWORD dwSigLen = 0;
BYTE* pPublicKey = NULL;
DWORD dwPublicKeyLen = 0;
SignHash((BYTE*)pData, strlen(pData), &pSignature, &dwSigLen, &pPublicKey, &dwPublicKeyLen);
printf("signature:%s, publickey:%s", pSignature, pPublicKey);
VerifySignature((BYTE*)pData, strlen(pData), pSignature, dwSigLen, pPublicKey,dwPublicKeyLen);
if(pPublicKey)
free(pPublicKey);
if(pSignature)
free(pSignature);
getchar();
return 0;
}
BOOL SignHash(IN BYTE* pData, IN DWORD dwDataLen, OUT BYTE** pSignature, OUT DWORD* dwSigLen, OUT BYTE** pPublicKey, OUT DWORD* dwPubKeyLen)
{
//一、获得一个CSP句柄
HCRYPTPROV hCryptProv;
BOOL bRet = CryptAcquireContext(
&hCryptProv,
NULL, //密钥容器名,NULL表示使用默认容器
NULL, //CSP_NAME
PROV_RSA_FULL,
0
);
if(!bRet)
{
bRet = CryptAcquireContext(
&hCryptProv,
NULL, //密钥容器名,NULL表示使用默认容器
NULL, //CSP_NAME
PROV_RSA_FULL,
CRYPT_NEWKEYSET //创建密钥容器
);
if(!bRet)
{
printf("CryptAcquireContext fail!");
return FALSE;
}
}
//二,获取签名密钥
HCRYPTKEY hKey;
bRet = CryptGetUserKey(hCryptProv,AT_SIGNATURE,&hKey);
if(!bRet)
{
//获取失败,现在创建新的RSA密钥对。\n");
bRet = CryptGenKey(hCryptProv, 2, CRYPT_EXPORTABLE | 0X04000000, &hKey);
if(!bRet)
{
printf("CryptGenKey fail!\n");
return FALSE;
}
}
//三、导出公钥
if(CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, dwPubKeyLen))
printf("we get the length of the public key.\n");
else
printf("CryptExportKey erro.\n");
if(*pPublicKey = (BYTE*)malloc(*dwPubKeyLen))
printf("we get the memory.\n");
else
printf("malloc erro.\n");
if(CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, *pPublicKey,dwPubKeyLen))
printf("export the public key.\n");
else
printf("CryptExportKeya error.\n");
//四、对数据进行哈稀签名
HCRYPTHASH hHash;
if(CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash))
printf("CreateHash succeed.\n");
else
printf("CreatHash error.\n");
if(CryptHashData(hHash, pData, dwDataLen, 0))
printf("HashData succeed.\n ");
else
printf("HashData error.\n");
//获取签名的长度
if(CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, NULL, dwSigLen))
printf("Get the length of signature.\n");
else
printf("CryptSignHash error.\n");
if(*pSignature = (BYTE*) malloc(*dwSigLen))
printf("get the memory.\n");
else
printf("memory error.\n");
//签名
if(CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, *pSignature, dwSigLen))
printf("signature succeed.\n");
else
{
printf("Signature error.\n");
return FALSE;
}
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return TRUE;
}
BOOL VerifySignature(IN BYTE* pData, IN DWORD dwDataLen, IN BYTE* pSignature, IN DWORD dwSigLen, IN BYTE* pPublicKey, IN DWORD dwPublicKeyLen)
{
//一、获得一个CSP句柄
HCRYPTPROV hCryptProv;
BOOL bRet = CryptAcquireContext(
&hCryptProv,
NULL, //密钥容器名,NULL表示使用默认容器
NULL, //CSP_NAME
PROV_RSA_FULL,
0
);
if(!bRet)
{
bRet = CryptAcquireContext(
&hCryptProv,
NULL, //密钥容器名,NULL表示使用默认容器
NULL, //CSP_NAME
PROV_RSA_FULL,
CRYPT_NEWKEYSET //创建密钥容器
);
if(!bRet)
{
printf("CryptAcquireContext fail!");
return FALSE;
}
}
//二、导入公钥
HCRYPTKEY hPubKey;
if(CryptImportKey(hCryptProv, pPublicKey, dwPublicKeyLen, 0, 0, &hPubKey))
printf("Import the key.\n");
else
printf("erro");
//计算哈稀
HCRYPTHASH hHash;
if(CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash))
printf("创建哈希对象成功 \n");
else
printf("调用CryptCreateHash失败");
if(CryptHashData(hHash, pData, dwDataLen, 0))
printf("数据哈希完成.\n");
else
printf("调用CryptHashData失败");
//验证哈稀签名
if(CryptVerifySignature(hHash, pSignature, dwSigLen, hPubKey, NULL, 0))
printf("验证签名成功。\n");
else
printf("签名验证失败,签名无效");
if(hHash)
CryptDestroyHash(hHash);
if(hCryptProv)
CryptReleaseContext(hCryptProv,0);
return TRUE;
}