副标题#e#
上次我们讲了Microsoft CryptoAPI的组成以及会话密钥的利用。接下来我们将看一下公私密钥对的利用、HASH算法、数字签名等技能。
一、 公用密钥加密技能
公用密钥加密技能利用两个差异的密钥:公钥和私钥。私钥必需安详的保管好不能被外人知道,而公钥可以汇报任何人,只要他需要。凡是公钥是以数字证书的形式宣布的。
用公私密钥对中的一个密钥加密的数据只能用密钥对中的另一个密钥才气解密。也就是说用用户A的公钥加密的数据只能用A的私钥才气解密,同样,用A的私钥加密的数据只能用A的公钥才气解密。
假如用私钥签名一个动静,那么必需用与之对应的公钥去验证签名的有效性。
不幸的是公用密钥加密技能的效率很是低甚至只有对称加密的千分之一,所以不适合对大量的数据举办加密。实际上,公用密钥加密技能一般用来加密会话密钥,而数据加密可以用对称加密的要领。
好了,让我们回到Microsoft CryptoAPI。我们知道一个CSP有一个密钥库,这个密钥库有一个或多个密钥容器。而密钥容器中有什么呢?一般来说,一个密钥容器中有两对公私密钥对,一对用来加密会话密钥,而另一对用来举办数字签名,也就是各人知道的key exchange key pair和signature key pair。
那么,怎么获得这些密钥对呢?
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。
#p#副标题#e#
此刻我们获得的仅仅是一个句柄,我们需要把这个key值存储的磁盘或文件中,这样才气传给对方来举办解密。下面让我们来看一个用于导出密钥的API。
BOOL WINAPI CryptExportKey(
hKey:需要被导出的密钥句柄
HCRYPTKEY hKey,
HCRYPTKEY hExpKey,
DWORD dwBlobType,
DWORD dwFlags,
BYTE* pbData,
DWORD* pdwDataLen
);
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句柄就可以了。
既然有了导出虽然要有导入。
#p#分页标题#e#
BOOL WINAPI CryptImportKey(
这个API较量简朴,这里就不举例说明白,在今后的例子里会看到。
HCRYPTPROV hProv, //CSP句柄
BYTE* pbData, //要导入的密钥数据
DWORD dwDataLen, //数据长度
HCRYPTKEY hPubKey, //假如数据是被加密的这里输入解密用的密钥句柄
DWORD dwFlags, //符号位
HCRYPTKEY* phKey //导入后返回的密钥句柄
);
二、 HASH
Hash简朴点讲就是把任意一段数据颠末某种算法生成一段独一的牢靠长度的数据。也叫做摘要。为了确保数据A免受意外可能存心(恶意)的修改,往往用这段数据A发生一个hash数据一起发送出去,吸收方可以通过沟通的hash算法用这段吸收到的数据A发生一个新的hash数据并与吸收到的hash数据较量,来验证数据A是否为真实完整的数据。
下面的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);
三、 数字签名
#p#分页标题#e#
宣布一个纯文本形式信息时,吸收者可以用数字签名来辨别和验证信息的发送者。对信息签名并不改变这个信息,只是生成一个数字签名串随信息一起传送,或单独传送。
一个数字签名,就是一段被用发送者的私钥加密的数据段,而吸收者只有拥有发送者的公钥才气解密这个数据段。暗示如下:
由Message生成数字签名有两步。首先,对Message举办hash处理惩罚,发生hash数据。然后用签名者A的私钥对这个hash数据加密。详细如下:
验证一个签名需要上图暗示的Message和Digital signatures。首先跟生成时一样对Message举办hash处理惩罚,发生hash数据。然后通过签名者A的公钥、Digital signatures以及刚生成的hash数据举办验证。详细如下:
好了,你是否学会数字签名了呢?许多技能名词听起来很唬人,其实原来是很简朴的!!嘿嘿。
随文档的例程险些将用到我们上面讲的所有内容。