Rijndael: та же строка, разные результаты

У нас было небольшое настольное приложение, которое теперь необходимо предоставить в виде веб-функции (.Net). Это приложение содержит некоторый код для шифрования и использует классы Rijndael из .Net framework. Код принимает входную строку, шифрует ее и записывает результаты в файл. Поскольку весь код содержится в одном классе, я просто скопировал этот класс в свое приложение веб-службы. Когда я шифрую одну и ту же строку с помощью одного и того же ключа в исходном и новом приложении, результаты будут разными. Строка результата, предоставленная исходным приложением, является подмножеством строки результата, предоставленной моей веб-службой. Последний имеет дополнительные символы в конце зашифрованной строки.

Ниже приведен код, который я использую. Обратите внимание, что я не разрабатывал этот код и не понимаю его полностью. Есть мысли о разнице в поведении? Пожалуйста помоги!!

Вот код, который получает пользовательский ввод и вызывает шифровальщик.

    public void EncryptDomain(string EncryptValue, string outputDomainFile)
    {
            if (EncryptValue.Length > 0)
            {
                if ((outputDomainFile != null) && (outputDomainFile.Length > 0))
                {
                    _outputDomainFile = outputDomainFile;
                }

                byte[] input = Encoding.UTF8.GetBytes(EncryptValue);

                Transform(input, TransformType.ENCRYPT);

            }

Это код шифровальщика:

    private byte[] Transform(byte[] input, TransformType transformType)
    {
        CryptoStream cryptoStream = null;      // Stream used to encrypt
        RijndaelManaged rijndael = null;        // Rijndael provider
        ICryptoTransform rijndaelTransform = null;// Encrypting object            
        FileStream fsIn = null;                 //input file
        FileStream fsOut = null;                //output file
        MemoryStream memStream = null;          // Stream to contain data
        try
        {
            // Create the crypto objects
            rijndael = new RijndaelManaged();
            rijndael.Key = this._Key;
            rijndael.IV = this._IV;
            rijndael.Padding = PaddingMode.Zeros;   

            if (transformType == TransformType.ENCRYPT)
            {
                rijndaelTransform = rijndael.CreateEncryptor();
            }
            else
            {
                rijndaelTransform = rijndael.CreateDecryptor();
            }

            if ((input != null) && (input.Length > 0))
            {
                //memStream = new MemoryStream();
                //string outputDomainFile = 
                FileStream fsOutDomain = new FileStream(_outputDomainFile,
                                            FileMode.OpenOrCreate, FileAccess.Write);

                cryptoStream = new CryptoStream(
                     fsOutDomain, rijndaelTransform, CryptoStreamMode.Write);

                cryptoStream.Write(input, 0, input.Length);

                cryptoStream.FlushFinalBlock();

                //return memStream.ToArray();
                return null;
            }
            return null;

        }
        catch (CryptographicException)
        {
            throw new CryptographicException("Password is invalid. Please verify once again.");
        }
        finally
        {
            if (rijndael != null) rijndael.Clear();
            if (rijndaelTransform != null) rijndaelTransform.Dispose();
            if (cryptoStream != null) cryptoStream.Close();
            if (memStream != null) memStream.Close();
            if (fsOut != null) fsOut.Close();
            if (fsIn != null) fsIn.Close();
        }
 }

Код, который устанавливает значения IV:

    private void GenerateKey(string SecretPhrase)
    {
        // Initialize internal values
        this._Key = new byte[24];
        this._IV = new byte[16];

        // Perform a hash operation using the phrase.  This will 
        // generate a unique 32 character value to be used as the key.
        byte[] bytePhrase = Encoding.ASCII.GetBytes(SecretPhrase);
        SHA384Managed sha384 = new SHA384Managed();
        sha384.ComputeHash(bytePhrase);
        byte[] result = sha384.Hash;

        // Transfer the first 24 characters of the hashed value to the key
        // and the remaining 8 characters to the intialization vector.
        for (int loop = 0; loop < 24; loop++) this._Key[loop] = result[loop];
        for (int loop = 24; loop < 40; loop++) this._IV[loop - 24] = result[loop];
    }

person Apeksha    schedule 04.08.2011    source источник
comment
Код принимает входную строку — код, который вы включили до сих пор, принимает входной массив байтов. Покажите нам код, который переходит от строки к массиву байтов.   -  person AakashM    schedule 04.08.2011
comment
Может быть, на обоих компьютерах разные локали?   -  person TJHeuvel    schedule 04.08.2011
comment
Строка, зашифрованная исходным приложением, является подмножеством строки, зашифрованной моей веб-службой. Последний имеет дополнительные символы в конце зашифрованной строки. Так это разные струны? Но вы сказали, что это одна и та же строка. Просьба уточнить.   -  person Joe White    schedule 04.08.2011
comment
Почему вы используете ASCII.GetBytes вместо варианта, поддерживающего юникод, например Utf8.GetBytes? И я настоятельно рекомендую использовать медленный хеш, т.е. хорошую функцию вывода ключей. Я предпочитаю PBKDF2, который предлагается классом Rfc2898DeriveBytes в .net.   -  person CodesInChaos    schedule 04.08.2011
comment
@CodeInChaos - Почему, я не знаю. Как я уже говорил, это устаревший код. Спасибо за предложение, попробую UTF8.GetBytes. Я не уверен, где и как мне использовать PBKDF2. Я не очень знаком с этими методами. Не могли бы вы указать мне некоторые ресурсы?   -  person Apeksha    schedule 05.08.2011
comment
@aakashm - Мой плохой! Я также добавил этот код   -  person Apeksha    schedule 05.08.2011
comment
@tjheuvel - На данный момент они оба на одном компьютере   -  person Apeksha    schedule 05.08.2011
comment
@Joe - Извините, я имел в виду зашифрованное значение. :(   -  person Apeksha    schedule 05.08.2011
comment
Статья в Википедии о Key-Derivation-Functions является хорошим введением. Он в основном заменяет вызовы SHA384, которые у вас есть. Смысл этого в том, чтобы сделать хеширование медленным, что не сильно повредит серверу, но повредит взломщику.   -  person CodesInChaos    schedule 05.08.2011
comment
Также я думаю, что вы неправильно используете IV. Он должен быть случайным и храниться вместе (например, в начале) с зашифрованным текстом. Его эффект заключается в том, что если вы дважды зашифруете одни и те же данные, зашифрованный текст будет выглядеть совершенно по-другому.   -  person CodesInChaos    schedule 05.08.2011
comment
@CodeInChaos На самом деле, на данный момент я хочу, чтобы при двойном шифровании одних и тех же данных зашифрованный текст был точно таким же.   -  person Apeksha    schedule 05.08.2011


Ответы (2)


Я предполагаю, что это из-за IV (вектор инициализации)

person DaveShaw    schedule 04.08.2011
comment
В продолжение того, что написал ДэйвШоу, как устанавливается this._IV? Если вы каждый раз не используете один и тот же вектор Initialisatio, вы получите разные результаты, даже если ключ и строка совпадают. - person Tim; 04.08.2011
comment
@Tim - я добавил код, который устанавливает значение IV. Поскольку SecretPhrase одинакова в обоих случаях, я ожидаю, что значения IV будут одинаковыми. Могут ли они как-то отличаться? - person Apeksha; 05.08.2011
comment
@tim - я убедился, что _IV имеет одинаковое значение в обоих случаях. Спасибо за предложение. - person Apeksha; 05.08.2011

Это классическая ошибка. Создаете ли вы IV самостоятельно или нет, Rijndael (AES) предоставит его вам. Хитрость заключается в том, чтобы всегда сохранять IV (на RijndaelManaged есть геттер).

  • При расшифровке вам необходимо передать и ключ и IV.

Если вы сохраняете данные в файл или базу данных, вы можете сохранить IV как обычный текст. Вы даже можете передать IV по проводу (сеть, Интернет) в виде простого текста. Злоумышленник не сможет (насколько мне известно) взломать ваш шифр, основываясь только на IV. Передача или сохранение IV обычно выполняется путем добавления префикса перед зашифрованным текстом или добавления его в конце. (объединение двух строк)

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

Таким образом, если ваш ключ — ABCDEFABCDEFABCD, а ваш IV — ABCDEF0123456789, а этот открытый текст: 'это какой-то секретный текст' (скажем) создает шифр, такой как: abcd1234abcd00

Вы бы передавали (или сохраняли) вот так: ABCDEF0123456789abcd1234abcd00

person ra170    schedule 31.10.2011