我正在尝试使用wincrypt解密一个文件,我似乎无法使此功能正确解密。这些字节是用C#中的RC2实现加密的,我为加密和解密过程提供相同的密码和IV(用C#加密,用c ++解密)。
我的所有功能都将返回true,直到最终的“CryptDecrypt”功能。而不是我输入更多,这是功能:
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;
}
input是传递给函数的数据,经过加密。 password与用于加密C#中的数据的密码相同。 size是加密时的数据大小 所有上述函数都返回true,直到CryptDecrypt,我似乎无法弄清楚为什么。同时,我不确定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#中的密钥相同,由PasswordDeriveBytes.CryptDeriveKey创建
答案 0 :(得分:3)
首先,在我的评论中,使用GetLastError(),以便您知道它失败的。我假设你得到NTE_BAD_DATA,所有其他错误都更容易处理,因为它们基本上意味着你错过了API调用序列的一些步骤。
CryptDecrypt使用NTE_BAD_DATA失败的典型原因是您正在解密块密码的最后一个块(就像您一样)并且解密的填充字节不正确。如果输入被截断(并非所有加密字节都保存到文件中)或密钥不正确,则会发生这种情况。
我建议你有条不紊地采用这个方法,因为有很多地方可能会失败,只会在CryptDecrypt时间显现:
答案 1 :(得分:1)
有些人在操作系统之间移动时发现了问题。 CryptDeriveKey调用使用基于所选操作系统和算法的“默认密钥长度”。对于RC2,默认生成的密钥长度在Windows 2000上为40位,在Windows 2003上为128位。当在CryptDecrypt调用中使用生成的密钥时,这将导致“BAD DATA”返回代码。
据推测,这与在尝试应用128位密钥解密40位加密流之后出现在最终缓冲区末尾的“垃圾”有关。错误代码通常表示填充字节错误 - 但根本原因可能是密钥生成问题。
要生成40位加密密钥,请在CryptDeriveKey调用的flags字段中使用((40 <&lt; 16))。