C# 加密,C++解密。最后几个字节解密失败

发布于 2024-08-08 19:29:16 字数 3456 浏览 7 评论 0原文

对于我即将列出的代码的长度,我深表歉意。

我需要在代码的 C# 端加密 xml 文件的内容,并在 C++ 中解密。我使用的是 RC2,在 C# 端使用 RC2CryptoServiceProviderCryptoStream,在 C++ 端使用 Wincrypt。加密似乎工作正常,看起来像这样:

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();

    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();
}

我的解密代码几乎工作完美。它缺少文件的最后两个字符,而是吐出垃圾字符。我尝试过以空值终止解密的字符串,但没有骰子。如下所示:

char* FileReader::DecryptMyFile(char *input, char *password, int size, int originalSize) 
{
UNREFERENCED_PARAMETER(password);
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
    {
        DWORD check = GetLastError();
        UNREFERENCED_PARAMETER(check);
        printf("Could not acquire context.");
    }
}

HCRYPTKEY key = NULL;
HCRYPTHASH hash = NULL;
if(CryptCreateHash(provider, CALG_MD5, 0, 0, &hash))
{
    printf("empty hash created.");
}

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

HCRYPTHASH duphash = NULL;
CryptDuplicateHash(hash, 0, 0, &duphash);
BYTE *mydata = new BYTE[512];
DWORD mydatasize = 512;
CryptGetHashParam(hash, HP_HASHVAL, mydata, &mydatasize, 0);

BYTE *mydata2 = new BYTE[512]; //these duplicates were made to test my hash.
DWORD mydatasize2 = 512;  
CryptGetHashParam(duphash, HP_HASHVAL, mydata2, &mydatasize2, 0); 

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

DWORD dwKeyLength = 128;
if(CryptSetKeyParam(key, KP_EFFECTIVE_KEYLEN, reinterpret_cast<BYTE*>(&dwKeyLength), 0))
{
    printf("CryptSetKeyParam success");
}

BYTE IV[8] = {0,0,0,0,0,0,0,0};
if(CryptSetKeyParam(key, KP_IV, IV, 0))
{
    printf("CryptSetKeyParam worked");
}

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

memcpy(somebytes, input, dwCount);

if(CryptDecrypt(key,0, true, 0, somebytes, &dwCount))
{
    printf("CryptDecrypt succeeded.");
}
else
{
    if(GetLastError() == NTE_BAD_DATA)
    {
        printf("NTE_BAD_DATA");
    }
    printf("CryptDecrypt failed.");
    DWORD testest = NULL;
    testest = GetLastError();
    testest = 3;
}
somebytes[originalSize] = '\0';

    return (char *)somebytes;
}

生成的 xml 文件应以 结尾。目前,它以 结尾,

为什么会这样?我怎样才能阻止这个?我对为什么会发生这种情况感到非常困惑。由于我对解密进行了空终止,并且仍然仅在最终字符上遇到问题,因此我不认为解密是问题所在(尽管我希望是错误的)。是否有可能我的加密在完成文件加密时遇到了麻烦?

从 CryptDecrypt 返回后,dwCount 等于 size,即 11296。同时,originalSize 等于 11290。

My apologies for the length of the code I'm about to list.

I need to encrypt the contents of an xml file on the C# end of my code, and decrypt it in C++. I'm using RC2, with RC2CryptoServiceProvider and CryptoStream on the C# side, with Wincrypt on the C++ side. Encryption seems to be working fine, it looks like such:

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();

    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();
}

MY decryption code almost works perfectly. It is missing the final two characters of the file, and instead spitting out garbage characters. I have tried null-terminating the decrypted string, but no dice. It is as follows:

char* FileReader::DecryptMyFile(char *input, char *password, int size, int originalSize) 
{
UNREFERENCED_PARAMETER(password);
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
    {
        DWORD check = GetLastError();
        UNREFERENCED_PARAMETER(check);
        printf("Could not acquire context.");
    }
}

HCRYPTKEY key = NULL;
HCRYPTHASH hash = NULL;
if(CryptCreateHash(provider, CALG_MD5, 0, 0, &hash))
{
    printf("empty hash created.");
}

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

HCRYPTHASH duphash = NULL;
CryptDuplicateHash(hash, 0, 0, &duphash);
BYTE *mydata = new BYTE[512];
DWORD mydatasize = 512;
CryptGetHashParam(hash, HP_HASHVAL, mydata, &mydatasize, 0);

BYTE *mydata2 = new BYTE[512]; //these duplicates were made to test my hash.
DWORD mydatasize2 = 512;  
CryptGetHashParam(duphash, HP_HASHVAL, mydata2, &mydatasize2, 0); 

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

