【问题标题】:Reimplement ASP.NET Membership and User Password Hashing in Ruby在 Ruby 中重新实现 ASP.NET 成员资格和用户密码哈希
【发布时间】:2009-02-09 22:52:00
【问题描述】:

我有一个庞大的用户数据库(约 200,000 个),我正在将其从 ASP.NET 应用程序转移到 Ruby on Rails 应用程序。我真的不想要求每个用户重置他们的密码,所以我试图在 Ruby 中重新实现 C# 密码哈希函数。

旧函数是这样的:

public string EncodePassword(string pass, string saltBase64)
 {
     byte[] bytes = Encoding.Unicode.GetBytes(pass);
     byte[] src = Convert.FromBase64String(saltBase64);
     byte[] dst = new byte[src.Length + bytes.Length];
     Buffer.BlockCopy(src, 0, dst, 0, src.Length);
     Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
     HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
     byte[] inArray = algorithm.ComputeHash(dst);
     return Convert.ToBase64String(inArray);
 }

哈希密码和盐的示例是(并且使用的密码是“密码”):

散列密码:“weEWx4rhyPtd3kec7usysxf7kpk=” 盐:“1ptFxHq7ALe7yXIQDdzQ9Q==” 密码:“密码”

现在使用以下 Ruby 代码:

require "base64"
require "digest/sha1"


password = "password"
salt = "1ptFxHq7ALe7yXIQDdzQ9Q=="

concat = salt+password

sha1 = Digest::SHA1.digest(concat)

encoded = Base64.encode64(sha1)

puts encoded

我没有得到正确的密码哈希(我得到的是“+BsdIOBN/Vh2U7qWG4e+O13h3iQ=”而不是“weEWx4rhyPtd3kec7usysxf7kpk=”)。谁能看出问题出在哪里?

非常感谢

阿方

【问题讨论】:

    标签: asp.net ruby-on-rails ruby base64 sha1


    【解决方案1】:

    只是一个快速更新,我的一个同事已经解决了这个问题:

    require "base64"
    require "digest"
    require "jcode"
    
    
    def encode_password(password, salt)
     bytes = ""
     password.each_char { |c| bytes += c + "\x00" }
     salty = Base64.decode64(salt)
     concat = salty+bytes
     sha1 = Digest::SHA1.digest(concat)
     encoded = Base64.encode64(sha1).strip()
     puts encoded
    end
    

    【讨论】:

      【解决方案2】:

      我的任务是将现有的 .NET 应用程序迁移到 Ruby on Rails。我正在使用下面的代码来模拟 .NET 密码散列。我对 Ruby 很陌生,根本不了解 .NET。代码可能不够干净,但它是一个开始。

      要测试,请将其保存为 Ruby 脚本并运行:

      ruby 脚本 plain_text_password salt_in_base64

      例如

      ruby dotNetHash.rb 密码123 LU7hUk4MXAvlq6DksvP9SQ==

      require "base64"
      require "digest"
      
      # Encode password as double-width characters
      password_as_text = ARGV.first
      double_width_password = []
      double_width_password = password_as_text.encode("UTF-16LE").bytes.to_a
      
      # Unencode the salt
      salt = Base64.decode64(ARGV[1])
      
      # Concatenate salt+pass
      salt_pass_array = []
      salt_pass_array = salt.bytes.to_a + double_width_password
      
      # Repack array as string and hash it. Then encode.
      salt_pass_str = salt_pass_array.pack('C*')
      sha1_saltpass = Digest::SHA1.digest(salt_pass_str)
      enc_sha1_saltpass = Base64.encode64(sha1_saltpass).strip()
      puts "Encoded SHA1 saltpass is " + enc_sha1_saltpass
      

      【讨论】:

      • 哇,我一直在玩这个,你的代码做到了。我认为您正在尝试复制非常相似的代码。我尝试了很多不同的事情,并且与您的非常接近,但只是略有不同。我正在用“S*”打包和拆包。非常感谢。
      【解决方案3】:

      你很接近。不幸的是,Ruby 目前没有内置的 unicode 支持,您的散列函数依赖于它。有解决方法。环顾该站点,了解如何在 Ruby 中执行 unicode。 顺便说一句,我想你忘了对 salt 进行 base64 解码,看起来 ASP.net 函数可以做到这一点。

      【讨论】:

        【解决方案4】:

        您需要取消对盐的编码以将其转换回它的字节表示,然后将其与密码连接以获得散列密码值。您直接使用编码盐字符串(这是一种不同的盐),因此它正在散列到不同的东西。

        require "base64"
        require "digest/sha1"
        password = "password"
        salt = Base64.decode64("1ptFxHq7ALe7yXIQDdzQ9Q==")
        concat = salt+password
        sha1 = Digest::SHA1.digest(concat)
        encoded = Base64.encode64(sha1)
        puts encoded
        

        【讨论】:

        • 您正在跳过一个重要步骤:将密码转换为字节。
        • 好的,看来我必须降到字节级别才能做到这一点?
        • @Adam -- 不确定。在 .NET 中,它把它们放在一个字节数组中,以传递给散列算法。 Ruby 实际上可以使用一个简单的字符串来做同样的事情。如果它们存储为空终止,则它本质上与 .NET 示例中的缓冲区相同。我会试一试,看看它是否有效。
        • 我猜这里的一个潜在问题是 Ruby Digest 库不能散列字节数组,只能散列字符串。
        猜你喜欢
        • 1970-01-01
        • 2013-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-08
        • 1970-01-01
        相关资源
        最近更新 更多