解密字符串时偶尔会出现错误数据错误:System.Security.Cryptography.CryptographicException

时间:2011-07-02 08:13:39

标签: .net asp.net cryptography encryption encryption-symmetric

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

  

糟糕的数据。

     

描述:未处理的异常   在执行期间发生   当前的网络请求。请查看   堆栈跟踪以获取更多信息   错误及其来源   代码。

     

异常详细信息:   System.Security.Cryptography.CryptographicException:   糟糕的数据。

     

来源错误:

     

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

     

堆栈追踪:

     

[CryptographicException:错误的数据。 ]
  System.Security.Cryptography.CryptographicException.ThrowCryptographicException(的Int32   hr)+33
  System.Security.Cryptography.Utils._DecryptData(SafeKeyHandle   hKey,Byte []数据,Int32 ib,Int32 cb,   字节[]&安培; outputBuffer,Int32   outputOffset,PaddingMode PaddingMode,   布尔fDone)+0
  System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(字节[]   inputBuffer,Int32 inputOffset,Int32   inputCount)+313
  System.Security.Cryptography.CryptoStream.FlushFinalBlock()   +33 Cryptography35.SymmetricEncryptionUtility.DecryptData(Byte []   data,String keyFile)in   E:\文档\ @Library \ Cryptography35 \ Cryptography35 \ SymmetricEncryptionUtility.cs:124   Cryptography35.SymmetricQueryString.SymmetriclyEncryptedQueryString..ctor(字符串   encryptedData,String keyfilename,   字符串algorithmname)   E:\文档\ @Library \ Cryptography35 \ Cryptography35 \ SymmetricQueryString \ SymmetriclyEncryptedQueryString.cs:67   WebForms.Web.Views.purchase_a.GetSymmetriclyEncryptedQueryString()   在   E:\文档\ WebForms.Web \查看\购a.aspx.cs:35   WebForms.Web.Views.purchase_a.Page_Load(对象   发件人,EventArgs e)in   E:\文档\ WebForms.Web \查看\购a.aspx.cs:56   错误帮助(IntPtr的   fp,Object o,Object t,EventArgs e)   +14 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object   发件人,EventArgs e)+35
  System.Web.UI.Control.OnLoad(EventArgs的   e)+91
  System.Web.UI.Control.LoadRecursive()   +74 System.Web.UI.Page.ProcessRequestMain(布尔值   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());
    }

}

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

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并繁荣。它给了我那个错误。好吧,我现在找到了错误的来源,但不管怎么说都不应该发生。

3 个答案:

答案 0 :(得分:3)

您的代码中隐藏着一个错误...

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

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

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

  3. 有关其他信息,请参阅MS安全大师Shawn Farkas的帖子http://blogs.msdn.com/b/shawnfa/archive/2005/11/10/491431.aspx

答案 1 :(得分:0)

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

也许值得一提的是@Dave Black答案似乎与上面公布的最终代码无关......?我是否正确阅读了上述代码? 这可能是随着时间的推移而发生变化的结果 - 但这使我在尝试解决出错的方面(我已经正确存储了我的加密数据,而不是所有这些:-()

答案 2 :(得分:-1)

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