如何在GCM模式下使用AES链接BCryptEncrypt和BCryptDecrypt调用? [英] How to chain BCryptEncrypt and BCryptDecrypt calls using AES in GCM mode?

查看:213
本文介绍了如何在GCM模式下使用AES链接BCryptEncrypt和BCryptDecrypt调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Windows CNG API,我能够在GCM模式下使用AES通过身份验证来加密和解密单个数据块。我现在要连续加密和解密多个缓冲区。

Using the Windows CNG API, I am able to encrypt and decrypt individual blocks of data with authentication, using AES in GCM mode. I now want to encrypt and decrypt multiple buffers in a row.

根据 CNG文档,支持以下情况:


如果加密或解密的输入分散在多个
缓冲区中,则必须将调用链接到BCryptEncrypt和
BCryptDecrypt函数。通过在dwFlags成员中设置
BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG标志来指示链接。

If the input to encryption or decryption is scattered across multiple buffers, then you must chain calls to the BCryptEncrypt and BCryptDecrypt functions. Chaining is indicated by setting the BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG flag in the dwFlags member.

如果我理解正确,则表示我可以在多个缓冲区上依次调用 BCryptEncrypt ,最后获得组合缓冲区的身份验证标签。同样,我可以依次在多个缓冲区上调用 BCryptDecrypt ,同时将实际的身份验证检查推迟到最后。但是,我无法正常工作,它似乎忽略了 dwFlags 的值。每当我使用 BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG 时,我得到的返回值 0xc000a002 等于 STATUS_AUTH_TAG_MISMATCH (在 ntstatus.h 中定义。)

If I understand it correctly, this means that I can invoke BCryptEncrypt sequentially on multiple buffers an obtain the authentication tag for the combined buffers at the end. Similarly, I can invoke BCryptDecrypt sequentially on multiple buffers while deferring the actual authentication check until the end. I can not get that to work though, it looks like the value for dwFlags is ignored. Whenever I use BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG, I get a return value of 0xc000a002 , which is equal to STATUS_AUTH_TAG_MISMATCH as defined in ntstatus.h.

即使参数 pbIV 被标记为输入/输出,参数 pbIV 指向的元素不会被 BCryptEncrypt修改()。那是预期的吗?我还查看了 pPaddingInfo BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO 结构中的字段 pbNonce / code>指针,但是该指针也不会被修改。我还尝试手动推进IV,根据计数器方案自己修改内容,但这也无济于事。

Even though the parameter pbIV is marked as in/out, the elements pointed to by the parameter pbIV do not get modified by BCryptEncrypt(). Is that expected? I also looked at the field pbNonce in the BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO structure, pointed to by the pPaddingInfo pointer, but that one does not get modified either. I also tried "manually" advancing the IV, modifying the contents myself according to the counter scheme, but that did not help either.

什么是正确的方法来链接 BCryptEncrypt 和/或 BCryptDecrypt 是否成功运行?

What is the right procedure to chain the BCryptEncrypt and/or BCryptDecrypt functions successfully?

推荐答案

我设法使其正常运行。看来问题出在MSDN中,应该提到设置 BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG 而不是 BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG

I managed to get it to work. It seems that the problem is in MSDN, it should mention setting BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG instead of BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG.

#include <windows.h>
#include <assert.h>
#include <vector>
#include <Bcrypt.h>
#pragma comment(lib, "bcrypt.lib")

std::vector<BYTE> MakePatternBytes(size_t a_Length)
{
    std::vector<BYTE> result(a_Length);
    for (size_t i = 0; i < result.size(); i++)
    {
        result[i] = (BYTE)i;
    }

    return result;
}

