6

現在、ユーザーのログイン資格情報がSQLServerDBに保存されているアプリケーションがあります。これらは、基本的に、プレーンテキストのユーザー名、パスワードハッシュ、およびこのハッシュに関連付けられたソルトとして保存されます。

これらはすべて、ASP.NETのメンバーシップ/ロールシステムに組み込まれている関数によって作成されました。'joe'という名前のユーザーと'password'のパスワードの行は次のとおりです。

joe、kDP0Py2QwEdJYtUX9cJABg ==、OJF6H4KdxFLgLu + oTDNFodCEfMA =

このようなものをCSVファイルにダンプし、パスワードを次の形式で保存するDjangoで使用可能な形式にしようとしています。

[algo] $ [salt] $ [hash]

ここで、saltはプレーンな文字列であり、ハッシュはSHA1ハッシュの16進ダイジェストです。

これまでのところ、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())

誰かが私のアプローチの欠陥を見ることができるか、または別の方法を提案できるかどうか疑問に思っています。おそらく、上記のアルゴリズムと上記の既知のパスワードとソルトを使用して、システムでハッシュを生成できますか?

4

2 に答える 2

8

UTF16 文字列をバイナリに変換するときに、Python がバイト オーダー マーカーを挿入しているようです。.NET バイト配列には BOM が含まれていないため、UTF16 を 16 進数に変換し、最初の 4 文字を削除してバイナリにデコードするゲットー python を実行しました。

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())
于 2008-11-06T22:57:12.407 に答える
0

何がうまくいかないのかについての2つの考え。

まず、リフレクションからのコードには 3 つのパスがあります。

  • passwordFormat が 0 の場合、パスワードをそのまま返します。
  • passwordFormat が 1 の場合、Python コードと同様にハッシュが作成されます。
  • passwordFormat が 0 または 1 以外の場合は、this.EncryptPassword() を呼び出します。

パスワードをハッシュしていて、this.EncryptPassword() でパスワードを暗号化していないことをどのように確認できますか? EncryptPassword() メンバー関数を逆にして、それを複製する必要がある場合があります。これは、パスワードをハッシュして暗号化していないことを保証する情報がない限りです。

次に、実際にパスワードをハッシュしている場合は、次のようなものが返される可能性があるため、文字列「password」に対して Encoding.Unicode.GetBytes() 関数が返すものを確認したい場合があります。

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

それ以外の:

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

これが役立つことを願っています。

于 2008-11-06T19:06:58.817 に答える