gpt4 book ai didi

c - 如何在 GCM 模式下使用 AES 链接 BCryptEncrypt 和 BCryptDecrypt 调用?

转载 作者:可可西里 更新时间:2023-11-01 12:39:03 24 4
gpt4 key购买 nike

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

根据 documentation for CNG , 支持以下场景:

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 的返回值,这等于 ntstatus.h 中定义的 STATUS_AUTH_TAG_MISMATCH.

即使参数 pbIV 被标记为 in/out,参数 pbIV 指向的元素不会被 BCryptEncrypt() 。这是预期的吗?我还查看了 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO 结构中的字段 pbNonce,由 pPaddingInfo 指针指向,但该字段也没有被修改。我也尝试过“手动”推进IV,根据计数器方案自己修改内容,但这也没有帮助。

成功链接 BCryptEncrypt 和/或 BCryptDecrypt 函数的正确过程是什么?

最佳答案

我设法让它工作。看来问题出在 MSDN 中,它应该提到设置 BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG 而不是 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;
}

关于c - 如何在 GCM 模式下使用 AES 链接 BCryptEncrypt 和 BCryptDecrypt 调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30720414/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com