std::vector<BYTE> MakeRandomBytes(size_t a_Length)
{
    std::vector<BYTE> result(a_Length);
    for (size_t i = 0; i < result.size(); i++)
    {
        result[i] = (BYTE)rand();
    }

    return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
    NTSTATUS bcryptResult = 0;
    DWORD bytesDone = 0;

    BCRYPT_ALG_HANDLE algHandle = 0;
    bcryptResult = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_AES_ALGORITHM, 0, 0);
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptOpenAlgorithmProvider");

    bcryptResult = BCryptSetProperty(algHandle, BCRYPT_CHAINING_MODE, (BYTE*)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptSetProperty(BCRYPT_CHAINING_MODE)");

    BCRYPT_AUTH_TAG_LENGTHS_STRUCT authTagLengths;
    bcryptResult = BCryptGetProperty(algHandle, BCRYPT_AUTH_TAG_LENGTH, (BYTE*)&authTagLengths, sizeof(authTagLengths), &bytesDone, 0);
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptGetProperty(BCRYPT_AUTH_TAG_LENGTH)");

    DWORD blockLength = 0;
    bcryptResult = BCryptGetProperty(algHandle, BCRYPT_BLOCK_LENGTH, (BYTE*)&blockLength, sizeof(blockLength), &bytesDone, 0);
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptGetProperty(BCRYPT_BLOCK_LENGTH)");

    BCRYPT_KEY_HANDLE keyHandle = 0;
    {
        const std::vector<BYTE> key = MakeRandomBytes(blockLength);
        bcryptResult = BCryptGenerateSymmetricKey(algHandle, &keyHandle, 0, 0, (PUCHAR)&key[0], key.size(), 0);
        assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptGenerateSymmetricKey");
    }

    const size_t GCM_NONCE_SIZE = 12;
    const std::vector<BYTE> origNonce = MakeRandomBytes(GCM_NONCE_SIZE);
    const std::vector<BYTE> origData  = MakePatternBytes(256);

    // Encrypt data as a whole
    std::vector<BYTE> encrypted = origData;
    std::vector<BYTE> authTag(authTagLengths.dwMinLength);
    {
        BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
        BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
        authInfo.pbNonce = (PUCHAR)&origNonce[0];
        authInfo.cbNonce = origNonce.size();
        authInfo.pbTag   = &authTag[0];
        authInfo.cbTag   = authTag.size();

        bcryptResult = BCryptEncrypt
            (
            keyHandle,
            &encrypted[0], encrypted.size(),
            &authInfo,
            0, 0,
            &encrypted[0], encrypted.size(),
            &bytesDone, 0
            );

        assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptEncrypt");
        assert(bytesDone == encrypted.size());
    }

    // Decrypt data in two parts
    std::vector<BYTE> decrypted = encrypted;
    {
        DWORD partSize = decrypted.size() / 2;

        std::vector<BYTE> macContext(authTagLengths.dwMaxLength);

        BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
        BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
        authInfo.pbNonce = (PUCHAR)&origNonce[0];
        authInfo.cbNonce = origNonce.size();
        authInfo.pbTag   = &authTag[0];
        authInfo.cbTag   = authTag.size();
        authInfo.pbMacContext = &macContext[0];
        authInfo.cbMacContext = macContext.size();

        // IV value is ignored on first call to BCryptDecrypt.
        // This buffer will be used to keep internal IV used for chaining.
        std::vector<BYTE> contextIV(blockLength);

        // First part
        authInfo.dwFlags = BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
        bcryptResult = BCryptDecrypt
            (
            keyHandle,
            &decrypted[0*partSize], partSize,
            &authInfo,
            &contextIV[0], contextIV.size(),
            &decrypted[0*partSize], partSize,
            &bytesDone, 0
            );

        assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptDecrypt");
        assert(bytesDone == partSize);

        // Second part
        authInfo.dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
        bcryptResult = BCryptDecrypt
            (
            keyHandle,
            &decrypted[1*partSize], partSize,
            &authInfo,
            &contextIV[0], contextIV.size(),
            &decrypted[1*partSize], partSize,
            &bytesDone, 0
            );

        assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptDecrypt");
        assert(bytesDone == partSize);
    }

    // Check decryption
    assert(decrypted == origData);

    // Cleanup
    BCryptDestroyKey(keyHandle);
    BCryptCloseAlgorithmProvider(algHandle, 0);

    return 0;
}

这篇关于如何在GCM模式下使用AES链接BCryptEncrypt和BCryptDecrypt调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