WindowsCryptoAPI的使用
一、实验目的
该实验为设计性实验,实验目的如下:
1.熟悉WindowsCryptoAPI提供的常用函数接口。
2.掌握WindowsCryptoAPI的使用。
二、实验内容及步骤
1.熟悉WindowsCryptoAPI提供的常用函数接口。
2.掌握WindowsCryptoAPI的使用。
3.利用WindowsCryptoAPI设计和实现一个小型密码系统(如文件加密机),完成加解密、摘要运算、数字签名等功能
三、实验要求
1.本实验一人一组,编程语言为C/C++/C#。
2.要求学生掌握WindowsCryptoAPI,并熟练掌握C/C++/C#语言编程。
3.要求学生能够设计和实现一个小型密码系统,具体要求如下:
(1)界面友好,操作方便。
(2)利用WindowsCryptoAPI完成该密码系统的相关功能,如加解密、摘要运算、数字签名等。
4.实验报告要求:
(1)实验报告要求包括实验目的、实验要求、实验内容(系统的设计和实现)、实验结果分析和实验体会等,重点在于实验内容(系统的设计和实现)和实验结果分析。实验报告要求上传和打印。
(2)写出系统设计和实现过程中的心得和体会,并回答实验中的思考题。
(3)实验报告撰写规范请见附。
四、实验环境
计算机:Windows11、CodeBlocks C
五、实验提示
1.本实验可以参考以下资料:
(1)《编写安全的代码(第2版)》,(美)MichaelHoward,DavidLeBlanc,机械工业出版社,2005年
(2)《C#数据安全手册》,(美)MatthewMacDonald、ErikHohansson,清华大学出版社,2003年
(3)DanFox.使用.NETFramework的Cryptography命名空间保护私有数据
http://www.microsoft.com/china/msdn/Archives/msdnmag/issues/02/06/crypto/crypto.asp
(4)PaulD.Sheriff.Microsoft.NET中的简化加密
http://www.microsoft.com/china/MSDN/library/default.aspx?mfr=true
(5)《Windows系统中的安全组件—CAPICOM》
http://tag.csdn.net/Article/009a481c-c023-4a5f-926e-f4488e7314d4.html
2.此外,MSDN中有关于WindowsCryptoAPI的详细描述。更多关于WindowsCryptoAPI的参考资料和参考例程请到实验室服务器或BB系统下载。
六、实验知识点
Windows CryptoAPI系统调用中的加解密、信息摘要和签名。
1、加密
使用CryptGenKey函数生成会话密钥,或使用CryptDeriveKey函数将密码转换为适用于加密的密钥,然后使用用CryptEncrypt函数加密文件中的数据;
2、解密
使用CryptDecryptMessage解密数据,获取指向加密 BLOB 的指针,打开证书存储,创建证书存储数组,初始化CRYPT_DECRYPT_MESSAGE_PARA构,最后调用CryptDecryptMessage以解密消息中包含的数据。
3、摘要
通过调用CryptAcquireContext获取加密服务提供程序的句柄。通过调用CryptCreateHash、CryptHashData和CryptDeriveKey派生字节字符串的对称
密钥。使用对称密钥通过调用CryptCreateHash和CryptSetHashParam创建HMAC哈希对象。通过调用CryptHashData对消息进行哈希处理。通过调CryptGetHashParam检索哈希值;
4、签名
首先获取指向要签名的数据的指针。将指向数据的指针分配给"要签名的数据"数组的索引零。获取加密提供程序的句柄。打开包含签名者证书的证书存储。获取签名者证书的地址。将证书的地址分配给MsgCert数组的零索引。将消息中包含的任何其他证书的地址分配给MsgCert数组。初始CRYPT_ALGORITHM_DENTIFIER结构,将pszObjId 成员初始化为所需的哈希算法,并适当地初始化其他成员。初始化CRYPT_SIGN_MESSAGE_PARA 结构,将pSigningCert成员初始化为签名者 证书的地址,将MsgCert数组成员初始化为签名者和其他证书的地址,将HashAlgorithm成员初始化为CRYPT ALGORITHM__IDENTIFIER结构的地址,并视情况初始化其他成员。调用CryptSignMessage函数,传递pSignPara参数的CRYPT_SIGN MESSAGE__PARA结构、rgpbToBeSigned参数的"要签名的数据"数组的地址、pbSignedBlob输出参数的地址以及其他参数的值。
七、实验运行截图
八、实验代码
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <conio.h>
// Link with the Advapi32.lib file.
#pragma comment (lib, "advapi32")
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define KEYLENGTH 0x00800000
//--------------------------------------------------------------------
// These additional #define statements are required.
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
#define MAX_FILE_SIZE 4000000
#define SIGNATURE_SIZE 500
BYTE* pbKeyBlob; // 用来保存导出的公钥
DWORD dwBlobLen;
void HandleError(char* s)
{
fprintf(stderr, "运行程序时出现错误。\n");
fprintf(stderr, "%s\n", s);
fprintf(stderr, "Error number %x.\n", GetLastError());
fprintf(stderr, "程序终止。\n");
exit(1);
} // End of HandleError
//-----------------------------------------------------------------------
// Code for the function VerifyFile 功能:验证数字签名
extern BOOL VerifyFile(
PCHAR szSource, //原文件
PCHAR szSignature) //数字签名文件
{
//--------------------------------------------------------------------
// Declare and initialize local variables.
FILE* hSource;
FILE* hSignature;
HCRYPTPROV hCryptProv; //CSP:钥匙容器
HCRYPTKEY hKey; //公钥对:包括配对的一个公钥和一个密钥
HCRYPTKEY hPubKey; //公钥对中的公钥
HCRYPTHASH hHash; //hash对象,用于对数据文件进行hash处理,得到hash值
//公钥签名就是针对hash值进行签名,而不是原文件,
//这是因为公钥处理的速度非常慢
BYTE* pbSignature;
DWORD dwSigLen;
PBYTE pbBuffer;
DWORD dwBufferLen;
DWORD dwCount;
//DWORD dwBlobLen;
//--------------------------------------------------------------------
// Open source file.
if (hSource = fopen(szSource, "rb"))
{
printf("\n源明文文件 %s 已打开。\n", szSource);
}
else
{
HandleError("\n打开源代码明文文件时出错!");
}
//--------------------------------------------------------------------
// Allocate memory.
if (pbBuffer = (BYTE*)malloc(MAX_FILE_SIZE))
{
printf("已为缓冲区分配了内存。 \n");
}
else
{
HandleError("内存不足。\n");
}
//将源文件读入pbBuffer
dwCount = fread(pbBuffer, 1, MAX_FILE_SIZE, hSource);
if (ferror(hSource))
{
HandleError("读取明文错误!\n");
}
//---------------------------------------------------------------------
// Open signature file 读入签名文件(特殊处理:直接采用保留在内存中的签名来进行验证)
if (hSignature = fopen(szSignature, "rb"))
{
printf("\n签名明文文件 %s 已打开。\n", szSignature);
}
else
{
HandleError("\n打开签名文件时出错!");
}
//--------------------------------------------------------------------
// Allocate memory.
if (pbSignature = (BYTE*)malloc(SIGNATURE_SIZE))
{
printf("已为缓冲区分配了内存。\n");
}
else
{
HandleError("内存不足。\n");
}
//将签名读入pbSignature
dwSigLen = fread(pbSignature, 1, SIGNATURE_SIZE, hSignature);
if (ferror(hSource))
{
HandleError("读取明文错误!\n");
}
//以下获得一个CSP句柄
if (CryptAcquireContext(
&hCryptProv, //调用完成之后hCryptProv保存密钥容器的句柄
NULL, //NULL表示使用默认密钥容器,默认密钥容器名为用户登陆名
NULL,
PROV_RSA_FULL,
0))
{
printf("已获取加密提供程序。\n");
}
else
{
if (CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET)) //创建密钥容器
{
//创建密钥容器成功,并得到CSP句柄
printf("已经创建了一个新的密钥容器。\n");
}
else
{
HandleError("无法创建新的密钥容器。\n");
}
}
//导入 pbKeyBlob 公钥(这个公钥与签名时所用的私钥配对,在签名时导出到pbKeyBlob中)
if (CryptImportKey(
hCryptProv,
pbKeyBlob,
dwBlobLen,
0,
0,
&hPubKey))
{
printf("已导入密钥。\n");
}
else
{
HandleError("公钥导入失败。");
}
//-------------------------------------------------------------------
// Create a new hash object. 对原文件进行hash处理
if (CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
printf("已经重新创建了哈希对象。\n");
}
else
{
HandleError("CryptCreateHash 过程中出错。");
}
//-------------------------------------------------------------------
// Compute the cryptographic hash of the buffer.
if (CryptHashData(
hHash,
pbBuffer,
dwCount,
0))
{
printf("The new has been created.\n");
}
else
{
HandleError("CryptHashData 期间发生错误。");
}
//-------------------------------------------------------------------
// Validate the digital signature. 验证数字签名是否正确
if (CryptVerifySignature(
hHash,
pbSignature,
dwSigLen,
hPubKey,
NULL,
0))
{
printf("\n**********************************************\n");
printf("签名已通过验证!\n");
printf("\n**********************************************\n");
}
else
{
printf("\n**********************************************\n");
printf("签名未验证!");
printf("\n**********************************************\n");
}
//--------------------------------------------------------------------
// Close files.
if (hSource)
fclose(hSource);
//if(hSignature)
// fclose(hSignature);
//-------------------------------------------------------------------
// Free memory to be used to store signature.
if (pbSignature)
free(pbSignature);
//-------------------------------------------------------------------
// Destroy the hash object.
if (hHash)
CryptDestroyHash(hHash);
//-------------------------------------------------------------------
// Release the provider handle.
if (hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return(TRUE);
}
//-----------------------------------------------------------------------
// Code for the function SignFile 功能:对文件进行数字签名
extern BOOL SignFile(
PCHAR szSource,
PCHAR szDestination)
{
//--------------------------------------------------------------------
// Declare and initialize local variables.
FILE* hSource;
FILE* hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
BYTE* pbSignature;
PBYTE pbBuffer;
DWORD dwBufferLen;
DWORD dwCount;
DWORD dwSigLen;
//--------------------------------------------------------------------
// Open source file.
if (hSource = fopen(szSource, "rb"))
{
printf("\n源明文文件 %s 已打开。\n", szSource);
}
else
{
HandleError("\n打开源代码明文文件时出错!");
}
//--------------------------------------------------------------------
// Allocate memory.
if (pbBuffer = (BYTE*)malloc(MAX_FILE_SIZE))
{
printf("已为缓冲区分配了内存。\n");
}
else
{
HandleError("内存不足。\n");
}
dwCount = fread(pbBuffer, 1, MAX_FILE_SIZE, hSource);
if (ferror(hSource))
{
HandleError("读取明文错误!\n");
}
//--------------------------------------------------------------------
// Open destination file.
if (hDestination = fopen(szDestination, "wb"))
{
printf("/n目标文件 %s 已打开。\n", szDestination);
}
else
{
HandleError("\n打开目标密文文件时出错!");
}
//以下获得一个CSP句柄
if (CryptAcquireContext(
&hCryptProv,
NULL, //NULL表示使用默认密钥容器,默认密钥容器名为用户登陆名
NULL,
PROV_RSA_FULL,
0))
{
printf("已经获得了一个加密提供者。\n");
}
else
{
if (CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET)) //创建密钥容器
{
//创建密钥容器成功,并得到CSP句柄
printf("已经创建了一个新的密钥容器。\n");
}
else
{
HandleError("无法创建新的密钥容器。\n");
}
}
if (CryptGetUserKey(
hCryptProv, // 我们已经得到的CSP句柄
AT_SIGNATURE, // 这里想得到signature key pair
&hKey)) // 返回密钥句柄
{
printf("已准备好签名密钥。\n");
}
else //取signature key pair错误
{
printf("无可用签名密钥。\n");
if (GetLastError() == NTE_NO_KEY) //密钥容器里不存在signature key pair
{
// 创建 signature key pair.
printf("签名密钥不存在。\n");
printf("创建签名密钥对。\n");
if (CryptGenKey(
hCryptProv, //CSP句柄
AT_SIGNATURE, //创建的密钥对类型为signature key pair
0, //key类型,这里用默认值
&hKey)) //创建成功返回新创建的密钥对的句柄
{
printf("创建签名密钥对。\n");
}
else
{
printf("创建签名密钥时发生错误。\n");
}
}
else
{
printf("一个错误,而不是 NTE_NO_KEY 获取签名/密钥。\n");
}
} // end if
//-------------------------------------------------------------------
// 导出公钥
// Export the public key. Here the public key is exported to a
// PUBLICKEYBOLB so that the receiver of the signed hash can
// verify the signature. This BLOB could be written to a file and
// sent to another user.
if (CryptExportKey(
hKey,
NULL,
PUBLICKEYBLOB,
0,
NULL,
&dwBlobLen))
{
printf("确定公钥的 BLOB 的大小。\n");
}
else
{
HandleError("计算 BLOB 长度错误。");
}
//-------------------------------------------------------------------
// Allocate memory for the pbKeyBlob.
if (pbKeyBlob = (BYTE*)malloc(dwBlobLen))
{
printf("已经为 BLOB 分配了内存。\n");
}
else
{
HandleError("内存不足。\n");
}
//-------------------------------------------------------------------
// Do the actual exporting into the key BLOB.
if (CryptExportKey(
hKey,
NULL,
PUBLICKEYBLOB,
0,
pbKeyBlob,
&dwBlobLen))
{
printf("内容已写入 BLOB。\n");
}
else
{
HandleError("CryptExportKey 期间出错。");
}
//签名密钥已经准备完毕,公钥也已导出到 pbKeyBlob 中
//*****************************签名***********************************
//-------------------------------------------------------------------
// Create the hash object.
if (CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
printf("创建的散列对象。\n");
}
else
{
HandleError("CryptCreateHash 过程中出错。");
}
if (CryptHashData(
hHash,
pbBuffer,
dwCount,
0))
{
printf("数据缓冲区已被散列。\n");
}
else
{
HandleError("CryptHashData 期间发生错误。\n");
}
//释放缓冲区
if (pbBuffer)
free(pbBuffer);
pbBuffer = NULL;
//-------------------------------------------------------------------
// Determine the size of the signature and allocate memory.
dwSigLen = 0;
if (CryptSignHash(
hHash,
AT_SIGNATURE,
NULL,
0,
NULL,
&dwSigLen))
{
printf("发现签名长度 %d。\n", dwSigLen);
}
else
{
HandleError("CryptSignHash 期间发生错误。");
}
//-------------------------------------------------------------------
// Allocate memory for the signature buffer.
if (pbSignature = (BYTE*)malloc(dwSigLen))
{
printf("为签名分配的内存。\n");
}
else
{
HandleError("内存不足。");
}
//-------------------------------------------------------------------
// Sign the hash object.
if (CryptSignHash(
hHash,
AT_SIGNATURE,
NULL,
0,
pbSignature,
&dwSigLen))
{
printf("pbSignature 是哈希签名。\n");
}
else
{
HandleError("CryptSignHash 期间发生错误。");
}
if (fwrite(pbSignature, 1, dwSigLen, hDestination) != dwSigLen)
HandleError("将签名写入文件失败!");
printf("散列对象已被销毁。\n");
printf("该项目的签约阶段已经完成。\n\n");
//善后工作
//--------------------------------------------------------------------
// Destroy session key.
if (hKey)
CryptDestroyKey(hKey);
//-------------------------------------------------------------------
// Destroy the hash object.
if (hHash)
CryptDestroyHash(hHash);
//-------------------------------------------------------------------
// Release the provider handle.
if (hCryptProv)
CryptReleaseContext(hCryptProv, 0);
//--------------------------------------------------------------------
// Close files.
if (hSource)
fclose(hSource);
if (hDestination)
fclose(hDestination);
return(TRUE);
}
//--------------------------------------------------------------------
// Code for the function Decryptfile, which is called by main too
extern BOOL DecryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword)
//--------------------------------------------------------------------
// Parameters passed are:
// szSource, the name of the input, a plaintext file.
// szDestination, the name of the output, an encrypted file to be
// created.
// szPassword, the password.
{
//--------------------------------------------------------------------
// Declare and initialize local variables.
FILE* hSource;
FILE* hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
//--------------------------------------------------------------------
// Open source file.
if (hSource = fopen(szSource, "rb"))
{
printf("\n源明文文件 %s 已打开。\n", szSource);
}
else
{
HandleError("\n打开源代码明文文件时出错!");
}
//--------------------------------------------------------------------
// Open destination file.
if (hDestination = fopen(szDestination, "wb"))
{
printf("\n目标文件 %s 已打开。\n", szDestination);
}
else
{
HandleError("\n打开目标密文文件时出错!");
}
//以下获得一个CSP句柄
if (CryptAcquireContext(
&hCryptProv,
NULL, //NULL表示使用默认密钥容器,默认密钥容器名为用户登陆名
NULL,
PROV_RSA_FULL,
0))
{
printf("已获取加密提供程序。\n");
}
else
{
if (CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET)) //创建密钥容器
{
//创建密钥容器成功,并得到CSP句柄
printf("已经创建了一个新的密钥容器。\n");
}
else
{
HandleError("无法创建新的密钥容器。\n");
}
}
//--------------------------------------------------------------------
// 创建一个会话密钥(session key)
// 会话密钥也叫对称密钥,用于对称加密算法。
// (注: 一个Session是指从调用函数CryptAcquireContext到调用函数
// CryptReleaseContext 期间的阶段。会话密钥只能存在于一个会话过程)
//--------------------------------------------------------------------
// Create a hash object.
if (CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
printf("已经创建了一个哈希对象。\n");
}
else
{
HandleError("CryptCreateHash 过程中出错!\n");
}
//--------------------------------------------------------------------
// 用输入的密码产生一个散列
if (CryptHashData(
hHash,
(BYTE*)szPassword,
strlen(szPassword),
0))
{
printf("密码已添加到散列中。\n");
}
else
{
HandleError("CryptHashData 期间发生错误。\n");
}
//--------------------------------------------------------------------
// 通过散列生成会话密钥
if (CryptDeriveKey(
hCryptProv,
ENCRYPT_ALGORITHM,
hHash,
KEYLENGTH,
&hKey))
{
printf("加密密钥源自密码哈希。\n");
}
else
{
HandleError("CryptDeriveKey 期间出错!\n");
}
//--------------------------------------------------------------------
// Destroy the hash object.
CryptDestroyHash(hHash);
hHash = NULL;
//--------------------------------------------------------------------
// The session key is now ready.
//--------------------------------------------------------------------
// 因为加密算法是按ENCRYPT_BLOCK_SIZE 大小的块加密的,所以被加密的
// 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍。下面计算一次加密的
// 数据长度。
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
//--------------------------------------------------------------------
// Determine the block size. If a block cipher is used,
// it must have room for an extra block.
if (ENCRYPT_BLOCK_SIZE > 1)
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
dwBufferLen = dwBlockLen;
//--------------------------------------------------------------------
// Allocate memory.
if (pbBuffer = (BYTE*)malloc(dwBufferLen))
{
printf("已为缓冲区分配了内存。\n");
}
else
{
HandleError("内存不足。\n");
}
//*****************************解密***********************************
do
{
//--------------------------------------------------------------------
// Read up to dwBlockLen bytes from the source file.
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
if (ferror(hSource))
{
HandleError("读取明文错误!\n");
}
//--------------------------------------------------------------------
// 解密数据
if (!CryptDecrypt(
hKey, //密钥
0, //如果数据同时进行散列和加密,这里传入一个散列对象
feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输.
//入FALSE这里通过判断是否到文件尾来决定是否为最后一块。
0, //保留
pbBuffer, //输入被加密数据,输出加密后的数据
&dwCount)) //输入被加密数据实际长度,输出加密后数据长度
{
HandleError("CryptEncrypt 期间发生错误。\n");
}
//--------------------------------------------------------------------
// Write data to the destination file.
fwrite(pbBuffer, 1, dwCount, hDestination);
if (ferror(hDestination))
{
HandleError("写入密文错误。");
}
}
while (!feof(hSource));
//*****************************解密***********************************
//善后工作
//--------------------------------------------------------------------
// Close files.
if (hSource)
fclose(hSource);
if (hDestination)
fclose(hDestination);
//--------------------------------------------------------------------
// Free memory.
if (pbBuffer)
free(pbBuffer);
//--------------------------------------------------------------------
// Destroy session key.
if (hKey)
CryptDestroyKey(hKey);
//--------------------------------------------------------------------
// Destroy hash object.
if (hHash)
CryptDestroyHash(hHash);
//--------------------------------------------------------------------
// Release provider handle.
if (hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return(TRUE);
}
//--------------------------------------------------------------------
// Code for the function EncryptFile called by main.
extern BOOL EncryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword)
//--------------------------------------------------------------------
// Parameters passed are:
// szSource, the name of the input, a plaintext file.
// szDestination, the name of the output, an encrypted file to be
// created.
// szPassword, the password.
{
//--------------------------------------------------------------------
// Declare and initialize local variables.
FILE* hSource;
FILE* hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
//--------------------------------------------------------------------
// Open source file.
if (hSource = fopen(szSource, "rb"))
{
printf("\n源明文文件 %s 已打开。\n", szSource);
}
else
{
HandleError("\n打开源代码明文文件时出错!");
}
//--------------------------------------------------------------------
// Open destination file.
if (hDestination = fopen(szDestination, "wb"))
{
printf("\n目标文件 %s 已打开。\n", szDestination);
}
else
{
HandleError("\n打开目标密文文件时出错!");
}
//以下获得一个CSP句柄
if (CryptAcquireContext(
&hCryptProv,
NULL, //NULL表示使用默认密钥容器,默认密钥容器名为用户登陆名
NULL,
PROV_RSA_FULL,
0))
{
printf("已获取加密提供程序。\n");
}
else
{
if (CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET)) //创建密钥容器
{
//创建密钥容器成功,并得到CSP句柄
printf("已经创建了一个新的密钥容器。\n");
}
else
{
HandleError("无法创建新的密钥容器。\n");
}
}
//--------------------------------------------------------------------
// 创建一个会话密钥(session key)
// 会话密钥也叫对称密钥,用于对称加密算法。
// (注: 一个Session是指从调用函数CryptAcquireContext到调用函数
// CryptReleaseContext 期间的阶段。会话密钥只能存在于一个会话过程)
//--------------------------------------------------------------------
// Create a hash object.
if (CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
printf("已经创建了一个哈希对象。\n");
}
else
{
HandleError("CryptCreateHash 过程中出错!\n");
}
//--------------------------------------------------------------------
// 用输入的密码产生一个散列
if (CryptHashData(
hHash,
(BYTE*)szPassword,
strlen(szPassword),
0))
{
printf("密码已添加到散列中。\n");
}
else
{
HandleError("CryptHashData 期间发生错误。\n");
}
//--------------------------------------------------------------------
// 通过散列生成会话密钥
if (CryptDeriveKey(
hCryptProv,
ENCRYPT_ALGORITHM,
hHash,
KEYLENGTH,
&hKey))
{
printf("加密密钥源自密码哈希。\n");
}
else
{
HandleError("CryptDeriveKey 期间出错!\n");
}
//--------------------------------------------------------------------
// Destroy the hash object.
CryptDestroyHash(hHash);
hHash = NULL;
//--------------------------------------------------------------------
// The session key is now ready.
//--------------------------------------------------------------------
// 因为加密算法是按ENCRYPT_BLOCK_SIZE 大小的块加密的,所以被加密的
// 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍。下面计算一次加密的
// 数据长度。
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
//--------------------------------------------------------------------
// Determine the block size. If a block cipher is used,
// it must have room for an extra block.
if (ENCRYPT_BLOCK_SIZE > 1)
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
dwBufferLen = dwBlockLen;
//--------------------------------------------------------------------
// Allocate memory.
if (pbBuffer = (BYTE*)malloc(dwBufferLen))
{
printf("已为缓冲区分配了内存。\n");
}
else
{
HandleError("内存不足。\n");
}
//--------------------------------------------------------------------
// In a do loop, encrypt the source file and write to the source file.
do
{
//--------------------------------------------------------------------
// Read up to dwBlockLen bytes from the source file.
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
if (ferror(hSource))
{
HandleError("读取明文错误!\n");
}
//--------------------------------------------------------------------
// 加密数据
if (!CryptEncrypt(
hKey, //密钥
0, //如果数据同时进行散列和加密,这里传入一个散列对象
feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输.
//入FALSE这里通过判断是否到文件尾来决定是否为最后一块。
0, //保留
pbBuffer, //输入被加密数据,输出加密后的数据
&dwCount, //输入被加密数据实际长度,输出加密后数据长度
dwBufferLen)) //pbBuffer的大小。
{
HandleError("CryptEncrypt 期间发生错误。\n");
}
//--------------------------------------------------------------------
// Write data to the destination file.
fwrite(pbBuffer, 1, dwCount, hDestination);
if (ferror(hDestination))
{
HandleError("写入密文错误。");
}
}
while (!feof(hSource));
//--------------------------------------------------------------------
// End the do loop when the last block of the source file has been
// read, encrypted, and written to the destination file.
//--------------------------------------------------------------------
// Close files.
if (hSource)
fclose(hSource);
if (hDestination)
fclose(hDestination);
/*****************************解密***********************************
//解密
--------------------------------------------------------------------
//Open source file.
//if(hSource = fopen(szDestination,"rb"))
//{
// printf("The source plaintext file, %s, is open. \n", szSource);
//}
//else
//{
// HandleError("Error opening source plaintext file!");
//}
--------------------------------------------------------------------
//Open destination file.
//if(hDestination = fopen("ccc.txt","wb"))
//{
// printf("Destination file %s is open. \n", szDestination);
//}
//else
//{
// HandleError("Error opening destination ciphertext file!");
//}
//do
//{
// //--------------------------------------------------------------------
// // Read up to dwBlockLen bytes from the source file.
// dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
// if(ferror(hSource))
// {
// HandleError("Error reading plaintext!\n");
// }
//
// //--------------------------------------------------------------------
// // 解密数据
// if(!CryptDecrypt(
// hKey, //密钥
// 0, //如果数据同时进行散列和加密,这里传入一个散列对象
// feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输.
// //入FALSE这里通过判断是否到文件尾来决定是否为最后一块。
// 0, //保留
// pbBuffer, //输入被加密数据,输出加密后的数据
// &dwCount)) //输入被加密数据实际长度,输出加密后数据长度
// {
// HandleError("Error during CryptEncrypt. \n");
// }
//
// //--------------------------------------------------------------------
// // Write data to the destination file.
//
// fwrite(pbBuffer, 1, dwCount, hDestination);
// if(ferror(hDestination))
// {
// HandleError("Error writing ciphertext.");
// }
//}
//while(!feof(hSource));
//***************************** 解密***********************************/
//--------------------------------------------------------------------
// Free memory.
if (pbBuffer)
free(pbBuffer);
//--------------------------------------------------------------------
// Destroy session key.
if (hKey)
CryptDestroyKey(hKey);
//--------------------------------------------------------------------
// Destroy hash object.
if (hHash)
CryptDestroyHash(hHash);
//--------------------------------------------------------------------
// Release provider handle.
if (hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return(TRUE);
} // End of Encryptfile
//--------------------------------------------------------------------
// This example uses the function HandleError, a simple error
// handling function, to print an error message to the standard error
// (stderr) file and exit the program.
// For most applications, replace this function with one
// that does more extensive error reporting.
//--------------------------------------------------------------------
// Begin main.
int main(int argc, char* argv[])
{
CHAR szSource[100];
CHAR szDestination[100];
CHAR szPassword[100];
//--------------------------------------------------------------------
// Call EncryptFile to do the actual encryption. 加密文件
printf("\n------------------------------------------------------------\n");
printf("\n\n1.加密文件。\n\n");
printf("\n输入要加密的文件名: ");
scanf("%s", szSource);
printf("\n输入输出文件的名称: ");
scanf("%s", szDestination);
printf("\n输入密码:");
scanf("%s", szPassword);
if (EncryptFile(szSource, szDestination, szPassword))
{
printf("\n文件 %s 的加密成功。\n", szSource);
printf("\n加密的数据在文件 %s 中。\n", szDestination);
}
else
{
HandleError("/n加密文件错误!");
}
//--------------------------------------------------------------------
// Call Decryptfile to do the actual decryption. 解密文件
printf("\n------------------------------------------------------------\n");
printf("\n\n2.解密文件。\n\n");
printf("\n输入要解密的文件的名称: ");
scanf("%s", szSource);
printf("\n输入输出文件的名称: ");
scanf("%s", szDestination);
printf("\n输入密码:");
scanf("%s", szPassword);
if (DecryptFile(szSource, szDestination, szPassword))
{
printf("\n文件 %s 的解密成功。\n", szSource);
printf("\n解密的数据在文件 %s 中。\n", szDestination);
}
else
{
HandleError("\n解密文件出错!");
}
//--------------------------------------------------------------------
// Call SignFile to do the actual signature 签名文件
printf("\n------------------------------------------------------------\n");
printf("\n\n3.签名文件。\n\n");
printf("\n输入要签名的文件名: ");
scanf("%s", szSource);
printf("\n输入签名文件名: ");
scanf("%s", szDestination);
if (SignFile(szSource, szDestination))
{
printf("\n文件 %s 的签名成功。\n", szSource);
printf("\n签名数据在文件 %s 中。\n", szDestination);
}
else
{
HandleError("\n签名文件时出错!");
}
//---------------------------------------------------------------------
// Call VerifyFile to do the actual verification 验证签名
printf("\n------------------------------------------------------------\n");
printf("\n\n4.验证文件及其签名。\n\n");
printf("\n输入需要验证的文件名: ");
scanf("%s", szSource);
printf("\n输入签名文件名: ");
scanf("%s", szDestination);
//printf("/nEnter the name of the public key file: ");
//scanf("%s",szDestination);
if (VerifyFile(szSource, szDestination))
{
printf("\n文件 %s 的验证成功。\n", szSource);
}
else
{
HandleError("\n验证失败。文件错误!");
}
return 0;
} // End of main
九、实验总结
在本次实验中我对WindowsCryptoAPI有了一定的掌握。实现了对文本的加密解密签名和验签。
十、思考题
标签:加密,HandleError,else,------------------------------------------------------------ From: https://www.cnblogs.com/daijun123/p/16927803.html利用WindowsCryptoAPI进行加解密的一般步骤是怎样的?