【问题标题】:Special characters in MD5 encryptionMD5加密中的特殊字符
【发布时间】:2019-05-29 04:42:53
【问题描述】:

我在 C# 和 SQL Server 中遇到了 MD5 加密问题,它只发生在带有特殊字符的行上。

这是c#中的代码:

public virtual string RowHash<T>(T item)
    {
        PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        var finalvalue = "";
        foreach (PropertyInfo p in properties)
        {
            if (p.Name != "Hash")
            {
                if (!p.CanWrite || !p.CanRead) { continue; }

                MethodInfo mget = p.GetGetMethod(false);
                MethodInfo mset = p.GetSetMethod(false);

                // Get and set methods have to be public
                if (mget == null) { continue; }
                if (mset == null) { continue; }
                var value = p.GetValue(item, null) == null ? "" : p.GetValue(item, null) is Entity? ((Entity)p.GetValue(item, null)).Id.ToString() : p.GetValue(item, null).ToString();
                finalvalue += value;
            }

        }
        return finalvalue;
    }

    public static string GetMD5(string text)
    {
        var md5 = MD5CryptoServiceProvider.Create();
        var encoding = new ASCIIEncoding();
        byte[] stream = null;

        var sb = new StringBuilder();
        stream = md5.ComputeHash(encoding.GetBytes(text));

        for (int i = 0; i < stream.Length; i++) sb.AppendFormat("{0:x2}", stream[i]);

        return sb.ToString();
    }

    public static string PasswordMD5(string password)
    {
        var pwd = GetMD5(password + GetMD5(password).Substring(0,2));
        return pwd;
    }

使用 RowHash 方法,我将 Row 中的所有字段连接起来,除非将存储结果的字段哈希,然后我将其发送到方法 PasswordMD5,该方法创建我们保存在数据库中的加密哈希。

然后我用这段代码在 SQL Server 中做同样的事情:

CONVERT(VARCHAR(32), HashBytes('MD5',CONVERT(VARCHAR(MAX),CONVERT(VARCHAR(MAX),ISNULL([Field1],''))+ISNULL([Field2],'')+ISNULL([Field3],'')+CONVERT(VARCHAR(MAX),ISNULL([Field4],''))+ISNULL(CONVERT(VARCHAR(MAX),[Field5]),'')+ISNULL(CONVERT(VARCHAR(MAX),Field6]),'')+CONVERT(VARCHAR(MAX),Field7]))+SUBSTRING(CONVERT(VARCHAR(32),HashBytes('MD5',CONVERT(VARCHAR(MAX),CONVERT(VARCHAR(MAX),ISNULL([Field1],''))+ISNULL([Field2],'')+ISNULL([Field3],'')+CONVERT(VARCHAR(MAX),ISNULL([Field4],''))+ISNULL(CONVERT(VARCHAR(MAX),Field5]),'')+ISNULL(CONVERT(VARCHAR(MAX),[Field6]),'')+CONVERT(VARCHAR(MAX),Field7]))) 2), 1, )), 2)

然后我将它与我在 C# 中创建的 Hash 进行比较,以检查我在数据库中拥有的数据的完整性。这适用于所有没有特殊字符的行,但对于包含任何特殊字符(如 é 或 ö)的所有行都失败。

这是我前段时间遇到的一个问题,但是任务被其他优先级暂停了,我不记得我已经尝试过哪些解决方案,我记得我尝试了一些解决方案来改变 C# 中字符串的编码但是没有工作。

我做错了什么?

提前致谢。

【问题讨论】:

  • 看起来您已经将nvarchar 数据压缩为varchar,是的:会破坏很多非ASCII 字符。尝试始终使用nvarchar
  • 也:“从 SQL Server 2016 (13.x) 开始,除 SHA2_256 和 SHA2_512 之外的所有算法都已弃用。较旧的算法(不推荐)将继续工作,但它们会引发弃用事件。” - 服务器不希望您为此使用 MD5。 您的用户不希望您为此使用 MD5。并且:它要求您发送未散列的密码而不是必要的。 IMO 你应该尽快散列 - 大概是立即在应用层 - 使用加盐和强(读取:慢)散列算法,如 PBKDF2、bcrypt 或 scrypt。
  • var encoding = new ASCIIEncoding();将删除不可打印的字符。
  • @jdweng 它肯定会消除任何非 ASCII 字符,你是对的;不过控制字符应该没问题
  • 如果您实际上没有对密码进行哈希处理,请重命名该函数。如果您实际上是在散列密码,请停止使用 MD5。请注意,加密与散列不同(即使散列是加密散列);错误地使用这些词可能会导致一些混乱。您通常不会加密散列。如果散列仅用作加速查找或检测其他受信任环境中差异的一种方式,则不需要安全地对行数据进行散列,但散列密码没有这样的借口。

