【问题标题】:Simulating MySql's password() encryption using .NET or MS SQL使用 .NET 或 MS SQL 模拟 MySql 的 password() 加密
【发布时间】:2010-10-26 11:47:46
【问题描述】:

我正在将旧的 ASP/MySql webapp 更新为 ASP.NET/MS SQL。

我们希望旧网站的登录信息在新应用中正常运行。

不幸的是,密码是使用 MySql 的 password() 函数存储在 MySql DB 中的。

是否可以在 .NET 或 .NET 中模拟 MySql 的 password() 函数? MS SQL?

感谢任何帮助/链接。

【问题讨论】:

  • 您使用的是什么版本的 MySQL?如果您知道您使用的是什么版本,这似乎应该是可能的。 MySQL 使用双 SHA1 哈希算法对密码进行编码。
  • 当我可以访问 mysql 数据库时会检查这个。感谢您发布的解决方案!

标签: .net sql mysql sql-server encryption


【解决方案1】:

修改了 C# 版本以更正填充问题。
[测试] 公共无效生成MySQLHashX2() { 字符串密码 = "20iva05";

        byte[] keyArray = Encoding.UTF8.GetBytes(password);
        SHA1Managed enc = new SHA1Managed();
        byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray));
        StringBuilder myBuilder = new StringBuilder(encodedKey.Length);

        foreach (byte b in encodedKey)
        {
            log.Debug(b.ToString() + "    ->   " +  b.ToString("X2"));
            myBuilder.Append(b.ToString("X2"));
        }

        Assert.AreEqual("*8C2029A96507478FD1720F6B713ADD57C66EED49", "*" + myBuilder.ToString());
    } 

