2009-02-09 9 views
8

Ich habe eine große Datenbank von Benutzern (~ 200.000), die ich von einer ASP.NET-Anwendung auf eine Ruby on Rails-Anwendung übertrage. Ich möchte wirklich nicht jeden Benutzer bitten, sein Kennwort zurückzusetzen und so versuche ich, die C# Kennwort-Hashfunktion in Ruby neu zu implementieren.Reimplementieren ASP.NET Mitgliedschaft und Benutzer Passwort Hashing in Ruby

Die alte Funktion ist dies:

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); 
} 

Ein Beispiel Hash-Passwort und Salz ist (und das Passwort verwendet wurde, "password"):

Gehashte Passwort: "weEWx4rhyPtd3kec7usysxf7kpk =" Salz: " 1ptFxHq7ALe7yXIQDdzQ9Q ==“ Passwort: "password"

Jetzt mit dem folgenden Ruby-Code:

require "base64" 
require "digest/sha1" 


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

concat = salt+password 

sha1 = Digest::SHA1.digest(concat) 

encoded = Base64.encode64(sha1) 

puts encoded 

Ich bekomme nicht den richtigen Passwort-Hash (ich bekomme "+ BsdIOBN/Vh2U7qWG4e + O13h3iQ =" anstelle von "weeEWx4rhyPtd3kec7usysxf7kpk ="). Kann jemand sehen, was das Problem sein könnte?

Vielen Dank

Arfon

Antwort

8

Nur ein kurzes Update, ein Kollege von mir hat dies gelöst:

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

Sie müssen das Salz unencode es ihm die Byte-Darstellung zurück zu konvertieren und dann das verketten mit dem Passwort des Hash-Passwort-Wert zu erhalten. Sie verwenden die codierende Salzzeichenkette direkt (was ein anderes Salz ist) und daher hasht es zu etwas anderem.

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 
+0

Sie sind ein wichtiger Schritt Überspringen: Passwort in Bytes umgewandelt wird. –

+0

OK, sieht so aus, als müsste ich auf die Byte-Ebene fallen, um das zu tun? – arfon

+0

@Adam - nicht sicher. In .NET werden sie in ein Byte-Array eingefügt, um den Hashalgorithmus zu übergeben. Ruby kann das Gleiche mit einer einfachen Zeichenfolge tun. Wenn sie als null-terminiert gespeichert werden, entspricht dies im Wesentlichen dem Puffer im .NET-Beispiel. Ich würde es drehen und sehen, ob es funktioniert. – tvanfosson

2

Sie sind ziemlich nah. Leider hat Ruby momentan keine integrierte Unicode-Unterstützung und Ihre Hashing-Funktion beruht darauf. Es gibt Problemumgehungen. Schauen Sie sich die Seite an, wie Sie Unicode in Ruby machen können. BTW, ich glaube, Sie haben vergessen, Base64 das Salz zu dekodieren, es sieht aus wie die ASP.net-Funktion das tut.

3

Ich habe mit der Migration eines bestehenden .NET-App zu Ruby on Rails beauftragt. Ich verwende den folgenden Code, um das .NET-Passwort-Hashing nachzuahmen. Ich bin sehr neu in Ruby und kenne .NET überhaupt nicht. Der Code ist möglicherweise nicht so sauber, wie es könnte, aber es ist ein Anfang.

Um zu testen, das als Ruby-Script speichern und mit laufen:

Ruby-Skript plain_text_password salt_in_base64

z.B.

Rubin 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 
+0

Wow Mann, ich habe damit für immer gespielt und dein Code hat es getan. Ich denke, Sie versuchen, sehr ähnlichen Code zu replizieren. Ich habe so viele verschiedene Dinge ausprobiert und war ganz nah bei dir, aber es war nur ein bisschen anders. Ich packte und entpackte mit "S *". Danke vielmals. – Amala

Verwandte Themen