使用Python对ASP.NET角色/成员资格创建的DB中的原始用户名,哈希,salt进行身份验证

时间:2008-11-06 18:14:45

标签: asp.net python hash passwords

我们有一个当前的应用程序,其中用户登录凭据存储在SQL Server数据库中。它们基本上存储为纯文本用户名,密码哈希以及此哈希的关联盐。

这些都是由ASP.NET的成员资格/角色系统中的内置函数创建的。这是一个名为'joe'的用户和一个'password'密码的行:

  

乔,kDP0Py2QwEdJYtUX9cJABg ==,OJF6H4KdxFLgLu + oTDNFodCEfMA =

我已将这些内容转储到CSV文件中,我试图将其转换为Django的可用格式,以这种格式存储密码:

[ALGO] $ [盐] $ [散列]

salt是一个普通字符串,而hash是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, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, 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())

我想知道是否有人可以在我的方法中看到任何缺陷或者可以提出替代方法。也许你可以采用上面的算法和上面已知的密码和盐,并在你的系统上产生哈希值?

2 个答案:

答案 0 :(得分:8)

当您将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())

答案 1 :(得分:0)

关于可能出现什么问题的两个想法。

首先,反射中的代码有三条路径:

  • 如果passwordFormat为0,则按原样返回密码。
  • 如果passwordFormat为1,则会根据您的python代码创建哈希值。
  • 如果passwordFormat不是0或1,则调用this.EncryptPassword()

你怎么知道你正在哈希密码,而不是用this.EncryptPassword()加密密码?您可能需要反转EncryptPassword()成员函数并复制它。除非您有一些信息可以确保您正在对密码进行哈希处理而不对其进行加密。

其次,如果它确实哈希密码,你可能想看看Encoding.Unicode.GetBytes()函数为字符串“password”返回什么,因为你可能会得到一些回复:

0x00 0x70 0x00 0x61 0x00 0x73 0x00 0x73 0x00 0x77 0x00 0x6F 0x00 0x72 0x00 0x64

而不是:

0x70 0x61 0x73 0x73 0x77 0x6F 0x72 0x64

我希望这会有所帮助。