DWORD dwKeyLength = 128;
if(CryptSetKeyParam(key, KP_EFFECTIVE_KEYLEN, reinterpret_cast<BYTE*>(&dwKeyLength), 0))
{
    printf("CryptSetKeyParam success");
}

BYTE IV[8] = {0,0,0,0,0,0,0,0};
if(CryptSetKeyParam(key, KP_IV, IV, 0))
{
    printf("CryptSetKeyParam worked");
}

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

memcpy(somebytes, input, dwCount);

if(CryptDecrypt(key,0, true, 0, somebytes, &dwCount))
{
    printf("CryptDecrypt succeeded.");
}
else
{
    if(GetLastError() == NTE_BAD_DATA)
    {
        printf("NTE_BAD_DATA");
    }
    printf("CryptDecrypt failed.");
    DWORD testest = NULL;
    testest = GetLastError();
    testest = 3;
}
somebytes[originalSize] = '\0';

    return (char *)somebytes;
}

The resulting xml file should end with </LudoData>. Currently, it ends with </LudoDat[funny looking s]b

Why might this be? How can I stop this? I'm terribly confused as to why this is occurring. Since I am null-terminating the decryption and still getting a problem only on the final characters, I don't believe that the decryption is the problem (although I would love to be wrong). Is it possible that my encryption is having troubles when finishing the encryption of the file?

Upon returning from CryptDecrypt, dwCount is equal to size, which is 11296. Meanwhile, originalSize is equal to 11290.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

安静 2024-08-15 19:29:16

这一行是您的问题(在调用 CryptDecrypt 之前):

somebytes[originalSize - 1] = '\0';

它用零覆盖最后一个块中的加密填充部分,这导致最后一个块解密为垃圾。只需删除该行 - 密文无论如何都不是以 nul 结尾的(它几乎肯定包含大量嵌入的 nul),解密例程使用长度参数来了解有多少数据。

哦,还有……RC2?严重地?

This line is your problem (before the call to CryptDecrypt):

somebytes[originalSize - 1] = '\0';

It is overwriting part of the encrypted padding in the last block with a zero, which is causing the last block to decrypt to rubbish. Just remove the line - the ciphertext isn't nul-terminated anyway (it almost certainly contains plenty of embedded nuls), the length parameter is used by the decryption routine to know how much data there is.

Oh, and... RC2? Seriously?

花开柳相依 2024-08-15 19:29:16

您不应该只执行以下操作吗

DWORD dwCount = size;
BYTE *somebytes = new BYTE[dwCount];

memcpy(somebytes, input, dwCount);

在调用 CryptDecrypt 之前, ?当 CryptDecrypt 已将字节数作为最终参数时,为什么需要添加空字符?我怀疑这就是破坏事物的原因,因为您通过破坏位置 originalSize - 1 处的字符来更改输入。

编辑:

originalSizesize 哪个更大?由于 CryptDecrypt 重复使用该数组,因此必须使用两者中较大的一个来确定其尺寸。顺便说一句,你为什么认为你需要额外的维度?

Shouldn't you be doing just the following

DWORD dwCount = size;
BYTE *somebytes = new BYTE[dwCount];

memcpy(somebytes, input, dwCount);

before calling CryptDecrypt? Why do you need to add a null character when CryptDecrypt already takes the number of bytes as it's final argument? I suspect that's what's breaking things as you've changed the input by clobbering the character at position originalSize - 1.

Edit:

Which is bigger, originalSize or size? Since CryptDecrypt re-uses the array it must be dimensioned with the bigger of the two. BTW, why do you think you need the extra one in the dimension?

听风吹 2024-08-15 19:29:16

完成写入 CryptoStream 后,您需要刷新 FileStream,然后 finalflush CryptoStream。之后,首先关闭 CryptoStream,最后关闭 FileStream。如果不这样做,无论是来自 MemoryStream/FileStream 的所有原始字节都可能无法写入,从而导致字节丢失。如果完成后 FileStream.Position 不等于 FileStream.Length,则 FileStream.Length-FileStream.Position = 缺失字节。因此,现在当您尝试获取解密的数据时(上帝禁止序列化,在这种情况下这对您来说将失败),您将无法取回所有数据。

after you finish writing to the CryptoStream you need to flush FileStream then finalflush the CryptoStream. After that close the CryptoStream first and the FileStream last. If you don't, all the original bytes whether from a MemoryStream/FileStream may not get written causing missing bytes. If the FileStream.Position does not equal FileStream.Length when you are done then FileStream.Length-FileStream.Position = missing bytes. So now when you try to get the decrypted data (Lord forbid by Serialization which will fail on you in that case), you will not get all the data back.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文