利用CryptoAPI加/解密文件: 允许用户输入口令,根据用户输入的口令,加/解密文件, 要求: 由用户选择要加密或解密的文件 • 用户要输入口令, 用户没有输入口令,则用随机数产生密钥句柄
时间: 2023-06-27 07:04:25 浏览: 154
这里提供一个基本的 CryptoAPI 加/解密文件的实现:
```c++
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib, "Crypt32.lib")
#define BLOCK_SIZE 16
// 加密文件
BOOL EncryptFile(LPCTSTR file_path, LPCTSTR password) {
// 打开文件
HANDLE h_file = CreateFile(file_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h_file == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open file: " << file_path << std::endl;
return FALSE;
}
// 获取文件大小
DWORD file_size = GetFileSize(h_file, NULL);
// 创建一个加密算法提供者
HCRYPTPROV h_prov = 0;
if (!CryptAcquireContext(&h_prov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
std::cerr << "Failed to acquire crypto context." << std::endl;
CloseHandle(h_file);
return FALSE;
}
// 根据口令获取密钥
HCRYPTKEY h_key = 0;
DWORD password_len = _tcslen(password);
if (password_len > 0) {
if (!CryptDeriveKey(h_prov, CALG_AES_256, NULL, 0, (LPBYTE)password, password_len * sizeof(TCHAR), 0, &h_key)) {
std::cerr << "Failed to derive key." << std::endl;
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
}
else {
// 如果用户没有输入口令,则用随机数产生密钥
if (!CryptGenKey(h_prov, CALG_AES_256, CRYPT_EXPORTABLE, &h_key)) {
std::cerr << "Failed to generate key." << std::endl;
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
}
// 获取加密块大小
DWORD block_size = 0;
DWORD block_size_len = sizeof(DWORD);
if (!CryptGetKeyParam(h_key, KP_BLOCKLEN, (LPBYTE)&block_size, &block_size_len, 0)) {
std::cerr << "Failed to get block size." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
block_size /= 8;
// 创建一个加密模式
HCRYPTKEY h_mode = 0;
if (!CryptSetKeyParam(h_key, KP_MODE, (LPBYTE)CRYPT_MODE_CBC, 0)) {
std::cerr << "Failed to set encryption mode." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
if (!CryptSetKeyParam(h_key, KP_IV, (LPBYTE)password, 0)) {
std::cerr << "Failed to set IV." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
if (!CryptDuplicateKey(h_key, NULL, 0, &h_mode)) {
std::cerr << "Failed to duplicate key." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
// 读取文件并加密
DWORD bytes_read = 0;
DWORD bytes_written = 0;
BYTE buffer[BLOCK_SIZE * 2];
BOOL success = TRUE;
while (success && ReadFile(h_file, buffer, BLOCK_SIZE, &bytes_read, NULL) && bytes_read > 0) {
if (bytes_read < block_size) {
// 如果剩下的字节数不足一个加密块大小,则需要补齐
DWORD padding_size = block_size - bytes_read;
for (DWORD i = 0; i < padding_size; i++) {
buffer[bytes_read + i] = (BYTE)padding_size;
}
bytes_read += padding_size;
}
if (!CryptEncrypt(h_mode, NULL, FALSE, 0, buffer, &bytes_read, sizeof(buffer))) {
std::cerr << "Failed to encrypt data." << std::endl;
success = FALSE;
}
if (success && !WriteFile(h_file, buffer, bytes_read, &bytes_written, NULL)) {
std::cerr << "Failed to write encrypted data." << std::endl;
success = FALSE;
}
}
// 清理资源
CryptDestroyKey(h_mode);
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return success;
}
// 解密文件
BOOL DecryptFile(LPCTSTR file_path, LPCTSTR password) {
// 打开文件
HANDLE h_file = CreateFile(file_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h_file == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open file: " << file_path << std::endl;
return FALSE;
}
// 获取文件大小
DWORD file_size = GetFileSize(h_file, NULL);
// 创建一个加密算法提供者
HCRYPTPROV h_prov = 0;
if (!CryptAcquireContext(&h_prov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
std::cerr << "Failed to acquire crypto context." << std::endl;
CloseHandle(h_file);
return FALSE;
}
// 根据口令获取密钥
HCRYPTKEY h_key = 0;
DWORD password_len = _tcslen(password);
if (password_len > 0) {
if (!CryptDeriveKey(h_prov, CALG_AES_256, NULL, 0, (LPBYTE)password, password_len * sizeof(TCHAR), 0, &h_key)) {
std::cerr << "Failed to derive key." << std::endl;
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
}
else {
std::cerr << "No password provided." << std::endl;
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
// 获取加密块大小
DWORD block_size = 0;
DWORD block_size_len = sizeof(DWORD);
if (!CryptGetKeyParam(h_key, KP_BLOCKLEN, (LPBYTE)&block_size, &block_size_len, 0)) {
std::cerr << "Failed to get block size." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
block_size /= 8;
// 创建一个加密模式
HCRYPTKEY h_mode = 0;
if (!CryptSetKeyParam(h_key, KP_MODE, (LPBYTE)CRYPT_MODE_CBC, 0)) {
std::cerr << "Failed to set encryption mode." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
if (!CryptSetKeyParam(h_key, KP_IV, (LPBYTE)password, 0)) {
std::cerr << "Failed to set IV." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
if (!CryptDuplicateKey(h_key, NULL, 0, &h_mode)) {
std::cerr << "Failed to duplicate key." << std::endl;
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return FALSE;
}
// 读取文件并解密
DWORD bytes_read = 0;
DWORD bytes_written = 0;
BYTE buffer[BLOCK_SIZE * 2];
BOOL success = TRUE;
while (success && ReadFile(h_file, buffer, BLOCK_SIZE, &bytes_read, NULL) && bytes_read > 0) {
if (!CryptDecrypt(h_mode, NULL, FALSE, 0, buffer, &bytes_read)) {
std::cerr << "Failed to decrypt data." << std::endl;
success = FALSE;
}
if (success && bytes_read > 0 && !WriteFile(h_file, buffer, bytes_read, &bytes_written, NULL)) {
std::cerr << "Failed to write decrypted data." << std::endl;
success = FALSE;
}
}
// 清理资源
CryptDestroyKey(h_mode);
CryptDestroyKey(h_key);
CryptReleaseContext(h_prov, 0);
CloseHandle(h_file);
return success;
}
int _tmain(int argc, _TCHAR* argv[])
{
// 获取用户输入
std::cout << "Enter file path: ";
TCHAR file_path[MAX_PATH];
std::wcin.getline(file_path, MAX_PATH);
std::cout << "Enter password (empty for random key): ";
TCHAR password[MAX_PATH];
std::wcin.getline(password, MAX_PATH);
std::cout << "Enter operation (0: encrypt, 1: decrypt): ";
int operation;
std::cin >> operation;
// 执行加密/解密操作
if (operation == 0) {
EncryptFile(file_path, password);
}
else if (operation == 1) {
DecryptFile(file_path, password);
}
else {
std::cerr << "Invalid operation." << std::endl;
}
return 0;
}
```
以上代码中,我们先通过 `CryptAcquireContext` 函数获取一个加密算法提供者的句柄,然后根据用户输入的口令或随机数产生密钥句柄。接着,我们使用 `CryptSetKeyParam` 函数设置加密模式和初始化向量(IV),并使用 `CryptDuplicateKey` 函数创建一个加密模式的密钥句柄。最后,我们循环读取文件并使用 `CryptEncrypt` 或 `CryptDecrypt` 函数加/解密数据,并将加/解密后的数据写回到文件。
需要注意的是,这个实现中使用的是 AES-256 算法,加密模式为 CBC,填充方式为 PKCS#7。在实际应用中,我们可能需要根据具体情况选择不同的算法、模式和填充方式,以及使用更复杂的口令处理方式(比如加盐哈希算法)来提高安全性。
阅读全文