5

在我的 ASP.NET WebForms 应用程序中(该应用程序在 windows server 2008 R2、IIS 7.5 和 Runtime v4.0 集成模式应用程序池上运行),我正在加密数据,将其放在 QueryString 上并使用System.Security.Cryptography.SymmetricAlgorithm类解密数据。但是我偶尔会在解密数据时遇到一些问题,我得到以下异常;

不良数据。

说明:执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

异常详细信息:System.Security.Cryptography.CryptographicException:错误数据。

源错误:

在执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪来识别有关异常起源和位置的信息。

堆栈跟踪:

[加密异常:错误数据。]
System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +33
System.Security.Cryptography.Utils._DecryptData(SafeKeyHandle hKey, Byte[] data, Int32 ib, Int32 cb, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode PaddingMode, Boolean fDone) +0
System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) +313
System.Security.Cryptography.CryptoStream.FlushFinalBlock() +33 Cryptography35.SymmetricEncryptionUtility.DecryptData(Byte[] data, String keyFile) 在 E:\Documents\@Library\Cryptography35\Cryptography35\SymmetricEncryptionUtility.cs:124 Cryptography35.SymmetricQueryString.SymmetriclyEncryptedQueryString ..ctor(String encryptedData, String keyfilename, String algorithmname) 在 E:\Documents\@Library\Cryptography35\Cryptography35\SymmetricQueryString\SymmetriclyEncryptedQueryString.cs:67 WebForms.Web.Views.purchase_a.GetSymmetriclyEncryptedQueryString() 在 E:\Documents\ WebForms.Web\Views\purchase-a.aspx.cs:35 WebForms.Web.Views.purchase_a.Page_Load(Object sender, EventArgs e) 在 E:\Documents\WebForms.Web\Views\purchase-a.aspx.cs :56 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,对象 o,对象 t,EventArgs e) +14 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
System.Web.UI.Control.OnLoad(EventArgs e) +91
System.Web.UI.Control.LoadRecursive() +74 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207 版本信息:微软.NET 框架版本: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());
    }

}

更新 我想出了别的东西。在我的一个页面上,我正在做以下事情;

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并繁荣。它给了我那个错误。好的,现在我找到了错误的根源,但无论如何都不应该发生。

4

3 回答 3

3

您的代码中潜伏着一个错误...

您永远不应该将任何 System.Text.Encoding 类用于密文。您遇到间歇性错误。您应该使用 Base64 编码和 System.Convert 类方法。

  1. 要从加密的 byte[] 中获取加密的字符串,您应该使用:Convert.ToBase64String(byte[] bytes)

  2. 要从要加密的字符串中获取原始字节 [],您应该使用:Convert.FromBase64String(string data)

有关更多信息,请参阅 MS 安全专家 Shawn Farkas 在http://blogs.msdn.com/b/shawnfa/archive/2005/11/10/491431.aspx上的帖子

于 2011-12-30T18:34:12.463 回答
0

对于“错误数据”错误,我有一个不同的根本原因,这与没有“FlushFinalBlock”代码有关。这显然导致了一个问题,因为我从未存储完全加密的值。现在在上面的代码示例中包含,但显然它被隐藏在代码中。我希望这不是太离题,但我确实很快从谷歌找到了这篇文章,所以我认为其他人可能会来到这里并犯同样的简单错误。

还可能值得一提的是,@Dave Black 的答案似乎与上面发布的最终代码无关......?我是否正确阅读了上面的代码?这可能是随着时间的推移而发生变化的结果——但这让我在试图找出问题所在时有点误入歧途(我已经正确存储了我的加密数据,只是不是全部:-()

于 2012-11-12T14:51:51.213 回答
-1

将加密和解密模式设置为ECB。
正如 rossum 所说:“ECB 不安全,它会泄露信息”,所以如果您需要随机访问您的文件,请使用 CTR。

于 2011-07-04T18:35:09.133 回答