我正在尝试使用 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 时间出现:
- 确保您用 C# 加密的文件可以用 C# 解密。这将消除任何文件保存截断问题。
- 首先尝试使用固定的硬编码 key (不派生密码)进行加密和解密,这将确保您的 key 集代码 IV 初始化正确(以及填充模式和密码链模式)。
- 确保密码派生过程使用相同的哈希值。诸如 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/