【问题标题】:Decrypt C#-encrypted data in C++ using Windows AES crypto provider使用 Windows AES 加密提供程序在 C++ 中解密 C# 加密的数据
【发布时间】:2017-04-21 13:05:14
【问题描述】:

我需要使用 RijndaelManaged 在 C# 中加密数据并在 C++ 代码中解密。

C#加密代码:

static string Encrypt(string plainText)
{
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

    var keyBytes = new byte[] { /* ... 32 bytes of a key */};
    byte[] iv = new byte[] { /* ... 16 bytes of IV */ };


    var symmetricKey = new RijndaelManaged() 
    { 
        Mode = CipherMode.CBC, 
        Padding = PaddingMode.Zeros, 
        BlockSize = 128, // Must be 128 to be compatible with AES
        KeySize = 256 
    };

    var encryptor = symmetricKey.CreateEncryptor(keyBytes, iv);

    byte[] cipherTextBytes;
    using(var memoryStream = new MemoryStream())
    {
        using(var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            cipherTextBytes = memoryStream.ToArray();
            cryptoStream.Close();
        }
        memoryStream.Close();
    }
    return Convert.ToBase64String(cipherTextBytes);
}

但是当用 C++ 代码解密它时,我总是得到来自 CryptDecrypt 的 NTE_BAD_DATA 回复。这是 C++ 代码(为清楚起见,所有检查都已删除):

__declspec(dllexport) DWORD  Decrypt(char* stringBuffer)
{
string encryptedString(stringBuffer);

// Decode base64 string to byte array. Works ok, the binary array is the same as the one in C# code.
vector<BYTE> encryptionBuffer = Base64::decode(encryptedString);
DWORD bufferSize = encryptionBuffer.size();

struct CryptoBlob {
    BLOBHEADER header;
    DWORD cbKeySize;
    BYTE rgbKeyData[32];
} keyBlob;

keyBlob.header.bType = PLAINTEXTKEYBLOB;
keyBlob.header.bVersion = CUR_BLOB_VERSION;
keyBlob.header.reserved = 0;
keyBlob.header.aiKeyAlg = CALG_AES_256;
keyBlob.cbKeySize = 32;

BYTE keyData[32] = { /* 32 bytes of a key the same as in C# code */ };
BYTE ivData[16] = { /* 16 bytes of IV the same as in C# code */ };

memcpy(keyBlob.rgbKeyData, keyData, 32);

HCRYPTKEY hPubKey;
HCRYPTPROV hProv;

CryptAcquireContext(
    &hProv,
    NULL,
    NULL,
    PROV_RSA_AES,
    CRYPT_VERIFYCONTEXT);

CryptImportKey(hProv, (const LPBYTE)&keyBlob, sizeof(keyBlob), 0, 0, &hPubKey);
CryptSetKeyParam(hPubKey, KP_IV, ivData, 0);

// Here the error happens, the value returned is 0x80090005 (NTE_BAD_DATA)
DWORD err = CryptDecrypt(hPubKey, 0, TRUE, 0, encryptionBuffer.data(), &bufferSize);

// overwrite the input buffer with decrypted data
memset(stringBuffer, 0, encryptedString.length());
memcpy(stringBuffer, encryptionBuffer.data(), bufferSize);

return 0;
}

知道有什么问题吗? 谢谢!

【问题讨论】:

标签: c# c++ encryption aes


【解决方案1】:

当您将 TRUE 作为第三个参数传递给 CryptDecrypt 时,它会尝试撤消 PKCS#7 填充。当它无法撤消该填充时,它会发出 NTE_BAD_DATA。

由于您已将加密的填充模式更改为 Pkcs7 以外的值,因此您需要传递 FALSE 并执行手动去填充。

由于 PaddingMode.Zeros 本质上不是可撤销的,因此无需执行去填充。

【讨论】:

    【解决方案2】:

    如果以上不是答案,我建议在 C++ 和 C# 中查看它们的 key/iv,并确保字节数组看起来完全相同。

    末尾的额外字符可能会导致问题。

    如果它们不匹配,请注意,在编程语言和实现之间,返回的输出类型可能会有所不同(例如有符号/无符号、字符/字节数组),这也会导致问题。

    【讨论】:

    • 是的,非常不清楚,我编辑了它,感谢您的评论。
    猜你喜欢
    • 1970-01-01
    • 2013-04-19
    • 2011-02-28
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    相关资源
    最近更新 更多