C # шифрование, C ++ дешифрование. Последние несколько байтов не удалось расшифровать - PullRequest
1 голос
/ 26 октября 2009

Мои извинения за длину кода, который я собираюсь перечислить.

Мне нужно зашифровать содержимое xml-файла в конце C # моего кода и расшифровать его на C ++. Я использую RC2, с RC2CryptoServiceProvider и CryptoStream на стороне C #, с Wincrypt на стороне 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();

    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-файл должен заканчиваться </LudoData>. В настоящее время он заканчивается на </LudoDat[funny looking s]b

Почему это может быть? Как я могу это остановить? Я ужасно смущен тем, почему это происходит. Так как я заканчиваю дешифрование нулем и все еще получаю проблему только с последними символами, я не верю, что проблема в дешифровании (хотя я бы хотел ошибиться). Возможно ли, что у моего шифрования возникают проблемы при завершении шифрования файла?

После возврата из CryptDecrypt dwCount равен размеру, равному 11296. Между тем, originalSize равен 11290.

Ответы [ 3 ]

3 голосов
/ 27 октября 2009

Эта линия - ваша проблема (до вызова CryptDecrypt):

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

Он перезаписывает часть зашифрованного заполнения в последнем блоке нулем, в результате чего последний блок расшифровывается как мусор. Просто удалите строку - зашифрованный текст в любом случае не обнуляется (он почти наверняка содержит много встроенных nuls), параметр длины используется подпрограммой дешифрования, чтобы узнать, сколько там данных.

О, и ... RC2? Серьезно?

1 голос
/ 26 октября 2009

Разве вы не должны делать только следующее

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

memcpy(somebytes, input, dwCount);

перед звонком CryptDecrypt? Зачем вам нужно добавлять нулевой символ, когда CryptDecrypt уже принимает число байтов в качестве окончательного аргумента? Я подозреваю, что это то, что ломает вещи, когда вы изменили ввод, забив символ в позиции originalSize - 1.

Edit:

Что больше, originalSize или size? Поскольку CryptDecrypt повторно использует массив, он должен быть измерен с большим из двух. Кстати, почему вы думаете, что вам нужен дополнительный в измерении?

0 голосов
/ 23 февраля 2011

после того, как вы закончите запись в CryptoStream, вам нужно сбросить FileStream, затем finalflush CryptoStream. После этого закройте сначала CryptoStream, а затем FileStream. Если вы этого не сделаете, все оригинальные байты из MemoryStream / FileStream могут не записаться, что приведет к отсутствию байтов. Если FileStream.Position не равно FileStream.Length, когда вы закончите, то FileStream.Length-FileStream.Position = missing bytes. Так что теперь, когда вы пытаетесь получить расшифрованные данные (не дай Бог сериализацией, которая в таком случае не получится), вы не получите все данные обратно.

...