标签: c# sql-server cryptography md5 cryptographic-hash-function


【解决方案1】:

最后我找不到使用 MD5 的好解决方案,我转移到 SHA256 并使用此答案工作:

https://stackoverflow.com/a/19214122/4890862

【讨论】:

    【解决方案2】:

    我对我的代码使用了这种加密和解密方法,并且我已经用特殊字符进行了测试,它对我来说工作正常。我会把我的代码发给你,请测试一下,希望它对你有用。

    TableFilter 是普通类文件,文件中包含加密和解密方法,其他的你可以在.cs页面上写这两个方法。

    public static string Encrypt(string toEncrypt, bool useHashing = true)
        {
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
    
            System.Configuration.AppSettingsReader settingsReader =
                                                new AppSettingsReader();
            // Get the key from config file
    
            string key = (string)settingsReader.GetValue("EncryptionKey",
                                                             typeof(String));
            //System.Windows.Forms.MessageBox.Show(key);
            //If hashing use get hashcode regards to your key
            if (useHashing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                //Always release the resources and flush data
                // of the Cryptographic service provide. Best Practice
    
                hashmd5.Clear();
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);
    
            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            //set the secret key for the tripleDES algorithm
            tdes.Key = keyArray;
            //mode of operation. there are other 4 modes.
            //We choose ECB(Electronic code Book)
            tdes.Mode = CipherMode.ECB;
            //padding mode(if any extra byte added)
    
            tdes.Padding = PaddingMode.PKCS7;
    
            ICryptoTransform cTransform = tdes.CreateEncryptor();
            //transform the specified region of bytes array to resultArray
            byte[] resultArray =
              cTransform.TransformFinalBlock(toEncryptArray, 0,
              toEncryptArray.Length);
            //Release resources held by TripleDes Encryptor
            tdes.Clear();
            //Return the encrypted data into unreadable string format
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }
    
        public static string Decrypt(string cipherString, bool useHashing = true)
        {
            byte[] keyArray;
            //get the byte code of the string
    
            byte[] toEncryptArray = Convert.FromBase64String(cipherString);
    
            System.Configuration.AppSettingsReader settingsReader =
                                                new AppSettingsReader();
            //Get your key from config file to open the lock!
            string key = (string)settingsReader.GetValue("EncryptionKey",
                                                         typeof(String));
    
            if (useHashing)
            {
                //if hashing was used get the hash code with regards to your key
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                //release any resource held by the MD5CryptoServiceProvider
    
                hashmd5.Clear();
            }
            else
            {
                //if hashing was not implemented get the byte code of the key
                keyArray = UTF8Encoding.UTF8.GetBytes(key);
            }
    
            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            //set the secret key for the tripleDES algorithm
            tdes.Key = keyArray;
            //mode of operation. there are other 4 modes. 
            //We choose ECB(Electronic code Book)
    
            tdes.Mode = CipherMode.ECB;
            //padding mode(if any extra byte added)
            tdes.Padding = PaddingMode.PKCS7;
    
            ICryptoTransform cTransform = tdes.CreateDecryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(
                                 toEncryptArray, 0, toEncryptArray.Length);
            //Release resources held by TripleDes Encryptor                
            tdes.Clear();
            //return the Clear decrypted TEXT
            return UTF8Encoding.UTF8.GetString(resultArray);
        }
    

    :用于文本框字符串(而不是txtpassword.text put testingé123ö 用于理解))

    login_Model.Password = TableFilter.Encrypt("testingé123ö");
    

    :Web.config


        <add key="EncryptionKey" value="encyptionkeyvalue"/>
    

    【讨论】:

      猜你喜欢
      • 2014-06-06
      • 1970-01-01
      • 2017-09-09
      • 2012-12-21
      • 1970-01-01
      • 2017-01-19
      • 2022-01-24
      • 2016-11-26
      • 1970-01-01
      相关资源
      最近更新 更多