10

我有一个庞大的用户数据库(约 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=”)。谁能看到问题可能是什么?

非常感谢

阿尔丰

4

4 回答 4

9

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

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
于 2009-02-11T11:56:30.220 回答
3

我的任务是将现有的 .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
于 2011-11-18T15:11:16.253 回答
2

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

于 2009-02-09T23:11:39.073 回答
1

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

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
于 2009-02-09T23:01:33.187 回答