在Ruby中重新实现ASP.NET成员资格和用户密码哈希

时间:2009-02-09 22:52:00

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

我有一个庞大的用户数据库(~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);
 }

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

哈希密码:“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 =”)。任何人都可以看到问题所在吗?

非常感谢

Arfon

4 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:3)

我的任务是将现有的.NET应用程序迁移到Ruby on Rails。我使用下面的代码来模仿.NET密码散列。我是Ruby的新手,根本不了解.NET。代码可能不尽如人意,但它只是一个开始。

要进行测试,请将其另存为Ruby脚本并使用以下命令运行:

ruby​​ script plain_text_password salt_in_base64

e.g。

ruby​​ dotNetHash.rb password123 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

答案 2 :(得分:2)

你非常接近。不幸的是,Ruby目前没有内置的unicode支持,你的散列函数依赖于它。有解决方法。查看网站上有关如何在Ruby中执行unicode的信息。 顺便说一句,我想你忘记了base64解码盐,看起来像ASP.net函数那样。

答案 3 :(得分:1)

您需要对salt进行解码以将其转换回其字节表示形式,然后将其与密码连接以获取散列密码值。你直接使用编码盐字符串(这是一个不同的盐),因此它是散列到不同的东西。

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