1、熟悉Windows CryptoAPI提供的常用函数接口。
2、掌握Windows CryptoAPI的使用。
3、利用Windows CryptoAPI设计和实现一个小型密码系统(如文件加密机),完成加解密、摘要运算、数字签名等功能。
1. 先编写一个加密的代码,使用Windows crypticAPI实现。
结果如图:
2.编写一个解密的代码,使用Windows crypticAPI实现。
3. 编写一个计算文件的代码,使用Windows crypticAPI实现文件的MD5计算。
用写好的代码测试123.dll,启动代码结果:
以下是代码共三个:分别是加密解密和计算MD5
加密
#include <stdio.h>
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define KEYLENGTH 0x00800000
void HandleError(char *s);
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
BOOL EncryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword);
void main(void)
{
CHAR szSource[100];
CHAR szDestination[100];
CHAR szPassword[100];
printf("Encrypt a file. ");
printf("Enter the name of the file to be encrypted: ");
scanf("%s",szSource);
printf("Enter the name of the output file: ");
scanf("%s",szDestination);
printf("Enter the password:");
scanf("%s",szPassword);
if(EncryptFile(szSource, szDestination, szPassword))
{
printf("Encryption of the file %s was a success. ", szSource);
printf("The encrypted data is in file %s. ",szDestination);
}
else
{
HandleError("Error encrypting file!");
}
}
static 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.
{
FILE *hSource;
FILE *hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
if(hSource = fopen(szSource,"rb"))
{
printf("The source plaintext file, %s, is open. ", szSource);
}
else
{
HandleError("Error opening source plaintext file!");
}
if(hDestination = fopen(szDestination,"wb"))
{
printf("Destination file %s is open. ", szDestination);
}
else
{
HandleError("Error opening destination ciphertext file!");
}
if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
0))
{
printf("A cryptographic provider has been acquired. ");
}
else
{
if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))//创建密钥容器
{
//创建密钥容器成功,并得到CSP句柄
printf("A new key container has been created. ");
}
else
{
HandleError("Could not create a new key container. ");
}
}
if(CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
printf("A hash object has been created. ");
}
else
{
HandleError("Error during CryptCreateHash! ");
}
if(CryptHashData(
hHash,
(BYTE *)szPassword,
strlen(szPassword),
0))
{
printf("The password has been added to the hash. ");
}
else
{
HandleError("Error during CryptHashData. ");
}
if(CryptDeriveKey(
hCryptProv,
ENCRYPT_ALGORITHM,
hHash,
KEYLENGTH,
&hKey))
{
printf("An encryption key is derived from the password hash. ");
}
else
{
HandleError("Error during CryptDeriveKey! ");
}
CryptDestroyHash(hHash);
hHash = NULL;
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
if(ENCRYPT_BLOCK_SIZE > 1)
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
dwBufferLen = dwBlockLen;
if(pbBuffer = (BYTE *)malloc(dwBufferLen))
{
printf("Memory has been allocated for the buffer. ");
}
else
{
HandleError("Out of memory. ");
}
do
{
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
if(ferror(hSource))
{
HandleError("Error reading plaintext! ");
}
if(!CryptEncrypt(
hKey,
0,
feof(hSource),
0, //保留
pbBuffer, //输入被加密数据,输出加密后的数据
&dwCount, //输入被加密数据实际长度,输出加密后数据长度
dwBufferLen)) //pbBuffer的大小。
{
HandleError("Error during CryptEncrypt. ");
}
fwrite(pbBuffer, 1, dwCount, hDestination);
if(ferror(hDestination))
{
HandleError("Error writing ciphertext.");
}
}
while(!feof(hSource));
if(hSource)
fclose(hSource);
if(hDestination)
fclose(hDestination);
if(pbBuffer)
free(pbBuffer);
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return(TRUE);
}
void HandleError(char *s)
{
fprintf(stderr,"An error occurred in running the program. ");
fprintf(stderr,"%s ",s);
fprintf(stderr, "Error number %x. ", GetLastError());
fprintf(stderr, "Program terminating. ");
exit(1);
}
解密
#include <stdio.h>
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define KEYLENGTH 0x00800000
void HandleError(char *s);
//--------------------------------------------------------------------
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
BOOL DecryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword);
void main(void)
{
CHAR szSource[100];
CHAR szDestination[100];
CHAR szPassword[100];
printf("Decrypt a file. ");
printf("Enter the name of the file to be decrypted: ");
scanf("%s",szSource);
printf("Enter the name of the output file: ");
scanf("%s",szDestination);
printf("Enter the password:");
scanf("%s",szPassword);
if(!DecryptFile(szSource, szDestination, szPassword))
{
printf(" Error decrypting file. ");
}
else
{
printf(" Decryption of file %s succeeded. ", szSource);
printf("The decrypted file is %s . ",szDestination);
}
}
static BOOL DecryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword)
{
FILE *hSource;
FILE *hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
BOOL status = FALSE;
if(!(hSource = fopen(szSource,"rb")))
{
HandleError("Error opening ciphertext file!");
}
if(!(hDestination = fopen(szDestination,"wb")))
{
HandleError("Error opening plaintext file!");
}
if(!CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
0))
{
HandleError("Error during CryptAcquireContext!");
}
if(!CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
HandleError("Error during CryptCreateHash!");
}
if(!CryptHashData(
hHash,
(BYTE *)szPassword,
strlen(szPassword),
0))
{
HandleError("Error during CryptHashData!");
}
if(!CryptDeriveKey(
hCryptProv,
ENCRYPT_ALGORITHM,
hHash,
KEYLENGTH,
&hKey))
{
HandleError("Error during CryptDeriveKey!");
}
CryptDestroyHash(hHash);
hHash = 0;
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
dwBufferLen = dwBlockLen;
if(!(pbBuffer = (BYTE *)malloc(dwBufferLen)))
{
HandleError("Out of memory! ");
}
do {
dwCount = fread(
pbBuffer,
1,
dwBlockLen,
hSource);
if(ferror(hSource))
{
HandleError("Error reading ciphertext!");
}
if(!CryptDecrypt(
hKey,
0,
feof(hSource),
0,
pbBuffer,
&dwCount))
{
HandleError("Error during CryptDecrypt!");
}
fwrite(
pbBuffer,
1,
dwCount,
hDestination);
if(ferror(hDestination))
{
HandleError("Error writing plaintext!");
}
} while(!feof(hSource));
status = TRUE;
if(hSource)
fclose(hSource);
if(hDestination)
fclose(hDestination);
if(pbBuffer)
free(pbBuffer);
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return status;
}
void HandleError(char *s)
{
fprintf(stderr,"An error occurred in running the program. ");
fprintf(stderr,"%s ",s);
fprintf(stderr, "Error number %x. ", GetLastError());
fprintf(stderr, "Program terminating. ");
exit(1);
} // End of HandleError
MD5
#include <stdio.h>
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#define CHECK_NULL_RET(bCondition) if (!bCondition) goto Exit0
#define BUFSIZE 1024
#define MD5LEN 16
BOOL GetContentMD5(
BYTE *pszFilePath,
BOOL bFile,
BOOL bUpperCase,
TCHAR *pszResult,
DWORD &dwStatus)
{
BOOL bResult = FALSE;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HANDLE hFile = NULL;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigitsL[] = "0123456789abcdef";
CHAR rgbDigitsU[] = "0123456789ABCDEF";
CHAR *rgbDigits = bUpperCase ? rgbDigitsU : rgbDigitsL;
TCHAR szResult[MD5LEN*2+1] = {0};
dwStatus = 0;
bResult = CryptAcquireContext(&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT);
CHECK_NULL_RET(bResult);
bResult = CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
CHECK_NULL_RET(bResult);
if (bFile)
{
hFile = CreateFile((TCHAR *)pszFilePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
CHECK_NULL_RET(!(INVALID_HANDLE_VALUE == hFile));
while (bResult = ReadFile(hFile, rgbFile, BUFSIZE,
&cbRead, NULL))
{
if (0 == cbRead)
{
break;
}
bResult = CryptHashData(hHash, rgbFile, cbRead, 0);
CHECK_NULL_RET(bResult);
}
}
else
{
bResult = CryptHashData(hHash, pszFilePath, strlen((CHAR *)pszFilePath), 0);
CHECK_NULL_RET(bResult);
}
cbHash = MD5LEN;
if (bResult = CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
TCHAR szTmpBuff[3] ;
for (DWORD i = 0; i < cbHash; i++)
{
sprintf (szTmpBuff, TEXT("%c%c"), rgbDigits[rgbHash[i]>>4],
rgbDigits[rgbHash[i] & 0xf]);
lstrcat(szResult, szTmpBuff);
}
bResult = TRUE;
}
Exit0:
dwStatus = GetLastError();
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CloseHandle(hFile);
lstrcpy(pszResult, szResult);
return bResult;
}
int main(int argc, char* argv[])
{
DWORD dwStatus = 0;
TCHAR szResult[MD5LEN*2+1] = {0};
TCHAR szFilePath[] = TEXT("C:\123.dll");
CHAR szContent[] = "explorer.exe";
GetContentMD5((BYTE *)szFilePath,
TRUE, TRUE, szResult, dwStatus);
MessageBox(NULL, szResult, TEXT("该文件的MD5"), MB_OK);
return 0;
}
这次实验难度很大,过程中遇到了很多的问题。感觉从一开始就无从下手,所以只能先去上网找资料和相关博客等学习。在看了很多的资料和相关解答之后虽然还是一头雾水,但是还算是有了不少的了解。在找到了相关代码之后,自己做了一些修改,也算是完成了这次的任务。也算是对Windows CryptoAPI有了一个初步的了解了。
利用Windows CryptoAPI进行加解密的一般步骤是怎样的?
CryptoAPI使用两种密钥:会话密钥与公共/私人密钥对。会话密钥使用相同的加密和解密密钥,这种算法较快,但必须保证密钥的安全传递。公共/私人密钥对使用一个公共密钥和一个私人密钥,私人密钥只有专人才能使用,公共密钥可以广泛传播。如果密钥对中的一个用于加密,另一个一定用于解密。公共/私人密钥对算法很慢,一般只用于加密小批数据,例如用于加密会话密钥。
CryptoAPI支持两种基本的编码方法:流式编码和块编码。流式编码在明码文本的每一位上创建编码位,速度较快,但安全性较低。块编码在一个完整的块上(一般为64位)上工作,需要使用填充的方法对要编码的数据进行舍入,以组成多个完整的块。这种算法速度较慢,但更安全。
加密:
1、打开源文件
2、取得密钥容器(CSP)句柄
3、根据用户输入的密码创建一个会话密钥(即对称密钥,用于对原文件加密)
4、加密数据文件
5、清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。
解密:
1、打开源文件
2、取得密钥容器(CSP)句柄
3、根据用户输入的密码创建一个会话密钥(即对称密钥,用于对原文件解密,
这里要求用户输入的密码与加密时输入的密码相同。在实际应用中,这个所谓用户输入的“密码”其实只是一个产生密钥的种子,一旦产生完会话密钥,则用户完全 可以忘记当初输入的“密码”,接收方可以使用传过来的密钥直接对加密文件进行解密,而不用再重复一次“生成密钥”的过程。)
4、解密数据文件
5、清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。