刚刚接触C++,使用CryptEncrypt来对一个文件进行加密,代码都是MSDN上的,一开始使用起来比价困难,这里对代码解读和分享一下。
#include
#include
#include
#include
#include
#pragma comment (lib, "advapi32")
#define KEYLENGTH 0x00800000 //产生密钥的长度,类型
#define ENCRYPT_ALGORITHM CALG_RC4 //生成密钥所使用的算法
#define ENCRYPT_BLOCK_SIZE 8 //每次加密数据块的最小单位长度
bool MyEncryptFile(
LPTSTR szSource,
LPTSTR szDestination,
LPTSTR szPassword,
LPTSTR szexportkey);
void MyHandleError(
LPTSTR psz,
int nErrorNumber);
int main()
{
LPTSTR pszSource = (LPTSTR)L"D:\\testSecurity\\hello11.txt";//要加密的文件
LPTSTR pszDestination = (LPTSTR)L"D:\\testSecurity\\hello22.txt";//加密后的文件
LPTSTR pszexportkeyDestination = (LPTSTR)L"D:\\testSecurity\\exportkeyblob.txt";
//LPTSTR pszPassword = (LPTSTR)"123456";//随便一串字符,用于加解密
LPTSTR pszPassword = NULL;
//---------------------------------------------------------------
// Call EncryptFile to do the actual encryption.
if (MyEncryptFile(pszSource, pszDestination, pszPassword, pszexportkeyDestination))
{
_tprintf(TEXT("Encryption of the file %s was successful. \n"), pszSource);
_tprintf(TEXT("The encrypted data is in file %s.\n"), pszDestination);
}
else
{
MyHandleError(TEXT("Error encrypting file!\n"), GetLastError());
}
getchar();
return 0;
}
bool MyEncryptFile(LPTSTR pszSourceFile, LPTSTR pszDestinationFile, LPTSTR pszPassword, LPTSTR pszexportkeyDestination)
{
bool fReturn = false;
HANDLE hSourceFile = INVALID_HANDLE_VALUE;
HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
HANDLE hexportkeyDestinationFile = INVALID_HANDLE_VALUE;
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTKEY hXchgKey = NULL;
HCRYPTHASH hHash = NULL;
PBYTE pbKeyBlob = NULL;
DWORD dwKeyBlobLen;
PBYTE pbBuffer = NULL;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
hSourceFile = CreateFile(
pszSourceFile,
FILE_READ_DATA,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hSourceFile)
{
_tprintf(TEXT("The source plaintext file, %s, is open. \n"), pszSourceFile);
}
else
{
MyHandleError(TEXT("Error opening source plaintext file!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
// 创建目标文件
hDestinationFile = CreateFile(pszDestinationFile, FILE_WRITE_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hDestinationFile)
{
_tprintf(TEXT("The destination file, %s, is open. \n"), pszDestinationFile);
}
else
{
MyHandleError(TEXT("Error opening destination file!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
//获取容器handle
if (!CryptAcquireContext(
&hCryptProv, //返回的CSP句柄,秘钥容器
NULL, //密钥容器的名字
MS_ENHANCED_PROV, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块
PROV_RSA_FULL, //这里为使用的加密策略
0))
{
//
if (GetLastError() == NTE_BAD_KEYSET)
{
if (!CryptAcquireContext(
&hCryptProv,
NULL,
MS_ENHANCED_PROV,
PROV_RSA_FULL,
CRYPT_NEWKEYSET)) // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器。
{
MyHandleError(TEXT("Error during CryptAcquireContext!\n"), GetLastError());
goto Exit_MyEncryptFile;
//return FALSE;
}
}
else
{
MyHandleError(TEXT("Error during CryptAcquireContext!\n"), GetLastError());
goto Exit_MyEncryptFile;
//return FALSE;
}
}
_tprintf(TEXT("A cryptographic provider has been acquired. \n"));
// 创建密钥
if (pszPassword == NULL)
{
// 如果pszPassword为NULL,则生成一个随机的密钥,然后再把这个随机秘钥写到文件中
// 创建一个随机秘钥 hKey
if (CryptGenKey( //产生一个随机的交换密钥或者公/私钥对
hCryptProv,
ENCRYPT_ALGORITHM, //表明产生私钥所使用的算法或者公钥生成的算法
KEYLENGTH | CRYPT_EXPORTABLE, //表示密钥使用的长度,参数可以为0,采用默认的密钥长度
&hKey))
{
_tprintf(TEXT("A session key has been created. \n"));
}
else
{
MyHandleError(TEXT("Error during CryptGenKey. \n"), GetLastError());
goto Exit_MyEncryptFile;
}
//-----------------------------------------------------------
// Get the handle to the exchange public key.
//获取交换密钥句柄
if (CryptGetUserKey(
hCryptProv,
AT_KEYEXCHANGE, //AT_KEYEXCHANGE(交换密钥) or AT_SIGNATURE(签名密钥)
&hXchgKey)) //返回所获取密钥类型的句柄
{
_tprintf(TEXT("The user public key has been retrieved. \n"));
}
else
{
if (NTE_NO_KEY == GetLastError())
{
//如果没有交换密钥,可以随机生成一个
if (!CryptGenKey(
hCryptProv,
AT_KEYEXCHANGE,
CRYPT_EXPORTABLE,
&hXchgKey))
{
MyHandleError(TEXT("Could not create a user public key.\n"), GetLastError());
goto Exit_MyEncryptFile;
}
}
else
{
MyHandleError(TEXT("User public key is not available and may ")TEXT("not exist.\n"), GetLastError());
goto Exit_MyEncryptFile;
}
}
//-----------------------------------------------------------
// Determine size of the key BLOB, and allocate memory.
//这步导出密钥只是先获取导出key Blob的长度,并对其分配内存,
if (CryptExportKey(
hKey, //需要导出的密钥句柄
hXchgKey, //将待导出密钥用交换密钥进行加密,假如是公开的BLOG当然就设置为0
SIMPLEBLOB, // 指定导出的密钥BLOB类型,BLOB也就是一种存储结构。六个参数见MSDN
0,
NULL, //导出的数据指针,以后就可以将这个数据写如磁盘或者别的任务
&dwKeyBlobLen)) //导出的数据长度
{
_tprintf(TEXT("The key BLOB is %d bytes long. \n"), dwKeyBlobLen);
}
else
{
MyHandleError(TEXT("Error computing BLOB length! \n"), GetLastError());
goto Exit_MyEncryptFile;
}
//未将要存储秘钥的keyBlob分配内存
if (pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen))
{
_tprintf(TEXT("Memory is allocated for the key BLOB. \n"));
}
else
{
MyHandleError(TEXT("Out of memory. \n"), E_OUTOFMEMORY);
goto Exit_MyEncryptFile;
}
//-----------------------------------------------------------
// Encrypt and export the session key into a simple key
// BLOB.
//真正的用交换密钥将密钥加密后,存储到Blob
if (CryptExportKey(
hKey,
hXchgKey,
SIMPLEBLOB,
0,
pbKeyBlob,
&dwKeyBlobLen))
{
_tprintf(TEXT("The key has been exported. \n"));
}
else
{
MyHandleError(TEXT("Error during CryptExportKey!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
//-----------------------------------------------------------
// Release the key exchange key handle.
//释放交换密钥
if (hXchgKey)
{
if (!(CryptDestroyKey(hXchgKey)))
{
MyHandleError(
TEXT("Error during CryptDestroyKey.\n"),
GetLastError());
goto Exit_MyEncryptFile;
}
hXchgKey = 0;
}
hexportkeyDestinationFile = CreateFile(pszexportkeyDestination, FILE_WRITE_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hexportkeyDestinationFile)
{
_tprintf(TEXT("The destination file, %s, is open. \n"), pszexportkeyDestination);
}
else
{
MyHandleError(TEXT("Error opening destination file!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
//先将keyblob 长度保存到文件中,然后再将keyblob写入,以后想解密还是啥的可以直接导入该keyblob即可
if (!WriteFile(
hexportkeyDestinationFile,
&dwKeyBlobLen,
sizeof(DWORD),
&dwCount,
NULL))
{
MyHandleError(TEXT("Error writing header.\n"), GetLastError());
goto Exit_MyEncryptFile;
}
else
{
_tprintf(TEXT("A file header has been written. \n"));
}
//写入keyblob
if (!WriteFile(
hexportkeyDestinationFile,
pbKeyBlob,
dwKeyBlobLen,
&dwCount,
NULL))
{
MyHandleError(TEXT("Error writing header.\n"), GetLastError());
goto Exit_MyEncryptFile;
}
else
{
_tprintf(TEXT("The key BLOB has been written to the ")TEXT("file. \n"));
}
// Free memory.
free(pbKeyBlob);
}
else
{
//-----------------------------------------------------------
// The file will be encrypted with a session key derived
// from a password.
// The session key will be recreated when the file is
// decrypted only if the password used to create the key is
// available.
//创建一个hash对象,将password hash以后再通过CryptDeriveKey得到密钥
if (CryptCreateHash( //初始化一个HASH对象,产生一个空的HASH对象
hCryptProv,
CALG_MD5, //指定的hash算法
0,
0,
&hHash))
{
_tprintf(TEXT("A hash object has been created. \n"));
}
else
{
MyHandleError(TEXT("Error during CryptCreateHash!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
// Hash password后将hash信息保存在hHash中
if (CryptHashData( //对数据使用HASH,保存在hHash中
hHash,
(BYTE *)pszPassword,
lstrlen(pszPassword),
0))
{
_tprintf(TEXT("The password has been added to the hash. \n"));
}
else
{
MyHandleError(TEXT("Error during CryptHashData. \n"), GetLastError());
goto Exit_MyEncryptFile;
}
//再使用已经对password的hash对象生成密钥
if (CryptDeriveKey( //从某一数据产生会话密钥。有点类似CryptGenKey,但是产生的会话密钥来自固定数据,而CryptGenKey是随机产生的。并且不能产生公 / 私钥对
hCryptProv,
ENCRYPT_ALGORITHM, //in,指定的算法,类似CryptGenKey
hHash, //in,HASH对象的句柄
KEYLENGTH, //in,指定产生密钥的类型
&hKey)) //in,out产生的密钥句柄地址
{
_tprintf(TEXT("An encryption key is derived from the ")TEXT("password hash. \n"));
}
else
{
MyHandleError(TEXT("Error during CryptDeriveKey!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
}
//---------------------------------------------------------------
// The session key is now ready. If it is not a key derived from
// a password, the session key encrypted with the private key
// has been written to the destination file.
//---------------------------------------------------------------
// Determine the number of bytes to encrypt at a time.
// This must be a multiple of 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))
{
_tprintf(TEXT("Memory has been allocated for the buffer. \n"));
}
else
{
MyHandleError(TEXT("Out of memory. \n"), E_OUTOFMEMORY);
goto Exit_MyEncryptFile;
}
//---------------------------------------------------------------
// In a do loop, encrypt the source file,
// and write to the source file.
bool fEOF = FALSE;
do
{
//-----------------------------------------------------------
// Read up to dwBlockLen bytes from the source file.
//从要加密的文件每次读取dwBlockLen个字节进行加密
if (!ReadFile(
hSourceFile, //文件的句柄
pbBuffer, //用于保存读入数据的一个缓冲区
dwBlockLen, //要读入的字节数
&dwCount, //指向实际读取字节数的指针
NULL))
{
MyHandleError(TEXT("Error reading plaintext!\n"), GetLastError());
goto Exit_MyEncryptFile;
}
if (dwCount < dwBlockLen)
{
fEOF = TRUE;
}
// 加密数据
if (!CryptEncrypt(
hKey,
NULL,
fEOF, //若只有一个分组的数据需要加密或者为最后一个分组,则Final为TRUE。
0,
pbBuffer,
&dwCount,
dwBufferLen))
{
MyHandleError(TEXT("Error during CryptEncrypt. \n"), GetLastError());
goto Exit_MyEncryptFile;
}
//将加密后的数据写入目标文件
if (!WriteFile(
hDestinationFile,
pbBuffer,
dwCount,
&dwCount,
NULL))
{
MyHandleError(TEXT("Error writing ciphertext.\n"), GetLastError());
goto Exit_MyEncryptFile;
}
} while (!fEOF);
fReturn = true;
Exit_MyEncryptFile:
//---------------------------------------------------------------
// Close files.
if (hSourceFile)
{
CloseHandle(hSourceFile);
}
if (hDestinationFile)
{
CloseHandle(hDestinationFile);
}
//---------------------------------------------------------------
// Free memory.
if (pbBuffer)
{
free(pbBuffer);
}
//-----------------------------------------------------------
// Release the hash object.
if (hHash)
{
if (!(CryptDestroyHash(hHash)))
{
MyHandleError(
TEXT("Error during CryptDestroyHash.\n"),
GetLastError());
}
hHash = NULL;
}
//---------------------------------------------------------------
// Release the session key.
if (hKey)
{
if (!(CryptDestroyKey(hKey)))
{
MyHandleError(
TEXT("Error during CryptDestroyKey!\n"),
GetLastError());
}
}
//---------------------------------------------------------------
// Release the provider handle.
if (hCryptProv)
{
if (!(CryptReleaseContext(hCryptProv, 0)))
{
MyHandleError(
TEXT("Error during CryptReleaseContext!\n"),
GetLastError());
}
}
return fReturn;
} // End Encryptfile.
//-------------------------------------------------------------------
// This example uses the function MyHandleError, 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.
void MyHandleError(LPTSTR psz, int nErrorNumber)
{
_ftprintf(stderr, TEXT("An error occurred in the program. \n"));
_ftprintf(stderr, TEXT("%s\n"), psz);
_ftprintf(stderr, TEXT("Error number %x.\n"), nErrorNumber);
}