【讨论】:

    【解决方案2】:

    根据 MySQL 文档,该算法是双 SHA1 哈希。在检查 MySQL 源代码时,您会在 libmysql/password.c 中找到一个名为 make_scrambled_pa​​ssword() 的函数。函数定义如下:

    /*
        MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
        applied to the password string, and then produced octet sequence is
        converted to hex string.
        The result of this function is used as return value from PASSWORD() and
        is stored in the database.
      SYNOPSIS
        make_scrambled_password()
        buf       OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
        password  IN  NULL-terminated password string
    */
    
    void
    make_scrambled_password(char *to, const char *password)
    {
      SHA1_CONTEXT sha1_context;
      uint8 hash_stage2[SHA1_HASH_SIZE];
    
      mysql_sha1_reset(&sha1_context);
      /* stage 1: hash password */
      mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
      mysql_sha1_result(&sha1_context, (uint8 *) to);
      /* stage 2: hash stage1 output */
      mysql_sha1_reset(&sha1_context);
      mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE);
      /* separate buffer is used to pass 'to' in octet2hex */
      mysql_sha1_result(&sha1_context, hash_stage2);
      /* convert hash_stage2 to hex string */
      *to++= PVERSION41_CHAR;
      octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
    }
    

    使用这种方法,您可以创建一个基本上做同样事情的 .NET 对应物。这就是我想出的。当我运行 SELECT PASSWORD('test');针对我的本地 MySQL 副本,返回的值为:

    *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29

    根据源代码(同样在password.c中),开头的星号表示这是后MySQL 4.1加密密码的方法。例如,当我在 VB.Net 中模拟功能时,我会想到:

    Public Function GenerateMySQLHash(ByVal strKey As String) As String
        Dim keyArray As Byte() = Encoding.UTF8.GetBytes(strKey)
        Dim enc = New SHA1Managed()
        Dim encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray))
        Dim myBuilder As New StringBuilder(encodedKey.Length)
    
        For Each b As Byte In encodedKey
            myBuilder.Append(b.ToString("X2"))
        Next
    
        Return "*" & myBuilder.ToString()
    End Function
    

    请记住,SHA1Managed() 位于 System.Security.Cryptography 命名空间中。此方法返回与 MySQL 中的 PASSWORD() 调用相同的输出。我希望这对你有帮助。

    编辑:这是 C# 中的相同代码

    public string GenerateMySQLHash(string key)
    {
        byte[] keyArray = Encoding.UTF8.GetBytes(key);
        SHA1Managed enc = new SHA1Managed();
        byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray));
        StringBuilder myBuilder = new StringBuilder(encodedKey.Length);
    
        foreach (byte b in encodedKey)
            myBuilder.Append(b.ToString("X2"));
    
        return "*" + myBuilder.ToString();
    }
    

    【讨论】:

    • 太棒了,谢谢!将尝试它是否适用于我的 mysql 版本(目前无法检查)并让您知道。非常感谢您的研究和出色的解决方案。
    • 如果您使用的是 4.1.1 之前的版本,则有一种较旧的加密方法。我也可以帮你写出那个方法。让我知道,我很乐意为您提供帮助。祝你好运!
    • 我实际上也找到了一种使用 T-SQL 执行此操作的方法。它看起来很丑陋,但它有效! SELECT '*' + SUBSTRING(master.dbo.fn_varbintohexstr(HASHBYTES('SHA1',HASHBYTES('SHA1','VALUE-TO-ENCRYPT-GOES-HERE'))),1,42)
    • 谢谢! mysql 4.1.1 密码功能的 python 版本在这里:csl.sublevel3.org/mysql-password-function 如果您还可以包含 4.1 之前的版本,我将不胜感激,因为很多密码仍以旧格式保留。
    【解决方案3】:

    mysql密码功能不是特别安全 (例如,没有盐或其他防止寻找匹配哈希的方法) 我想复制算法的唯一原因是 1:您有一个具有 mysql 密码()的用户列表/表 2:你想从用户表中的哈希中破解mysql密码。

    否则使用不同的东西,例如结合用户名(和/或其他一些行不变量)和密码的哈希。这样,如果两个用户选择相同的密码,它就不会很明显。如果桌子暴露在外,安全性不会以同样的速度下降 (例如 446a12100c856ce9 的 google,它是一个非常流行的密码的 password() 哈希)

    【讨论】:

      【解决方案4】:

      “他们不会透露什么 他们使用的算法”

      erm ...有人应该醒来并告诉您 MySQL 开源 ...他们不需要“披露”某些内容,因为每个人都可以阅读数据库的结构 - 只需下载来源,搜索加密功能(我猜他们正在使用 C++)并开始调查...... SHA1 现在看起来很不安全 - 就在最近,一些科学家已经证明,可以不受限制地选择多达 20% 的数据并产生相同的哈希,因此人们可以建议使用 AES 或 SHA2(因此不是 MySQL-PASSWORD-func)

      【讨论】:

        【解决方案5】:

        对于 VB 网络,此函数在左侧填充 0,以便当十六进制代码为 [例如] 'E' 时,此函数将正确地将 '0E' 附加到结果字符串中。所以最后,包括前置的'*',结果字符串将是 41 个字符长,正如 MySQL 中所要求的那样

        Public Function GenerateMySQLHash(ByVal strKey As String) As String
        
            Dim keyArray As Byte() = System.Text.UTF8Encoding.UTF8.GetBytes(strKey)
            Dim enc = New Security.Cryptography.SHA1Managed()
            Dim encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray))
            Dim myBuilder As New System.Text.StringBuilder(encodedKey.ToString.Length)
        
            For Each b As Byte In encodedKey
                myBuilder.Append(Strings.Right("0" & b.ToString("X"), 2))
            Next
        
            Return "*" & myBuilder.ToString()
        End Function
        

        【讨论】:

          【解决方案6】:

          您可以在 .Net 中使用 MD5 或 SHA1 加密字符串,但 MySQL 使用的实际算法可能与这两种方法不同。我怀疑它是基于服务器实例的某种“盐”,但我不知道。

          理论上,由于我相信 MySQL 是开源的,因此您可以调查源代码并确定这是如何完成的。

          http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html#function_password

          编辑 1:我相信使用的算法是带有其他“调整”的双 SHA1(根据 this 博客文章)。

          【讨论】:

          • 我知道,我知道...也能够研究这些信息,但它并没有真正回答我的问题 :-) 无论如何,谢谢。
          • 我查看了源代码,我认为它基于 SHA1,但使用了各种盐和随机化技术。我知道不是很有帮助,所以我认为答案是去别处看看:(
          【解决方案7】:

          您将无法模拟 MySql 密码()函数。至少不是没有大量的工作和运气。由于 MySql 使用他们自己的算法来单向加密字符串,他们不会透露他们使用什么算法;这意味着您必须进行反复试验、比较结果字符串等。

          解决您的问题:

          我会复制数据库但保持与 MySql 的连接。使用标志来识别首次登录。要求他们使用当前密码;使用 MySql 密码()函数验证密码。如果密码有效;要求他们通过再次输入相同的密码或新密码来重置它;此时使用您最喜欢的加密算法并将结果存储在您的 MS Sql DB 中。

          我知道这听起来很痛苦,但这是你能做的最好的事情,而不是试图破解 MySql 加密算法。

          祝你好运!

          【讨论】:

          • 感谢您的信息。我将部分使用您的解决方案:第一步,将用户导入 MS SQL 并将“HasMysqlPassword”位设置为“1”。第二步,登录后我检索 MS SQL 用户详细信息并检查 HasMysqlPassword=1。如果不是,我检查 MS SQL 中的“密码”字段。如果是,我会在mysql中检查密码。如果匹配,我使用 SHA1 加密输入的密码,将其存储在 MS SQL 中,同时将 HasMysqlPassword 设置为 0。一段时间后,我应该能够分离 mysql 数据库并通知其余用户他们的新密码是自动生成
          • 这种方法的好处是用户不会注意到任何事情。
          • 这是不正确的。我已经写了一个方法来转换为 .NET 中的有效密码散列...帖子来关注
          • 你明白了。我认为这是一个不错的干净解决方案。
          • "他们不会透露他们使用什么算法;" -- MySql 是开源的,不是吗?
          猜你喜欢
          • 2013-07-23
          • 1970-01-01
          • 1970-01-01
          • 2011-06-12
          • 1970-01-01
          • 2012-02-16
          • 2014-03-09
          • 1970-01-01
          • 2023-03-29
          相关资源
          最近更新 更多