c++ - Wincrypt : Unable to decrypt file which was encrypted in C#. NTE_BAD_DATA 在 CryptDecrypt

标签 c++ cryptography encryption cryptoapi

我正在尝试使用 wincrypt 解密一段文件,但我似乎无法正确解密此函数。这些字节使用 C# 中的 RC2 实现加密,我为加密和解密过程提供相同的密码和 IV(在 C# 中加密,在 C++ 中解密)。

在最后的“CryptDecrypt”函数之前,我的所有函数都返回 true。不用我再打字了,这里是函数:

static char* DecryptMyFile(char *input, char *password, int size)
{
    HCRYPTPROV provider = NULL;

    if(CryptAcquireContext(&provider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {printf("Context acquired.");}
    else
    {
        if (GetLastError() == NTE_BAD_KEYSET)
        {
        if(CryptAcquireContext(&provider, 0, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
            {printf("new key made.");}
            else
            {
                printf("Could not acquire context.");
            }
        }
        else
        {printf("Could not acquire context.");}
    }

    HCRYPTKEY key = NULL;
    HCRYPTHASH hash = NULL;

    if(CryptCreateHash(provider, CALG_MD5, 0, 0, &hash))
    {printf("empty hash created.");}
    else
    {printf("could not create hash.");}

    if(CryptHashData(hash, (BYTE *)password, strlen(password), 0))
    {printf("data buffer is added to hash.");}
    else
    {printf("error. could not add data buffer to hash.");}

    if(CryptDeriveKey(provider, CALG_RC2, hash, 0, &key)) 
    {printf("key derived.");}
    else
    {printf("Could not derive key.");}

    DWORD dwKeyLength = 128;

if(CryptSetKeyParam(key, KP_EFFECTIVE_KEYLEN, reinterpret_cast<BYTE*>(&dwKeyLength), 0))
    {printf("success");}
    else
    {printf("failed.");}

    BYTE IV[8] = {0,0,0,0,0,0,0,0};

    if(CryptSetKeyParam(key, KP_IV, IV, 0))
    {printf("worked");}
    else
    {printf("faileD");}

    DWORD dwCount = size;
    BYTE *decrypted = new BYTE[dwCount + 1];

    memcpy(decrypted, input, dwCount);
    decrypted[dwCount] = 0;


    if(CryptDecrypt(key,0, true, 0, decrypted, &dwCount))
    {printf("succeeded");}
    else
    {printf("failed");}

return (char *)decrypted;
}

输入是传递给函数的加密数据。 password 与用于在 C# 中加密数据的密码相同。 size 是加密时数据的大小。
在 CryptDecrypt 之前,上述所有函数都返回 true,我似乎无法弄清楚原因。同时,我不确定 CryptDecrypt 函数如何编辑我的“解密”变量,因为我没有传递它的引用。

对于为什么这不起作用的任何帮助或建议,我们将不胜感激。这是我第一次尝试使用 wincrypt,也是多年来第一次使用 C++。

如果还有帮助,这是我的加密(在 C# 中):

 public static byte[] EncryptString(byte[] input, string password)
    {
        PasswordDeriveBytes pderiver = new PasswordDeriveBytes(password, null);
        byte[] ivZeros = new byte[8];
        byte[] pbeKey = pderiver.CryptDeriveKey("RC2", "MD5", 128, ivZeros);

        RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider();

        //using an empty initialization vector for convenience.
        byte[] IV = new byte[8];
        ICryptoTransform encryptor = RC2.CreateEncryptor(pbeKey, IV);

        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
        csEncrypt.Write(input, 0, input.Length);
        csEncrypt.FlushFinalBlock();

        return msEncrypt.ToArray();
    }

我已确认我在 C++ 中的哈希值与我在 C# 中的 key 相同,由 PasswordDeriveBytes.CryptDeriveKey 创建

最佳答案

首先,如我的评论所述,使用 GetLastError() 以便您知道什么它失败了。我假设您得到 NTE_BAD_DATA,所有其他错误都更容易处理,因为它们基本上意味着您错过了 API 调用序列中的某个步骤。

CryptDecrypt 因 NTE_BAD_DATA 而失败的典型原因是您正在解密 block 密码的最后一个 block (如您所愿)并且解密的填充字节不正确。如果输入被截断(并非所有加密字节都保存到文件中)或 key 不正确,就会发生这种情况。

我建议您有条不紊地进行此操作,因为有很多地方可能会失败,并且只会在 CryptDecrypt 时间出现:

  1. 确保您用 C# 加密的文件可以用 C# 解密。这将消除任何文件保存截断问题。
  2. 首先尝试使用固定的硬编码 key (不派生密码)进行加密和解密,这将确保您的 key 集代码 IV 初始化正确(以及填充模式和密码链模式)。
  3. 确保密码派生过程使用相同的哈希值。诸如 ANSI 与 Unicode 或终端 0 之类的东西可能会对 MD5 散列造成严重破坏,并导致表面上相同的密码散列产生截然不同的 key 。

关于c++ - Wincrypt : Unable to decrypt file which was encrypted in C#. NTE_BAD_DATA 在 CryptDecrypt,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1546447/

相关文章:

php - 快速搜索加密数据?

c++ - 从具有非虚拟析构函数的类中私有(private)继承是否安全?

c++ - 使用 Boost 的多元正态分布样本

iOS:如何以编程方式从应用程序中的私钥和 x509 证书创建 PKCS12 (P12) keystore ?

java - 如何在java中有一个常量初始化 vector 和 key ?

java - 如何最大限度地减少 HTTP 请求中的大量数据?

C++ 扩展函数?

c++ - 嗅探 QWebsocket 服务器 - 客户端通信

c# - 使用加密后在终结器线程中获取 "ReleaseHandleFailed"MDA

c - 加密实现 - 令人困惑的结果