Иногда ошибка неверных данных при расшифровке строки: System.Security.Cryptography.CryptographicException - PullRequest
4 голосов
/ 02 июля 2011

В моем приложении ASP.NET WebForms (приложение работает на Windows Server 2008 R2, IIS 7.5 и Runtime v4.0 в интегрированном режиме, если это имеет значение) , I Я шифрую данные, помещаю их в QueryString и дешифрую, используя класс System.Security.Cryptography.SymmetricAlgorithm. Но у меня иногда возникают проблемы с расшифровкой данных, которые я получаю в следующем исключении:

Плохие данные.

Описание: необработанное исключение произошло во время исполнения текущий веб-запрос. Пожалуйста, просмотрите трассировка стека для получения дополнительной информации о ошибка и откуда она возникла код.

Сведения об исключении: System.Security.Cryptography.CryptographicException: Неверные данные.

Ошибка источника:

Создано необработанное исключение во время исполнения текущего веб-запрос. Информация относительно Происхождение и место исключения можно определить с помощью исключения трассировка стека ниже.

Трассировка стека:

[CryptographicException: неверные данные. ]
System.Security.Cryptography.CryptographicException.ThrowCryptographicException (Int32 ч) + 33
System.Security.Cryptography.Utils._DecryptData (SafeKeyHandle данные hKey, Byte [], Int32 ib, Int32 cb, Byte [] & outputBuffer, Int32 outputOffset, PaddingMode PaddingMode, Boolean fDone) + 0
System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock (байт [] inputBuffer, Int32 inputOffset, Int32 inputCount) + 313
System.Security.Cryptography.CryptoStream.FlushFinalBlock () +33 Криптография35.SymmetricEncryptionUtility.DecryptData (Byte [] data, String keyFile) в E: \ Documents \ @Library \ Cryptography35 \ Cryptography35 \ SymmetricEncryptionUtility.cs: 124 Cryptography35.SymmetricQueryString.SymmetriclyEncryptedQueryString..ctor (String encryptedData, String keyfilename, Строковое имя алгоритма) в E: \ Documents \ @Library \ Cryptography35 \ Cryptography35 \ SymmetricQueryString \ SymmetriclyEncryptedQueryString.cs: 67 WebForms.Web.Views.purchase_a.GetSymmetriclyEncryptedQueryString () в E: \ Documents \ WebForms.Web \ Views \ покупного a.aspx.cs: 35 WebForms.Web.Views.purchase_a.Page_Load (Объект отправитель, EventArgs e) в E: \ Documents \ WebForms.Web \ Views \ покупного a.aspx.cs: 56 System.Web.Util.CalliHelper.EventArgFunctionCaller (IntPtr fp, объект o, объект t, EventArgs e) +14 System.Web.Util.CalliEventHandlerDelegateProxy.Callback (Object отправитель, EventArgs e) + 35
System.Web.UI.Control.OnLoad (EventArgs д) + 91
System.Web.UI.Control.LoadRecursive () +74 System.Web.UI.Page.ProcessRequestMain (Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207 Информация о версии: Microsoft .NET Framework Версия: 4.0.30319; ASP.NET версия: 4.0.30319.1

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

private SymmetriclyEncryptedQueryString GetSymmetriclyEncryptedQueryString() {

    #region _decrypting the value

    string KeyFileName;
    string AlgorithmName = "DES";

    Cryptography35.SymmetricEncryptionUtility.AlgorithmName = AlgorithmName;
    KeyFileName = HttpContext.Current.Server.MapPath("~/@config/") + "\\symmetric_key.config";

    #endregion

    #region _reading and assigning the value

    if (Request.QueryString["q"] == null)
        throw new NullReferenceException("QueryString value is null on search result page");

    SymmetriclyEncryptedQueryString QueryString = new SymmetriclyEncryptedQueryString(Request.QueryString["q"], KeyFileName, AlgorithmName);

    #endregion

    return QueryString;
}

SymmetriclyEncryptedQueryString Класс

public class SymmetriclyEncryptedQueryString : System.Collections.Specialized.StringDictionary {

        public string KeyFileName { get; set; }
        public string AlgorithmName { get; set; }

        /// <summary>
        /// Use this for encrypte the value
        /// </summary>
        /// <param name="keyfilename"></param>
        /// <param name="algorithmname"></param>
        public SymmetriclyEncryptedQueryString(string keyfilename, string algorithmname) {

            KeyFileName = keyfilename;
            AlgorithmName = algorithmname;

        }

        /// <summary>
        /// Use this for decrypte the value.
        /// </summary>
        /// <param name="encryptedData"></param>
        /// <param name="keyfilename"></param>
        /// <param name="algorithmname"></param>
        public SymmetriclyEncryptedQueryString(string encryptedData, string keyfilename, string algorithmname) {

            #region _initials

            KeyFileName = keyfilename;
            AlgorithmName = algorithmname;

            if (String.IsNullOrEmpty(AlgorithmName)){
                SymmetricEncryptionUtility.AlgorithmName = AlgorithmName;
            }
            else{
                SymmetricEncryptionUtility.AlgorithmName = "DES";
            }

            SymmetricEncryptionUtility.ProtectKey = false;

            // Check for encryption key
            if (!File.Exists(KeyFileName)){
                throw new FileNotFoundException("Keyfilename for  SymmetriclyEncryptedQueryString is not found on '" + KeyFileName + "'!");
            }

            #endregion

            //Arrange the data
            //In order not to get following exception
            //Invalid length for a Base-64 char array.
            //byte[] RawData = Convert.FromBase64String(encryptedData);
            encryptedData = encryptedData.Replace(" ", "+");
            int mod4 = encryptedData.Length % 4;
            if (mod4 > 0)
                encryptedData += new string('=', 4 - mod4);

            // Decrypt data passed in
            byte[] RawData = Convert.FromBase64String(encryptedData);
            string DecryptedVal = SymmetricEncryptionUtility.DecryptData(RawData, KeyFileName);
            string StringData = DecryptedVal;

            // Split the data and add the contents
            int Index;
            string[] SplittedData = StringData.Split(new char[] { '&' });
            foreach (string SingleData in SplittedData) {

                Index = SingleData.IndexOf('=');
                base.Add(
                    HttpUtility.UrlDecode(SingleData.Substring(0, Index)),
                    HttpUtility.UrlDecode(SingleData.Substring(Index + 1))
                );

            }
        }

        public override string ToString() {

            #region _initials

            if (String.IsNullOrEmpty(AlgorithmName)) {
                SymmetricEncryptionUtility.AlgorithmName = AlgorithmName;
            } else {
                SymmetricEncryptionUtility.AlgorithmName = "DES";
            }

            SymmetricEncryptionUtility.ProtectKey = false;

            // Check for encryption key
            if (!File.Exists(KeyFileName)) {
                throw new FileNotFoundException("Keyfilename for AsymmetriclyEncryptedQueryString is not found on '" + KeyFileName + "'!");
            }

            #endregion

            #region _prepare for querystring

            // Go through the contents and build a 
            // typical query string
            StringBuilder Content = new StringBuilder();

            foreach (string key in base.Keys) {

                Content.Append(HttpUtility.UrlEncode(key));
                Content.Append("=");
                Content.Append(HttpUtility.UrlEncode(base[key]));
                Content.Append("&");

            }

            // Remove the last '&'
            Content.Remove(Content.Length - 1, 1);


            #endregion

            #region _encrypt the contents

            // Now encrypt the contents
            byte[] data = SymmetricEncryptionUtility.EncryptData(Content.ToString(), KeyFileName);
            string EncryptedVal = Convert.ToBase64String(data);

            #endregion

            return EncryptedVal;

        }

    }

SymmetricEncryptionUtility Класс

public static class SymmetricEncryptionUtility {

    private static bool _ProtectKey;
    private static string _AlgorithmName;

    // Shhh!!! Don't tell anybody!
    private const string MyKey = "m$%&kljasldk$%/65asjdl";

    public static string AlgorithmName {

        get { return _AlgorithmName; }
        set { _AlgorithmName = value; }
    }

    public static bool ProtectKey {

        get { return _ProtectKey; }
        set { _ProtectKey = value; }
    }

    public static void GenerateKey(string targetFile) {

        // Create the algorithm
        SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
        Algorithm.GenerateKey();

        // No get the key
        byte[] Key = Algorithm.Key;

        if (ProtectKey)
        {
            // Use DPAPI to encrypt key
            Key = ProtectedData.Protect(
                Key, null, DataProtectionScope.LocalMachine);
        }

        // Store the key in a file called key.config
        using (FileStream fs = new FileStream(targetFile, FileMode.Create))
        {
            fs.Write(Key, 0, Key.Length);
        }
    }

    public static void ReadKey(SymmetricAlgorithm algorithm, string keyFile)
    {
        byte[] Key;

        using (FileStream fs = new FileStream(keyFile, FileMode.Open))
        {
            Key = new byte[fs.Length];
            fs.Read(Key, 0, (int)fs.Length);
        }

        if (ProtectKey)
            algorithm.Key = ProtectedData.Unprotect(Key, null, DataProtectionScope.LocalMachine);
        else
            algorithm.Key = Key;
    }

    public static byte[] EncryptData(string data, string keyFile)
    {
        // Convert string data to byte array
        byte[] ClearData = Encoding.UTF8.GetBytes(data);

        // Now Create the algorithm
        SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
        ReadKey(Algorithm, keyFile);

        // Encrypt information
        MemoryStream Target = new MemoryStream();

        // Append IV
        Algorithm.GenerateIV();
        Target.Write(Algorithm.IV, 0, Algorithm.IV.Length);

        // Encrypt actual data
        CryptoStream cs = new CryptoStream(Target, Algorithm.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(ClearData, 0, ClearData.Length);
        cs.FlushFinalBlock();

        // Output the bytes of the encrypted array to the textbox
        return Target.ToArray();
    }

    public static string DecryptData(byte[] data, string keyFile) {

        // Now create the algorithm
        SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
        ReadKey(Algorithm, keyFile);

        // Decrypt information
        MemoryStream Target = new MemoryStream();

        // Read IV
        int ReadPos = 0;
        byte[] IV = new byte[Algorithm.IV.Length];
        Array.Copy(data, IV, IV.Length);
        Algorithm.IV = IV;
        ReadPos += Algorithm.IV.Length;

        CryptoStream cs = new CryptoStream(Target, Algorithm.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(data, ReadPos, data.Length - ReadPos);
        cs.FlushFinalBlock();

        // Get the bytes from the memory stream and convert them to text
        return Encoding.UTF8.GetString(Target.ToArray());
    }

}

UPDATE Я понял что-то еще. На одной из моих страниц я делаю следующее:

protected override void OnInit(EventArgs e) {

    string url = Request.Url.AbsoluteUri.ToLower();
    if (url.StartsWith("http:"))
    {
        Response.Redirect(url.Replace("http://", "https://"), true);
    }
}

Я понял, что это вызывает проблему. (Помните, что мои зашифрованные данные находятся внутри строки запроса), когда я пытаюсь перейти на эту страницу с http, и она перенаправляет ее на https и boom. это дает мне эту ошибку. Хорошо, теперь я нашел источник ошибки, но это все равно не должно происходить.

Ответы [ 3 ]

3 голосов
/ 30 декабря 2011

В вашем коде скрывается ошибка ...

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

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

  2. Чтобы получить необработанный байт [] из строки для шифрования, вы должны использовать: Convert.FromBase64String(string data)

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

0 голосов
/ 12 ноября 2012

У меня была другая основная причина, из-за ошибки "Плохие данные", и это было связано с отсутствием кода "FlushFinalBlock".Это, очевидно, вызвало проблему, так как я никогда не сохранял полностью зашифрованное значение.Теперь в приведенном выше примере кода включено , но, очевидно, оно скрыто в коде.Я надеюсь, что это не слишком не по теме, но я нашел этот пост в Google довольно быстро, поэтому я предполагаю, что другие могут прийти сюда и совершить ту же самую простую ошибку.

Также стоит упомянуть, что ответ @Dave Black, похоже, не относится к окончательному коду, опубликованному выше ...?Я правильно прочитал код выше?Это может быть результатом изменений во времени - но это немного вводит меня в заблуждение, когда я пытаюсь разобраться, что пошло не так (я правильно сохранил зашифрованные данные, но не все :-()

0 голосов
/ 04 июля 2011

Установить режим шифрования и дешифрования на ECB.
Как говорят в Россуме: «ЕЦБ небезопасен, он пропускает информацию», поэтому, если вам нужен произвольный доступ к вашему файлу, используйте CTR.

...