【问题标题】:AES128 with CryptoAPIAES128 和 CryptoAPI
【发布时间】:2018-07-11 20:03:15
【问题描述】:

我正在尝试使用 CryptoAPI 加密 AES128 中的字符串,但由于某种原因我没有得到它。当我编译时,它只会使应用程序崩溃。我相信问题出在CryptDecryptCryptEncrypt 函数的调用中,因为我是根据我在互联网上找到的另一个函数编写这个函数的。我对它一无所知,也不知道如何使用它。

这是我的代码:

#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");
}

抱歉英语不好,我是巴西人。

【问题讨论】:

  • 编译时会崩溃吗?
  • 不,当我使用调试器运行程序时它崩溃了。
  • 如果葡萄牙语对你来说更方便,别忘了还有Stack Overflow em Português
  • 什么是崩溃?什么线路,什么信号,什么堆栈跟踪?

标签: c openssl aes cryptoapi


【解决方案1】:

您的计算已关闭:ceil((float)data.length() / BLOCK_LEN) + 12 对于 12-byte 输入。

但您不需要分块加密,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());
}

【讨论】:

    【解决方案2】:

    我怀疑你的崩溃即将到来:

    return std::string(reinterpret_cast<char*>(chunk));
    

    chunk 是一个完全随机的字节序列。它可能嵌入了空值。它几乎肯定不会以 null 结尾。此构造函数需要一个以 null 结尾的字符序列。我怀疑它会继续读取字节以寻找空值,直到它遇到无效地址并崩溃。

    AES 加密的数据不是字符串。它只是一个字节。你需要这样对待它。您可以将其作为vector&lt;BYTE&gt; 返回,或者如果您需要,您可以使用 Base64 或十六进制编码函数将其转换为人类可读的字符串。请务必在尝试解密之前解码此字符串。

    【讨论】:

      猜你喜欢
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-04
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多