【问题标题】:Bad Data error at CryptDecrypt when using AES 256 (MS CryptoAPI)使用 AES 256 (MS CryptoAPI) 时 CryptDecrypt 出现错误数据错误
【发布时间】:2011-10-21 15:05:57
【问题描述】:

我正在尝试解密 - 在 C++ 中使用微软的 CryptoAPI - 在 PHP 中使用 mcrypt_encrypt 加密的短消息。 php行是: mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $msg, MCRYPT_MODE_CBC);

其中 $key 和 $msg 是字符串。

在 C++ 中,我有密钥,我的解密函数如下所示:

bool decrypt( const unsigned char* input_buffer,
                 const size_t& input_size,
                 const unsigned char* key,
                 const size_t& key_size,
                 unsigned char* output_buffer,
                 DWORD* out_size)
{
   Log(L"START init_crypto");

   bool       ret        = false;
   HCRYPTKEY  hKey       = NULL;
   HCRYPTPROV hCryptProv = NULL;
   DWORD      dwDataLen  = 0;

   // Attempt to acquire a handle to the crypto provider for AES
   if(0 == CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT) ){//PROV_RSA_AES
    Log(L"CryptAcquireContext failed with code %ld", GetLastError());
        goto end;
}

   // key creation based on
   // http://mirror.leaseweb.com/NetBSD/NetBSD-release-5-0/src/dist/wpa/src/crypto/crypto_cryptoapi.c
   struct {
     BLOBHEADER hdr;
     DWORD len;
     BYTE key[32]; 
   } key_blob;

   key_blob.hdr.bType    = PLAINTEXTKEYBLOB;
   key_blob.hdr.bVersion = CUR_BLOB_VERSION;
   key_blob.hdr.reserved = 0;
   key_blob.hdr.aiKeyAlg = CALG_AES_256;
   key_blob.len          = 32;//key_size;

   memset(key_blob.key, '\0', sizeof(key_blob.key));

   assert(key_size <= sizeof(key_blob.key));
   CopyMemory(key_blob.key, key, min(key_size, sizeof(key_blob.key)));

   if (!CryptImportKey( hCryptProv,
                    (BYTE *)&key_blob,
                    sizeof(key_blob),
                    0,
                    CRYPT_EXPORTABLE,
                    &hKey)){
      Log(L"Error in CryptImportKey 0x%08x \n", GetLastError());
      goto free_context;
   }
   else{
       //---------------------------
       // Set Mode
       DWORD dwMode = CRYPT_MODE_CBC;
       if(!CryptSetKeyParam( hKey, KP_MODE, (BYTE*)&dwMode, 0 )){
           // Handle error
           Log(L"Cannot set the cbc mode for decryption 0x%08x \n", GetLastError());
           goto free_key;
       }

       //----------------------------
       // Set IV
       DWORD dwBlockLen = 0;
       DWORD dwDataLen  = sizeof(dwBlockLen);
       if (!CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwDataLen, 0)){
           // Handle error
           Log(_USTR("Cannot get the block length 0x%08x \n"), GetLastError());
           goto free_key;
       }
       dwBlockLen /= 8;
       BYTE *pbTemp = NULL;
       if (!(pbTemp = (BYTE *)LocalAlloc(LMEM_FIXED, dwBlockLen))){
           // Handle error
           Log(L"Cannot allcoate the IV block 0x%08x \n", GetLastError());
          goto free_key;
       }
       memset(pbTemp, '\0', dwBlockLen);
       if (!CryptSetKeyParam(hKey, KP_IV, pbTemp, 0)){
           // Handle error
           Log(L"Cannot set the IV block 0x%08x \n", GetLastError());
           LocalFree(pbTemp);
           goto free_key;
        }

        LocalFree(pbTemp);
  }

  CopyMemory(output_buffer, input_buffer, min(*out_size, input_size));
  *out_size = input_size;

  if (!CryptDecrypt(hKey, NULL, TRUE, 0, output_buffer, out_size)){
    Log(L"CryptDecrypt failed with code %ld", GetLastError());
    goto free_key;
  }
  else{
    Log(L"Decryption...");
    ret = true;
  }
free_key:
   if (hKey)
      CryptDestroyKey( hKey );

free_context:
   if (hCryptProv)
      CryptReleaseContext(hCryptProv, 0);
end:
   return ret;
}

我一直在 CryptDecrypt() 中收到“错误数据”错误...我可能遗漏了一些明显的东西 - 如果是这样,请帮忙。

编辑 - 为了找出问题的原因,我用以下代码替换了 CryptDecrypt(CopyMemory 的东西)之前的两行: ....

 strcpy((char*)output_buffer, "stuff");
 DWORD plain_txt_len = strlen((char*)output_buffer);
 if (!CryptEncrypt(hKey, NULL, TRUE, 0, output_buffer, &plain_txt_len, *out_size)){
      Log(L"CryptEncrypt failed with code 0x%08x", GetLastError());
      goto free_key;
 }  

... 并且 CryptDecrypt 正在工作 - 这让我相信问题是从 php 到 C++ 的密钥/和或消息传输......如果你同意,你能给我一个关于如何确保我在 PHP 中使用的字符串的提示与 C++ 中的相同(在字节级别?)

EDIT2 -- 在我在 php 中更改二进制流中的字符串(使用包)之后,在我从这里为 AES vs Rijndael 实现了解决方法(?)之后:http://kix.in/2008/07/22/aes-256-using-php-mcrypt/ 我终于让 CryptDecrypt 解密我的 PHP 消息......问题是它也仍然失败 - 即使输出包含解密的文本。关于为什么会发生这种情况的任何想法?

【问题讨论】:

  • 确保在通道的两端使用相同的填充模式。

标签: c++ cryptography cryptoapi


【解决方案1】:

在获取上下文时尝试传递NULL 而不是CRYPT_VERIFYCONTEXT

【讨论】:

    猜你喜欢
    • 2020-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2018-09-09
    相关资源
    最近更新 更多