WinAPI-CryptDecrypt()在AES 256中无法正常工作

时间:2018-08-14 10:38:00

标签: c winapi encryption aes wincrypt

以前我曾经在 Visual Studio 中使用select sv.*, v.visitorid, v.visittypeid from (select s.sitesId, s.name, s.modality, count(v.visitId) as numvisits, max(v.startdate) as maxdate from sites as s left join visits as v on s.sitesid = v.sitesId group by s.sitesId, s.name, s.modality ) as sv left join visits as v on v.sitesId = sv.sitesId and v.startdate = sv.maxdate where sv.modality = "A"; ,但是现在我想使用crypto++ API函数使用 AES 256 < / strong>和 IV (cbc模式)。

我做了下面的步骤,但是我对wincrypt.hCryptEncrypt()函数感到困惑,因为它们似乎无法正常工作:

  • CryptDecrypt()定义为创建CryptAcquireContextA

    CSP
  • 对于设置键,我正在使用这种方式(导入键):

    // create a cryptographic service provider (CSP)
    CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)
    
  • IV,密钥,纯文本大小为:

    CryptImportKey(hProv, (BYTE*)&AESBlob, sizeof(AES256KEYBLOB), NULL, CRYPT_EXPORTABLE, &hKey)
    

这是我的整个#define DEFAULT_AES_KEY_SIZE 32 #define DEFAULT_IV_SIZE 16 #define BUFFER_FOR_PLAINTEXT 32

code

它只是加密了一半的纯文本,并且解密没有完成!即使仅更改// handles for csp and key HCRYPTPROV hProv = NULL; HCRYPTPROV hKey = NULL; BYTE szKey[DEFAULT_AES_KEY_SIZE + 1] = {0}; BYTE szIV[DEFAULT_IV_SIZE + 1] = {0}; // plain bytes BYTE szPlainText[BUFFER_FOR_PLAINTEXT + 1] = {0}; DWORD dwPlainSize = 0; // initalize key and plaintext StrCpyA((LPSTR)szKey, "00112233445566778899001122334455"); StrCpyA((LPSTR)szIV, "4455667788990011"); StrCpyA((LPSTR)szPlainText, "abcdefghijklmnopqrstuvwxyzabcdef"); // blob data for CryptImportKey() function (include key and version and so on...) struct AES256KEYBLOB { AES256KEYBLOB() { StrCpyA((LPSTR)szBytes, 0); } BLOBHEADER bhHdr; DWORD dwKeySize; BYTE szBytes[DEFAULT_AES_KEY_SIZE + 1]; } AESBlob; AESBlob.bhHdr.bType = PLAINTEXTKEYBLOB; AESBlob.bhHdr.bVersion = CUR_BLOB_VERSION; AESBlob.bhHdr.reserved = 0; AESBlob.bhHdr.aiKeyAlg = CALG_AES_256; AESBlob.dwKeySize = DEFAULT_AES_KEY_SIZE; StrCpyA((LPSTR)AESBlob.szBytes, (LPCSTR)szKey); // create a cryptographic service provider (CSP) if(CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { if(CryptImportKey(hProv, (BYTE*)&AESBlob, sizeof(AES256KEYBLOB), NULL, CRYPT_EXPORTABLE, &hKey)) { if(CryptSetKeyParam(hKey, KP_IV, szIV, 0)) { if(CryptEncrypt(hKey, NULL, TRUE, 0, szPlainText, &dwPlainSize, lstrlenA((LPCSTR)szPlainText) + 1)) { printf("\nEncrypted data : %s\nSize : %d\n", (LPCSTR)szPlainText, dwPlainSize); if(CryptDecrypt(hKey, NULL, TRUE, 0, szPlainText, &dwPlainSize)) { printf("\nDecrypted data : %s\nSize : %d\n", (LPCSTR)szPlainText, dwPlainSize); } else printf("failed to decrypt!"); } else printf("failed to encrypt"); } } } 的值,它也总是给我以下的输出(这意味着szPlainTextCryptEncrypt()不能按预期工作!):<​​/ p>

CryptDecrypt()

2 个答案:

答案 0 :(得分:2)

这是我从 VStudio2015 运行的一种变体。

code.c

#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <Shlwapi.h>

