ASP.net rijndael decrypt — длина данных для расшифровки

Многие элементы, которые я нашел до сих пор, были немного расплывчатыми или ... неконкретными, поэтому я надеюсь получить ответ.

У меня есть два маленьких метода - простые, которые выглядят так...

    private const string initVector = "1234567890123456";
    private const string SaltValue = "ThisIsMySaltValue";
    private const int KeySize = 256;

    public static string Encrypt(string textToEncrypt)
    {
        var rijndael = new RijndaelManaged {KeySize = KeySize};
        var salt = SaltValue.ToByteArray();
        var vector = initVector.ToByteArray();

        var rfcBytes = new Rfc2898DeriveBytes(vector, salt, 2);
        var key = rfcBytes.GetBytes(rijndael.KeySize/8);

        ICryptoTransform encrypt = rijndael.CreateEncryptor(key, vector);

        var stream = new MemoryStream();
        var data = Encoding.ASCII.GetBytes(textToEncrypt);
        stream.Write(data, 0, data.Length);

        var cryptoStream = new CryptoStream(stream, encrypt, CryptoStreamMode.Write);
        cryptoStream.Write(data, 0, data.Length);
        cryptoStream.FlushFinalBlock();

        cryptoStream.Close();
        return Convert.ToBase64String(stream.ToArray());
    }


    public static string Decrypt(string textToDecrypt)
    {
        var vector = initVector.ToByteArray();
        var salt = SaltValue.ToByteArray();
        var encrypted = textToDecrypt.ToByteArray();

        var rijndael = new RijndaelManaged {KeySize = KeySize};

        var rfcBytes = new Rfc2898DeriveBytes(vector, salt, 2);
        var key = rfcBytes.GetBytes(rijndael.KeySize/8);

        var decrypt = rijndael.CreateDecryptor(key, vector);

        var stream = new MemoryStream(encrypted);
        var cryptoStream = new CryptoStream(stream, decrypt, CryptoStreamMode.Read);

        byte[] plainBytes = new byte[textToDecrypt.Length];

        var decryptedLength = cryptoStream.Read(plainBytes, 0, plainBytes.Length);

        var plainText = Encoding.UTF8.GetString(plainBytes, 0, decryptedLength);
        return plainText;
    }

Модульный тест выглядит примерно так...

    [Test]
    public void JustTestingThisOut()
    {
        var encryptMe = "SomethingToEncrypt";
        string result = encryptMe.ConvertToEncrypted();
        result.ShouldNotEqual(encryptMe);
        string backToReadAble = result.ConvertToDecrpted();
        backToReadAble.ShouldEqual(encryptMe);
    }

ToByteArray просто возвращает значение Encoding.UTF8.GetBytes(toByte); и моя тестовая строка проста — «SomethingToEncrypt». Я спустился в кроличью нору, найдя эту мысль это могло быть проблемой (Convert.ToBase64String и Convert.FromBase64String), которая, похоже, не имеет никакого значения. Что касается ошибки...

TestCase 'Tests.Encryption.EncryptionUnitTests.JustTestingThisOut' не удалось: System.Security.Cryptography.CryptographicException: недопустимая длина данных для расшифровки. в System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)

У меня есть FlushFinalBlock(), и я ДУМАЛ, что это сработает, но ... нет, это тоже не имеет значения. Любые идеи? Что попробовать?


person jeriley    schedule 04.11.2009    source источник


Ответы (3)


При шифровании вы сначала записываете data в stream, затем заключаете stream в CryptoStream и снова пишете data, на этот раз с шифрованием. Почему? Расшифровка не удалась, потому что первое, с чем она сталкивается, — это незашифрованные данные.

Выведите значение зашифрованного текста до кодирования base64, чтобы убедиться в этом. Вы должны увидеть открытый текст, за которым следует куча абракадабры, которая является зашифрованным текстом.

Кроме того, вы используете вектор инициализации в качестве пароля. Это определенно не одно и то же, и такое использование поставит под угрозу безопасность.

person erickson    schedule 04.11.2009
comment
Я видел это в какой-то момент — ромбовидные вопросительные знаки после текста. Посмотрим, не смогу ли я вернуться к этому. что касается IV - да, я знаю, я просто пытаюсь сначала заставить его работать. Прямо сейчас у меня есть личное значение пароля для тестирования, которое выглядит примерно так... private const string password = AreYouTellingMeThatAThreeOunceBirdCanCarryAOnePoundCoconut?; :-) - person jeriley; 04.11.2009
comment
да, дергая эту одну строку -- stream.Write(data, 0, data.Length); и это работает. Теперь, чтобы подключить самое интересное. - person jeriley; 04.11.2009

Я не могу понять, как это будет работать, как предлагает Джерили, поскольку в функции расшифровки вы делаете

var encrypted = textToDecrypt.ToByteArray();

Здесь textToDecrypt — это строка base64. Сначала вам нужно преобразовать base64 обратно в обычные байты, которые затем можно использовать для расшифровки.

person Henri    schedule 04.11.2009

У вас есть прерывистая ошибка, скрывающаяся в вашем коде...

Вы никогда не должны использовать классы System.Text.Encoding для зашифрованного текста. Вы будете сталкиваться с периодически возникающими ошибками. Вы должны использовать кодировку Base64 и методы класса System.Convert.

  1. Чтобы получить зашифрованную строку из зашифрованного byte[], вы должны использовать:

Convert.ToBase64String(byte[] bytes)

  1. Чтобы получить необработанный byte[] из строки для шифрования, вы должны использовать:

Convert.FromBase64String(string data)

Еще одно замечание: вам нужно будет иметь FlushFinalBlock() при шифровании, иначе оно не будет правильно заполнено.

Дополнительную информацию см. в публикации гуру MS Security Шона Фаннинга по адресу http://blogs.msdn.com/b/shawnfa/archive/2005/11/10/491431.aspx

person Dave Black    schedule 30.12.2011