我们有一个当前的应用程序,其中用户登录凭据存储在sql Server数据库中.它们基本上存储为纯文本用户名,密码哈希以及此哈希的关联盐.
这些都是由ASP.NET的成员资格/角色系统中的内置函数创建的.以下是名为“joe”的用户和“password”密码的行:
joe,kDP0Py2QwEdJYtUX9cJABg==,OJF6H4KdxFLgLu+oTDNFodCEfMA=
我已将这些内容转储到CSV文件中,我试图将其转换为Django的可用格式,它以这种格式存储密码:
[ALGO] $[盐] $[散列]
salt是普通字符串,哈希是SHA1哈希的十六进制摘要.
到目前为止,我已经能够确定ASP以base64格式存储这些哈希值和盐.上面的那些值解码成二进制字符串.
我们使用了反射器来收集ASP如何对这些值进行身份验证:
internal string EncodePassword(string pass,int passwordFormat,string salt) { if (passwordFormat == 0) { return pass; } byte[] bytes = Encoding.Unicode.GetBytes(pass); byte[] src = Convert.FromBase64String(salt); byte[] dst = new byte[src.Length + bytes.Length]; byte[] inArray = null; Buffer.BlockCopy(src,dst,src.Length); Buffer.BlockCopy(bytes,src.Length,bytes.Length); if (passwordFormat == 1) { HashAlgorithm algorithm = HashAlgorithm.Create(Membership.HashAlgorithmType); if ((algorithm == null) && Membership.IsHashAlgorithmFromMembershipConfig) { RuntimeConfig.GetAppConfig().Membership.ThrowHashAlgorithmException(); } inArray = algorithm.ComputeHash(dst); } else { inArray = this.EncryptPassword(dst); } return Convert.ToBase64String(inArray); }
有条件地,从DB中提取盐,b64将其解码为二进制表示.它在原始密码上执行“GetBytes”,然后将它们连接起来,首先是盐.
然后它在这个新字符串上运行SHA1算法,base64对其进行编码,并将其与存储在数据库中的值进行比较.
我试图编写一些代码来尝试在Python中重现这些哈希值,但我失败了.在我弄清楚这是如何转换之前,我将无法在Django中使用它们.这是我正在测试的方式:
import hashlib from base64 import b64decode,b64encode b64salt = "kDP0Py2QwEdJYtUX9cJABg==" b64hash = "OJF6H4KdxFLgLu+oTDNFodCEfMA=" binsalt = b64decode(b64salt) password_string = 'password' m1 = hashlib.sha1() # Pass in salt m1.update(binsalt) # Pass in password m1.update(password_string) # B64 encode the binary digest if b64encode(m1.digest()) == b64hash: print "Logged in!" else: print "Didn't match" print b64hash print b64encode(m1.digest())
我想知道是否有人可以看到我的方法中的任何缺陷或可以建议另一种方法.也许你可以采用上面的算法和上面已知的密码和盐,并在你的系统上产生哈希?
解决方法
当您将UTF16字符串转换为二进制时,python正在插入一个字节顺序标记. .NET字节数组不包含BOM,因此我做了一些ghetto python,它将UTF16转换为十六进制,删除前4个字符,然后将其解码为二进制.
撕掉BOM可能有更好的方法,但这对我有用!
这是一个通过:
import hashlib from base64 import b64decode,b64encode def utf16tobin(s): return s.encode('hex')[4:].decode('hex') b64salt = "kDP0Py2QwEdJYtUX9cJABg==" b64hash = "OJF6H4KdxFLgLu+oTDNFodCEfMA=" binsalt = b64decode(b64salt) password_string = 'password'.encode("utf16") password_string = utf16tobin(password_string) m1 = hashlib.sha1() # Pass in salt m1.update(binsalt + password_string) # Pass in password # B64 encode the binary digest if b64encode(m1.digest()) == b64hash: print "Logged in!" else: print "Didn't match" print b64hash print b64encode(m1.digest())