#define DEFAULT_AES_KEY_SIZE 32
#define DEFAULT_IV_SIZE 16
#define BUFFER_FOR_PLAINTEXT 32

#define CLEANUP_CRYPT_STUFF(PROV, KEY) \
    CryptDestroyKey(KEY); \
    CryptReleaseContext(PROV, 0)

#define PRINT_FUNC_ERR_AND_RETURN(FUNC) \
    printf("%s (line %d) failed: %d\n", ##FUNC, __LINE__, GetLastError()); \
    return -1


typedef struct AES256KEYBLOB_ {
    BLOBHEADER bhHdr;
    DWORD dwKeySize;
    BYTE szBytes[DEFAULT_AES_KEY_SIZE + 1];
} AES256KEYBLOB;


int main() {
    // handles for csp and key
    HCRYPTPROV hProv = NULL;
    HCRYPTKEY hKey = NULL;
    BYTE szKey[DEFAULT_AES_KEY_SIZE + 1] = { 0 };
    BYTE szIV[DEFAULT_IV_SIZE + 1] = { 0 };
    // plain bytes
    BYTE szPlainText[BUFFER_FOR_PLAINTEXT + 1] = { 0 }, *pBuf = NULL;
    AES256KEYBLOB AESBlob;
    memset(&AESBlob, 0, sizeof(AESBlob));

    // initalize key and plaintext
    StrCpyA((LPSTR)szKey, "00112233445566778899001122334455");
    StrCpyA((LPSTR)szIV, "4455667788990011");
    StrCpyA((LPSTR)szPlainText, "abcdefghijklmnopqrstuvwxyzabcdef");
    DWORD dwPlainSize = lstrlenA((LPCSTR)szPlainText), dwBufSize = dwPlainSize, dwBufSize2 = dwPlainSize;

    // blob data for CryptImportKey() function (include key and version and so on...)
    AESBlob.bhHdr.bType = PLAINTEXTKEYBLOB;
    AESBlob.bhHdr.bVersion = CUR_BLOB_VERSION;
    AESBlob.bhHdr.reserved = 0;
    AESBlob.bhHdr.aiKeyAlg = CALG_AES_256;
    AESBlob.dwKeySize = DEFAULT_AES_KEY_SIZE;
    StrCpyA((LPSTR)AESBlob.szBytes, (LPCSTR)szKey);

    // create a cryptographic service provider (CSP)
    if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        PRINT_FUNC_ERR_AND_RETURN(CryptAcquireContextA);
    }
    if (!CryptImportKey(hProv, (BYTE*)&AESBlob, sizeof(AES256KEYBLOB), NULL, CRYPT_EXPORTABLE, &hKey)) {
        CryptReleaseContext(hProv, 0);
        PRINT_FUNC_ERR_AND_RETURN(CryptImportKey);
    }
    if (!CryptSetKeyParam(hKey, KP_IV, szIV, 0)) {
        CLEANUP_CRYPT_STUFF(hProv, hKey);
        PRINT_FUNC_ERR_AND_RETURN(CryptSetKeyParam);
    }
    if (CryptEncrypt(hKey, NULL, TRUE, 0, NULL, &dwBufSize, 0)) {
        printf("%d bytes required to hold the encrypted buf\n", dwBufSize);
        if ((pBuf = calloc(dwBufSize, sizeof(BYTE))) == NULL)
        {
            CLEANUP_CRYPT_STUFF(hProv, hKey);
            PRINT_FUNC_ERR_AND_RETURN(calloc);
        }
        StrCpyA(pBuf, szPlainText);
    } else {
        CLEANUP_CRYPT_STUFF(hProv, hKey);
        PRINT_FUNC_ERR_AND_RETURN(CryptEncrypt);
    }
    if (CryptEncrypt(hKey, NULL, TRUE, 0, pBuf, &dwBufSize2, dwBufSize)) {
        printf("\nEncrypted data: [%s]\nSize: %d\n", (LPCSTR)pBuf, dwBufSize2);
        if (CryptDecrypt(hKey, NULL, TRUE, 0, pBuf, &dwBufSize)) {
            printf("\nDecrypted data: [%s]\nSize: %d\n", (LPCSTR)pBuf, dwBufSize);
        } else {
            free(pBuf);
            CLEANUP_CRYPT_STUFF(hProv, hKey);
            PRINT_FUNC_ERR_AND_RETURN(CryptDecrypt);
        }
    } else {
        free(pBuf);
        CLEANUP_CRYPT_STUFF(hProv, hKey);
        PRINT_FUNC_ERR_AND_RETURN(CryptEncrypt);
    }
    free(pBuf);
    CLEANUP_CRYPT_STUFF(hProv, hKey);
    return 0;
}

