.NET 4.0中的加密错误

时间:2010-05-13 00:43:59

标签: .net encryption .net-4.0 sqlmembershipprovider

今天我将我的网络应用程序移动到.net 4.0并且Forms Auth刚刚停止工作。经过几个小时的挖掘我的SqlMembershipProvider(内置SqlMembershipProvider的简化版)后,我发现HMACSHA256哈希不一致。这是加密方法:

internal string EncodePassword(string pass, int passwordFormat, string salt)
{
    if (passwordFormat == 0) // MembershipPasswordFormat.Clear
        return pass;

    byte[] bIn = Encoding.Unicode.GetBytes(pass);
    byte[] bSalt = Convert.FromBase64String(salt);
    byte[] bAll = new byte[bSalt.Length + bIn.Length];
    byte[] bRet = null;

    Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
    Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
    if (passwordFormat == 1)
    { // MembershipPasswordFormat.Hashed
        HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );
        bRet = s.ComputeHash(bAll);
    } else
    {
        bRet = EncryptPassword( bAll );
    }

    return Convert.ToBase64String(bRet);
}

传递相同的密码和盐两次返回不同的结果!它在.NET 3.5中完美运行

任何人都知道有任何重大变化,或者这是一个已知的错误?

更新:当我将SHA512指定为散列算法时,一切正常,所以我相信这是在.NET 4.0中实现HMACSHA256散列算法的一个错误

谢谢! 安德烈

2 个答案:

答案 0 :(得分:2)

我相信在.net 4.0中有一些与安全相关的变化看看这个......

http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/whitepapers/aspnet4/breaking-changes

第一个显而易见的事情是......

  

默认哈希算法现在   HMACSHA256

     

ASP.NET使用加密和   哈希算法有助于保护数据   例如表单身份验证cookie   并查看状态。默认情况下,ASP.NET 4   现在使用HMACSHA256算法   对cookie和视图的哈希操作   州。早期版本的ASP.NET   使用较旧的HMACSHA1算法。

     

如果您的应用程序可能会受到影响   您运行混合ASP.NET 2.0 / ASP.NET 4   表格等数据的环境   身份验证cookie必须工作   跨.NET Framework版本。至   配置ASP.NET 4 Web应用程序   使用旧的HMACSHA1算法,   在中添加以下设置   Web.config文件:

      <machineKey validation="SHA1" />

您是否明确设置了哈希算法或者只是让asp.net决定...如果它现在使用不同的默认值,它可能只是随机抓取任何旧的哈希算法,因为不再支持定义的哈希算法。

话虽如此,M $可能已经退役了你正在使用的那个,所以这可能是原因,开玩笑......我只是意识到我需要测试我的CMS ......这对我来说没有发生过。

感谢您的提醒,希望我的想法能帮助我们两个人!

答案 1 :(得分:2)

我也遇到了这个问题。

在我的情况下,最终目标是能够动态设置connectionString(而不是在web.config中进行硬编码)。我这样做是通过下载MS为ASP.NET Providers推出的源代码并更改一些内部功能来获取连接字符串。

然而,这完全适用于.NET 2.0,看起来就像安德烈在上面发布的代码一样。一旦我把它全部到位,我注意到我无法登录我的网站。所以在搜索后我找到了这篇文章。谢谢!

我继续下载.NET Framework 4.0代码并且(如果有人想知道)这里是EncodePassword方法的新版本。我打算将其复制到旧版本的SqlMembershipProvider中,这样我就可以使用新的加密方法,并能够再次登录我的ASP.NET 4.0网站!

    private string EncodePassword(string pass, int passwordFormat, string salt)
    { 
        if (passwordFormat == 0) // MembershipPasswordFormat.Clear
            return pass;

        byte[] bIn = Encoding.Unicode.GetBytes(pass); 
        byte[] bSalt = Convert.FromBase64String(salt);
        byte[] bRet = null; 

        if (passwordFormat == 1)
        { // MembershipPasswordFormat.Hashed 
            HashAlgorithm hm = GetHashAlgorithm();
            if (hm is KeyedHashAlgorithm) {
                KeyedHashAlgorithm kha = (KeyedHashAlgorithm) hm;
                if (kha.Key.Length == bSalt.Length) { 
                    kha.Key = bSalt;
                } else if (kha.Key.Length < bSalt.Length) { 
                    byte[] bKey = new byte[kha.Key.Length]; 
                    Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
                    kha.Key = bKey; 
                } else {
                    byte[] bKey = new byte[kha.Key.Length];
                    for (int iter = 0; iter < bKey.Length; ) {
                        int len = Math.Min(bSalt.Length, bKey.Length - iter); 
                        Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
                        iter += len; 
                    } 
                    kha.Key = bKey;
                } 
                bRet = kha.ComputeHash(bIn);
            }
            else {
                byte[] bAll = new byte[bSalt.Length + bIn.Length]; 
                Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
                Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length); 
                bRet = hm.ComputeHash(bAll); 
            }
        } else { 
            byte[] bAll = new byte[bSalt.Length + bIn.Length];
            Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
            Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
            bRet = EncryptPassword(bAll, _LegacyPasswordCompatibilityMode); 
        }

        return Convert.ToBase64String(bRet); 
    }

编辑:尝试将这一方法复制到旧版本的SqlMembershipProvider是一个坏主意。太多变了。 :(