Microsoft CryptoAPI加密技术(二) 下载本文示例源代码 一、 公用密钥加密技术 那么,怎么得到这些密钥对呢? if(CryptGetUserKey( hCryptProv, // 我们已经得到的CSP句柄 AT_SIGNATURE, // 这里想得到signature key pair &hKey)) // 返回密钥句柄 { printf("A signature key is available./n"); } else //取signature key pair错误 { printf("No signature key is available./n"); if(GetLastError() == NTE_NO_KEY) //密钥容器里不存在signature key pair { // 创建 signature key pair. printf("The signature key does not exist./n"); printf("Create a signature key pair./n"); if(CryptGenKey( hCryptProv, //CSP句柄 AT_SIGNATURE, //创建的密钥对类型为signature key pair 0, //key类型,这里用默认值 &hKey)) //创建成功返回新创建的密钥对的句柄 { printf("Created a signature key pair./n"); } else { printf ("Error occurred creating a signature key./n"); } } else { printf ("An error other than NTE_NO_KEY getting signature/key./n"); } } // end if将参数AT_SIGNATURE换成AT_KEYEXCHANGE就可以得到key exchange key pair。 现在我们得到的仅仅是一个句柄,我们需要把这个key值存储的磁盘或文件中,这样才能传给对方来进行解密。下面让我们来看一个用于导出密钥的API。 BOOL WINAPI CryptExportKey( HCRYPTKEY hKey, HCRYPTKEY hExpKey, DWORD dwBlobType, DWORD dwFlags, BYTE* pbData, DWORD* pdwDataLen );hKey:需要被导出的密钥句柄 hExpKey:前面咱们提到公用密钥加密技术的效率非常低所以公用密钥加密技术 一般用来加密会话密钥。这里传入的密钥就是用来加密被导出的密钥 的。也就是说,被导出的密钥hKey的数据是经过这个密钥hExpKey 加密的。如果为NULL表示不经过加密直接导出。 dwBlobType:被导出的密钥类型,比如公钥还是私钥等 dwFlags:标志位 pbData:保存导出的数据,如果为NULL, pdwDataLen将返回导出数据的长度 pdwDataLen:输入pbData缓冲区的大小,输出导出数据的长度 下面的例子演示如何导出密钥。 if(CryptExportKey( hKey, NULL, PUBLICKEYBLOB, //导出公钥 0, NULL, &dwBlobLen)) //返回密钥数据长度 { printf("Size of the BLOB for the public key determined. /n"); } else { printf("Error computing BLOB length./n"); exit(1); } //-------------------------------------------------------------------- // Allocate memory for the pbKeyBlob. if(pbKeyBlob = (BYTE*)malloc(dwBlobLen)) { printf("Memory has been allocated for the BLOB. /n"); } else { printf("Out of memory. /n"); exit(1); } //-------------------------------------------------------------------- // Do the actual exporting into the key BLOB. if(CryptExportKey( hKey, NULL, PUBLICKEYBLOB, 0, pbKeyBlob, //返回密钥数据 &dwBlobLen)) //导出的密钥数据的长度 { printf("Contents have been written to the BLOB. /n"); } else { printf("Error exporting key./n"); exit(1); }如果要导出用公用密钥加密技术加密的密钥,只要把API的第二个参数传入一个key exchange key pair句柄就可以了。 既然有了导出当然要有导入。 BOOL WINAPI CryptImportKey( HCRYPTPROV hProv, //CSP句柄 BYTE* pbData, //要导入的密钥数据 DWORD dwDataLen, //数据长度 HCRYPTKEY hPubKey, //如果数据是被加密的这里输入解密用的密钥句柄 DWORD dwFlags, //标志位 HCRYPTKEY* phKey //导入后返回的密钥句柄 );这个API比较简单,这里就不举例说明了,在以后的例子里会看到。 二、 HASH 下面的API用来创建hash对象 BOOL WINAPI CryptCreateHash( HCRYPTPROV hProv, //CSP句柄 ALG_ID Algid, //选择hash算法,比如CALG_MD5等 HCRYPTKEY hKey, //HMAC 和MAC算法时有用 DWORD dwFlags, //保留,传入0即可 HCRYPTHASH* phHash //返回hash句柄 ); if(CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash)) { printf("An empty hash object has been created. /n"); } else { printf("Error during CryptBeginHash!/n"); exit(1); } // Insert code that uses the hash object here. //-------------------------------------------------------------------- // After processing, hHash must be released. if(hHash) CryptDestroyHash(hHash); //释放句柄我们已经得到hash对象了,下面就找点数据试试,咱也去哈一下,当然这里可不是哈日哈韩的哈,更不是哈巴狗的哈,嘿嘿。Let’s go!! 哎呀!!不好意思,忘记了介绍一个API,看看先。 BOOL WINAPI CryptHashData( HCRYPTHASH hHash, //hash对象 BYTE* pbData, //被hash的数据 DWORD dwDataLen, //数据的长度 DWORD dwFlags //微软的CSP这个值会被忽略 );下面代码: BYTE *pbBuffer= (BYTE *)"The data that is to be hashed."; DWORD dwBufferLen = strlen((char *)pbBuffer)+1; if(CryptHashData( hHash, pbBuffer, dwBufferLen, 0)) { printf("The data buffer has been added to the hash./n"); } else { printf("Error during CryptHashData./n"); exit(1); } 现在,pbBuffer里的内容已经被hash了,然后我们需要导出哈希后的数据。 BYTE *pbHash; BYTE *pbHashSize; DWORD dwHashLen = sizeof(DWORD); DWORD i; if(!(pbHashSize =(BYTE *) malloc(dwHashLen))) MyHandleError("Memory allocation failed."); //下面的这次调用我没搞清楚:( 我怎么觉得没有必要!! if(CryptGetHashParam( hHash, HP_HASHSIZE, //取hash数据的大小 pbHashSize, //输出hash数据大小的缓冲区 &dwHashLen, //缓冲区大小 0)) { // It worked. Free pbHashSize. free(pbHashSize); } else { MyHandleError("CryptGetHashParam failed to get size."); } if(CryptGetHashParam( hHash, HP_HASHVAL, //取hash值 NULL, //设为NULL,在dwHashLen返回需要的输出缓冲区大小 &dwHashLen, //输出缓冲区大小 0)) { // It worked. Do nothing. } else { MyHandleError("CryptGetHashParam failed to get length."); } if(pbHash = (BYTE*)malloc(dwHashLen)) { // It worked. Do nothing. } else { MyHandleError("Allocation failed."); } if(CryptGetHashParam( hHash, HP_HASHVAL, //取hash值 pbHash, //返回Hash数据 &dwHashLen, //hash数据长度 0)) { // Print the hash value. printf("The hash is: "); for(i = 0 ; i < dwHashLen ; i++) { printf("%2.2x ",pbHash[i]); } printf("/n"); } else { MyHandleError("Error during reading hash value."); } free(pbHash); 三、 数字签名 发布一个纯文本形式信息时,接收者可以用数字签名来鉴别和验证信息的发送者。对信息签名并不改变这个信息,只是生成一个数字签名串随信息一起传送,或单独传送。 一个数字签名,就是一段被用发送者的私钥加密的数据段,而接收者只有拥有发送者的公钥才能解密这个数据段。表示如下: 由Message生成数字签名有两步。首先,对Message进行hash处理,产生hash数据。然后用签名者A的私钥对这个hash数据加密。具体如下: 验证一个签名需要上图表示的Message和Digital signatures。首先跟生成时一样对Message进行hash处理,产生hash数据。然后通过签名者A的公钥、Digital signatures以及刚生成的hash数据进行验证。具体如下: 好了,你是否学会数字签名了呢?很多技术名词听起来很唬人,其实本来是很简单的!!嘿嘿。 随文档的例程几乎将用到我们上面讲的所有内容。 参考资料: |