注释

  • 当我遇到访问冲突时,删除了AES256KEYBLOB构造函数(这在使用内存“不是你的”时很正常)。将结构初始化替换为memset调用
  • (逻辑)主要错误是缓冲区不够大,无法存储加密的文本(结合了错误的值( 0 )用于dwPlainSize-使函数误导成功)。根据{{​​3}}:

      

    如果此参数包含 NULL ,则此函数将计算密文所需的大小,并将其放在 pdwDataLen 参数所指向的值中。

    要找出所需的大小,请另外调用该函数,将pbData设置为NULL(在其他 WinAPI 中也会遇到这种情况)。然后分配一个缓冲区,用所需的数据填充它,并使“ main”在该缓冲区上调用函数...

  • 添加了丢失的#includemain

  • 添加了代码以在不再需要时释放使用的资源
  • 重新标记:
    • 否定了if条件,因为我不喜欢这么多的嵌套级别
    • 添加了一些便利宏(CLEANUP_CRYPT_STUFFPRINT_FUNC_ERR_AND_RETURN),以避免代码重复
  • 其他次要修复/改进
  • 您可能想添加一个从缓冲区中精确打印 N 个字节的函数,因为%s说明符仅在遇到\0时停止,只有{哑}的运气阻止了printf缓冲时,控制台充满了垃圾(甚至导致程序崩溃)
  • 可能还有一些我没有处理过的与此功能相关的方面(因为我不是该领域的专家),但目标只是使工作顺利进行

输出

48 bytes required to hold the encrypted buf

Encrypted data: [<É╙åh∩φ:bOPs  r2w~w╪c╟D╡ï╥V╟neΓßv∩·J8cÅ╥²²²²s]
Size: 48

Decrypted data: [abcdefghijklmnopqrstuvwxyzabcdefΓßv∩·J8cÅ╥²²²²s]
Size: 32

答案 1 :(得分:2)

CristiFati的答案很好,这使我可以使用波纹管语句来计算密码长度:

CryptEncrypt(hKey, NULL, TRUE, 0, NULL, &dwBufSize, 0);

根据Microsoft文档:

  

如果 pbData NULL ,则不会返回任何错误,并且该函数将加密数据的大小(以字节为单位)存储在pdwDataLen指向的DWORD值中) :

BOOL CryptEncrypt(
  HCRYPTKEY  hKey,
  HCRYPTHASH hHash,
  BOOL       Final,
  DWORD      dwFlags,
  BYTE       *pbData,
  DWORD      *pdwDataLen,
  DWORD      dwBufLen
);

我的解决方案:

但是在我的代码中,当我将szPlainText赋给CryptEncrypt()时,我只是忘记了计算大小:

DWORD dwPlainSize = 0;    // initialized with 0

因此,“零长度”对于波纹管功能没有任何意义(CryptEncrypt()函数始终获得长度为0的纯文本):

CryptEncrypt(hKey, NULL, TRUE, 0, szPlainText, &dwPlainSize, lstrlenA((LPCSTR)szPlainText) + 1)

我应该用下面的语句设置它的大小(只需添加以下内容,我的code就可以工作):

dwPlainSize = lstrlenA((LPCSTR)szPlainText);

然后在正确的情况下传递它:

CryptEncrypt(hKey, NULL, TRUE, 0, szPlainText, &dwPlainSize, BUFFER_FOR_PLAINTEXT)

所以,输出就像下面这样:

Encrypted data : <É╙åh∩φ:bOPs  r2w~w╪c╟D╡ï╥V╟neΓßv∩·J8cÅ╥
Size : 48

Decrypted data : abcdefghijklmnopqrstuvwxyzabcdefΓßv∩·J8cÅ╥
Size : 32