如何在Windows上使用NCryptDecrypt解密AES cipherText

时间:2018-01-11 10:53:08

标签: c++ windows cryptography encryption-symmetric cng

我正在尝试使用Ncrypt.lib加密带有AES的纯文本,然后对其进行解密。

我使用Ncrypt.lib,因为我想使用持久的symetric键。

我的问题是解密部分工作。实际上,我没有正确解密前16个字节。

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <ncrypt.h>
#include <bcrypt.h>

void PrintBytes(
  IN BYTE     *pbPrintData,
  IN DWORD    cbDataLen) {
    DWORD dwCount = 0;

    for (dwCount = 0; dwCount < cbDataLen; dwCount++) {
      printf("0x%02x, ", pbPrintData[dwCount]);

      if (0 == (dwCount + 1) % 10) putchar('\n');
    }
}

int main() {

  BYTE plaintext[] =
  {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
  };
  static const int plainTextLen = 48;

  printf("PlainText:\n");
  PrintBytes(plaintext, plainTextLen);
  printf("\n");

  LPCWSTR keyName = L"NCryptTest";
  SECURITY_STATUS status;
  NCRYPT_PROV_HANDLE hProvider;
  NCRYPT_KEY_HANDLE hKey;

  // Open storage provider
  status = NCryptOpenStorageProvider(&hProvider, NULL, 0);

  // Get stored key
  status = NCryptOpenKey(hProvider, &hKey, keyName, 0, 0);
  if (status == NTE_BAD_KEYSET) {
    // Create key if it doesn't exist
    status = NCryptCreatePersistedKey(hProvider, &hKey, BCRYPT_AES_ALGORITHM, keyName, 0, 0);
    status = NCryptFinalizeKey(hKey, 0);
  }

  // Set the chaining mode to cipher feedback
  LPCWSTR chainMode = BCRYPT_CHAIN_MODE_CFB;
  status = NCryptSetProperty(hKey, NCRYPT_CHAINING_MODE_PROPERTY, 
  (PBYTE)chainMode, wcslen(chainMode) * 2 + 2, 0);

  // Random iv but here, it's fixed
  //char* iv = "0123456789abcdef";
  //status = NCryptSetProperty(hKey, BCRYPT_INITIALIZATION_VECTOR, 
  //(PBYTE)iv, 16, 0);

  // Get size of the cipher text
  DWORD cbCipherText = 0;
  status = NCryptEncrypt(hKey, plaintext, plainTextLen, NULL, NULL, 0, 
  &cbCipherText, 0);
  PBYTE pbCipherText = NULL;
  pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
  if (pbCipherText == NULL) {
    printf("Error! memory allocation failed\n");
  }

  // Encrypt
  DWORD outlen = -1;
  status = NCryptEncrypt(hKey, plaintext, plainTextLen, NULL, pbCipherText, 
  cbCipherText, &outlen, 0);
  printf("CipherText:\n");
  PrintBytes(pbCipherText, cbCipherText);
  printf("\n");

  // Get size of the plain text
  DWORD cbPlainText = 0;
  status = NCryptDecrypt(hKey, pbCipherText, cbCipherText, NULL, NULL, 0, 
  &cbPlainText, 0);
  PBYTE pbPlainText = NULL;
  pbPlainText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbPlainText);
  if (pbPlainText == NULL) {
      printf("Error! memory allocation failed\n");
  }

  // Decrypt
  outlen = -1;
  status = NCryptDecrypt(hKey, pbCipherText, cbCipherText, NULL, 
  pbPlainText, cbPlainText, &outlen, 0);
  printf("PlainText:\n");
  PrintBytes(pbPlainText, cbPlainText);
  printf("\n");

  // Cleanup
  NCryptFreeObject(hKey);
  NCryptFreeObject(hProvider);

  getchar();
  return 0;
}

结果是:

PlainText:
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,

CipherText:
0xc5, 0xdc, 0x7e, 0xde, 0x83, 0x35, 0xbc, 0x34, 0x27, 0x4b,
0xf9, 0xde, 0x40, 0x36, 0xeb, 0x6d, 0xaf, 0x51, 0x8c, 0x48,
0x69, 0xa0, 0x16, 0xfb, 0x6d, 0x80, 0x44, 0xea, 0x5c, 0x74,
0x27, 0x38, 0xf1, 0x20, 0xa3, 0x87, 0x65, 0xc3, 0xcf, 0x62,
0x94, 0x84, 0xc9, 0xcd, 0x55, 0x4c, 0x7b, 0x48,

PlainText:
0x1d, 0x52, 0x88, 0x1b, 0x0c, 0x01, 0x13, 0xed, 0xe0, 0x39,
0x1e, 0x96, 0x67, 0x39, 0x72, 0x38, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,

我怀疑初始化向量问题,但我不知道如何使用它,只需使用BCRYPT_INITIALIZATION_VECTOR?或者我必须将随机iv放在纯文本前面?

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

回答评论:

  

这是因为每次成功调用NCryptEncrypt或NCryptDecrypt都会改变hKey的状态。所以你不能使用相同的密钥。加密后 - 您需要再次获取解密密钥 - RbMm

谢谢@RbMm!