文件加密CryptEncrypt和导出密钥CryptExportKey学习笔记

xiaoxiao2021-02-28  75

刚刚接触C++,使用CryptEncrypt来对一个文件进行加密,代码都是MSDN上的,一开始使用起来比价困难,这里对代码解读和分享一下。

#include <tchar.h> #include <stdio.h> #include <windows.h> #include <wincrypt.h> #include <conio.h> #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); }

要加密的文件: 加密后文件: 导出的秘钥blob:

转载请注明原文地址: https://www.6miu.com/read-84672.html

最新回复(0)