Неконтролируемое поведение с управляемым шифрованием Rijndael

У меня странная проблема с RijndaelManaged. В основном у меня есть новый экземпляр, где я настроил CipherMode, Padding, IV и Key. Затем я создаю другой экземпляр и назначаю второму экземпляру те же значения следующих свойств из исходного экземпляра: Mode, Padding, KeySize, FeedbackSize, BlockSize, IV и Key.

Итак, скопировав ВСЕ значения свойств из экземпляра 1 в экземпляр 2, я должен получить те же результаты, верно? НЕПРАВИЛЬНЫЙ! GetHashCode () обоих экземпляров как-то различается, но если я сброшу их свойства (указанные выше), то все они будут одинаковыми.

Если я зашифрую строку текста длиной, равной размеру блока (16 байт, 128 бит), то оба будут давать один и тот же результат, если ввод меньше BlockSize, тогда результаты шифрования НЕ совпадают.

У меня есть это, чтобы создать начальный экземпляр Rijndael.

    public static RijndaelManaged CreateSymmetricKey(string passphrase)
    {
        RijndaelManaged symCrypto = new RijndaelManaged();
        symCrypto.Mode = CipherMode.CBC;               
        symCrypto.Padding = PaddingMode.PKCS7;
        byte[] salt = Encoding.UTF8.GetBytes("dummy dummy dummy dummy test");
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passphrase, salt);
        symCrypto.Key = key.GetBytes(symCrypto.KeySize / 8);
        symCrypto.IV = key.GetBytes(symCrypto.BlockSize / 8);

        return symCrypto;
    }

Чтобы зашифровать строку для примера:

private string Encrypt(RijndaelManaged rm, string text)
    {
        byte[] encrypted;
        // Create a decrytor to perform the stream transform.
            ICryptoTransform encryptor = rm.CreateEncryptor(rm.Key, rm.IV);
        using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(text);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        return BitConverter.ToString(encrypted);
    }

Итак, сделайте это

RijndaelManaged rm1 = CreateSymmetricKey("there is something weird happening");
RijndaelManaged rm2 = new RijndaelManaged();
// copy ALL public properties to the new instance so that it has the same parameters
rm2.BlockSize = rm1.BlockSize; // 128
rm2.FeedbackSize = rm1.FeedbackSize; // 128
rm2.KeySize = rm1.KeySize; // 256
rm2.Mode = rm1.Mode; // CBC
rm2.Padding = rm1.Padding; // PKCS7
rm2.IV = rm1.IV;
rm2.Key = rm1.Key;
// Encryption
string cypher1 = Encrypt(rm1, "this is a test 6");  // length equal to BlockSize
string cypher2 = Encrypt(rm2, "this is a test 6");  // length equal to BlockSize
string cypher11 = Encrypt(rm1, "this is a test");  // length less than BlockSize
string cypher21 = Encrypt(rm2, "this is a test");  // length less than BlockSize

Я получаю cyper1 == cypher2 и cypher11! = Cypher21 также rm1.GetHashCode ()! = Rm2.GetHashCode (), но все общедоступные параметры одинаковы!

Я также сбросил все общедоступные свойства обоих экземпляров, чтобы увидеть, не упустил ли я что-то, но нет, все значения одинаковы.


person Lord of Scripts    schedule 09.02.2012    source источник
comment
blogs.msdn. ru / b / ericlippert / archive / 2011/02/28 /   -  person Austin Salonen    schedule 10.02.2012
comment
Я не уверен, что это решение, но вы можете вызвать FlushFinalBlock в потоке перед преобразованием в массив. Я, кажется, припоминаю, что без этого ничего не получалось.   -  person 500 - Internal Server Error    schedule 10.02.2012
comment
Я не могу воссоздать cyper11 != cyperh21. Основываясь на моем предыдущем комментарии, я бы не ожидал, что хэш-коды будут совпадать.   -  person Austin Salonen    schedule 10.02.2012
comment
+1 за предоставление всего необходимого кода.   -  person Austin Salonen    schedule 10.02.2012
comment
Я скопировал ваш код, запустил его и получил те же результаты, что и @AustinSalonen. cypher1 == cypher2 и cypher11 == cypher21.   -  person President James K. Polk    schedule 10.02.2012
comment
Привет, Владыка скриптов, не могли бы вы рассказать о прогрессе в этом вопросе?   -  person Maarten Bodewes    schedule 14.02.2012


Ответы (1)


Вы не должны использовать GetHashCode() таким образом. Для классов, которые не переопределяли базовую реализацию object.GetHashCode(), он вернет целочисленный обработчик этого конкретного экземпляра.
Поскольку дескриптор для двух разных экземпляров всегда будет отличаться, он никогда не будет совпадать.

Кроме того, GetHashCode() на самом деле никогда не гарантирует уникальность, он просто предназначен для использования в качестве легкой предварительной проверки перед проверкой фактического равенства.
Это широко используется в любой структуре данных хеширования, такой как словарь и т. Д.

Для получения дополнительной информации по этой теме:
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

Я также выполнил ваш код, и для меня это было следующим образом:

cyper1 == cypher2 and cypher11 == cypher21

Я почти уверен, что проблема заключалась в сравнении GetHashCode().

person ntziolis    schedule 16.03.2012