带有 CryptoAPI 的 AES128
AES128 with CryptoAPI
我正在尝试使用 CryptoAPI 在 AES128 中加密字符串,但由于某种原因我没有得到它。当我编译时,它只会使应用程序崩溃。我认为问题出在 CryptDecrypt
和 CryptEncrypt
函数的调用中,因为我是根据我在 Internet 上找到的另一个函数编写的。我对它一无所知,也不知道如何使用它。
这是我的代码:
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <cmath>
#include <string>
#pragma comment(lib, "crypt32.lib")
#define BLOCK_LEN 16
std::string AES128(std::string key, std::string data, bool enc)
{
bool Result = false;
size_t blocks = ceil((float)data.length() / BLOCK_LEN) + 1;
BYTE* chunk = new BYTE[blocks * BLOCK_LEN];
memset(chunk, 0, blocks * BLOCK_LEN);
memcpy(chunk, data.c_str(), data.length());
HCRYPTPROV hProv;
if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
goto finally;
HCRYPTHASH hHash;
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
goto finally;
if (!CryptHashData(hHash, (BYTE*)key.c_str(), key.length(), 0))
goto finally;
HCRYPTKEY hKey;
if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey))
goto finally;
for (int i = 0; i < blocks; i++)
switch (enc)
{
case true:
{
DWORD out_len = BLOCK_LEN;
if (!CryptEncrypt(hKey, NULL, i + 1 == blocks, NULL, &chunk[i * BLOCK_LEN], &out_len, blocks * BLOCK_LEN))
goto finally;
break;
}
case false:
{
DWORD out_len = BLOCK_LEN;
if (!CryptDecrypt(hKey, NULL, i + 1 == blocks, NULL, &chunk[i * BLOCK_LEN], &out_len))
goto finally;
break;
}
}
Result = true;
goto finally;
finally:
{
if (hProv)
CryptReleaseContext(hProv, 0);
if (hHash)
CryptDestroyHash(hHash);
if (hKey)
CryptDestroyKey(hKey);
if (Result)
return std::string(reinterpret_cast<char*>(chunk));
else
return "";
}
}
int main()
{
std::string key = "12345";
std::string data = "aaaaaabbbbbb";
std::string encdata = AES128(key, data, true);
std::string decdata = AES128(key, encdata, false);
printf("%s => %s => %s", data.c_str(), encdata.c_str(), decdata.c_str());
system("pause");
}
抱歉英语不好,我是巴西人。
我怀疑你的崩溃是来这里的:
return std::string(reinterpret_cast<char*>(chunk));
chunk
是一个完全随机的字节序列。它可能嵌入了空值。它几乎肯定不会以 null 结尾。此构造函数需要一个以 null 结尾的字符序列。我怀疑它会继续读取字节以寻找空值,直到它遇到无效地址并崩溃。
AES 加密数据不是字符串。它只是一个字节。你需要这样对待它。您可以将其 return 作为 vector<BYTE>
或者您可以使用 Base64 或十六进制编码函数将其转换为人类可读的字符串(如果需要的话)。请务必先解码此字符串,然后再尝试对其进行解密。
您的计算错误:ceil((float)data.length() / BLOCK_LEN) + 1
对于 12
字节输入是 2
。
但是您不需要分块加密,crypt API 可以为您处理分块。只需为整个输入调用一次。
这是一个有效的修改版本:
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <cmath>
#include <string>
#pragma comment(lib, "crypt32.lib")
#define BLOCK_LEN 16
std::string AES128(const std::string& key, const std::string& data, bool enc)
{
std::string result = data;
bool Result = false;
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hKey = NULL;
result.resize((data.length() + BLOCK_LEN - 1) & ~(BLOCK_LEN - 1));
DWORD out_len = data.length();
do {
if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
break;
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
break;
if (!CryptHashData(hHash, (const BYTE*)key.c_str(), key.length(), 0))
break;
if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey))
break;
if (enc)
{
if (!CryptEncrypt(hKey, NULL, TRUE, 0, (BYTE*)result.data(), &out_len, result.length()))
break;
}
else
{
if (!CryptDecrypt(hKey, NULL, TRUE, 0, (BYTE*)result.data(), &out_len))
break;
}
result.resize(out_len);
Result = true;
} while (false);
if (hKey)
CryptDestroyKey(hKey);
if (hHash)
CryptDestroyHash(hHash);
if (hProv)
CryptReleaseContext(hProv, 0);
if (!Result)
result = "";
return result;
}
int main()
{
std::string key = "12345";
std::string data = "aaaaaabbbbbb";
std::string encdata = AES128(key, data, true);
std::string decdata = AES128(key, encdata, false);
printf("%s => %s => %s\n", data.c_str(), encdata.c_str(), decdata.c_str());
}
我正在尝试使用 CryptoAPI 在 AES128 中加密字符串,但由于某种原因我没有得到它。当我编译时,它只会使应用程序崩溃。我认为问题出在 CryptDecrypt
和 CryptEncrypt
函数的调用中,因为我是根据我在 Internet 上找到的另一个函数编写的。我对它一无所知,也不知道如何使用它。
这是我的代码:
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <cmath>
#include <string>
#pragma comment(lib, "crypt32.lib")
#define BLOCK_LEN 16
std::string AES128(std::string key, std::string data, bool enc)
{
bool Result = false;
size_t blocks = ceil((float)data.length() / BLOCK_LEN) + 1;
BYTE* chunk = new BYTE[blocks * BLOCK_LEN];
memset(chunk, 0, blocks * BLOCK_LEN);
memcpy(chunk, data.c_str(), data.length());
HCRYPTPROV hProv;
if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
goto finally;
HCRYPTHASH hHash;
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
goto finally;
if (!CryptHashData(hHash, (BYTE*)key.c_str(), key.length(), 0))
goto finally;
HCRYPTKEY hKey;
if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey))
goto finally;
for (int i = 0; i < blocks; i++)
switch (enc)
{
case true:
{
DWORD out_len = BLOCK_LEN;
if (!CryptEncrypt(hKey, NULL, i + 1 == blocks, NULL, &chunk[i * BLOCK_LEN], &out_len, blocks * BLOCK_LEN))
goto finally;
break;
}
case false:
{
DWORD out_len = BLOCK_LEN;
if (!CryptDecrypt(hKey, NULL, i + 1 == blocks, NULL, &chunk[i * BLOCK_LEN], &out_len))
goto finally;
break;
}
}
Result = true;
goto finally;
finally:
{
if (hProv)
CryptReleaseContext(hProv, 0);
if (hHash)
CryptDestroyHash(hHash);
if (hKey)
CryptDestroyKey(hKey);
if (Result)
return std::string(reinterpret_cast<char*>(chunk));
else
return "";
}
}
int main()
{
std::string key = "12345";
std::string data = "aaaaaabbbbbb";
std::string encdata = AES128(key, data, true);
std::string decdata = AES128(key, encdata, false);
printf("%s => %s => %s", data.c_str(), encdata.c_str(), decdata.c_str());
system("pause");
}
抱歉英语不好,我是巴西人。
我怀疑你的崩溃是来这里的:
return std::string(reinterpret_cast<char*>(chunk));
chunk
是一个完全随机的字节序列。它可能嵌入了空值。它几乎肯定不会以 null 结尾。此构造函数需要一个以 null 结尾的字符序列。我怀疑它会继续读取字节以寻找空值,直到它遇到无效地址并崩溃。
AES 加密数据不是字符串。它只是一个字节。你需要这样对待它。您可以将其 return 作为 vector<BYTE>
或者您可以使用 Base64 或十六进制编码函数将其转换为人类可读的字符串(如果需要的话)。请务必先解码此字符串,然后再尝试对其进行解密。
您的计算错误:ceil((float)data.length() / BLOCK_LEN) + 1
对于 12
字节输入是 2
。
但是您不需要分块加密,crypt API 可以为您处理分块。只需为整个输入调用一次。
这是一个有效的修改版本:
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <cmath>
#include <string>
#pragma comment(lib, "crypt32.lib")
#define BLOCK_LEN 16
std::string AES128(const std::string& key, const std::string& data, bool enc)
{
std::string result = data;
bool Result = false;
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hKey = NULL;
result.resize((data.length() + BLOCK_LEN - 1) & ~(BLOCK_LEN - 1));
DWORD out_len = data.length();
do {
if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
break;
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
break;
if (!CryptHashData(hHash, (const BYTE*)key.c_str(), key.length(), 0))
break;
if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey))
break;
if (enc)
{
if (!CryptEncrypt(hKey, NULL, TRUE, 0, (BYTE*)result.data(), &out_len, result.length()))
break;
}
else
{
if (!CryptDecrypt(hKey, NULL, TRUE, 0, (BYTE*)result.data(), &out_len))
break;
}
result.resize(out_len);
Result = true;
} while (false);
if (hKey)
CryptDestroyKey(hKey);
if (hHash)
CryptDestroyHash(hHash);
if (hProv)
CryptReleaseContext(hProv, 0);
if (!Result)
result = "";
return result;
}
int main()
{
std::string key = "12345";
std::string data = "aaaaaabbbbbb";
std::string encdata = AES128(key, data, true);
std::string decdata = AES128(key, encdata, false);
printf("%s => %s => %s\n", data.c_str(), encdata.c_str(), decdata.c_str());
}