Повторная реализация членства в ASP.NET и хеширования пароля пользователя в Ruby

У меня есть большая база данных пользователей (~ 200 000), которую я переношу из приложения ASP.NET в приложение Ruby on Rails. Я действительно не хочу просить каждого пользователя сбросить свой пароль, поэтому я пытаюсь повторно реализовать функцию хеширования паролей C # в Ruby.

Старая функция такова:

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 =" Salt: "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 =»). Кто-нибудь может увидеть, в чем может быть проблема?

Большое спасибо

Арфон


person arfon    schedule 09.02.2009    source источник


Ответы (4)


Просто быстрое обновление, мой коллега решил это:

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
person arfon    schedule 11.02.2009

Мне было поручено перенести существующее приложение .NET на Ruby on Rails. Я использую приведенный ниже код для имитации хеширования паролей .NET. Я новичок в Ruby и вообще не знаю .NET. Код может быть не таким чистым, как мог бы, но это начало.

Для проверки сохраните это как сценарий Ruby и запустите с:

Рубиновый скрипт plain_text_password salt_in_base64

e.g.

рубиновый 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
person Simon Irwin    schedule 18.11.2011
comment
Ух ты, чувак, я играл с этим вечно, и твой код сделал это. Я думаю, вы пытаетесь воспроизвести очень похожий код. Я пробовал много разных вещей и был очень близок к твоему, но это было немного по-другому. Упаковывал и распаковывал с S *. Большое спасибо. - person Amala; 06.02.2013

Вы довольно близки. К сожалению, Ruby на данный момент не имеет встроенной поддержки Unicode, и ваша функция хеширования полагается на нее. Есть обходные пути. Посмотрите на сайте, как сделать юникод в Ruby. Кстати, я думаю, вы забыли декодировать соль base64, похоже, что это делает функция ASP.net.

person Aram Verstegen    schedule 09.02.2009

Вам нужно расшифровать соль, чтобы преобразовать ее обратно в байтовое представление, а затем объединить ее с паролем, чтобы получить хешированное значение пароля. Вы напрямую используете кодирующую строку соли (которая является другой солью), и, таким образом, она хеширует что-то другое.

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
person tvanfosson    schedule 09.02.2009
comment
Вы пропускаете важный шаг: преобразование пароля в байты. - person Adam Lassek; 10.02.2009
comment
Ладно, значит, мне придется перейти на байтовый уровень, чтобы это сделать? - person arfon; 10.02.2009
comment
@ Адам - ​​не уверен. В .NET они помещаются в массив байтов для передачи алгоритму хеширования. На самом деле Ruby может делать то же самое, используя простую строку. Если они сохраняются как с завершающим нулем, это по сути то же самое, что и буфер в примере .NET. Я бы завертелся и посмотрел, работает ли это. - person tvanfosson; 10.02.2009
comment
Одна потенциальная проблема здесь, я полагаю, заключается в том, что библиотека Ruby Digest не может хешировать байтовый массив, а только строки. - person arfon; 10.02.2009