1

Oracle11gを使用するJava/SpringベースのWebアプリケーションがあります。現在、ユーザーはログイン時にシステムテーブルに対して直接ユーザー名/パスワードを介して認証SYS.USER$します。

これは変更する必要があるため、すべてのユーザーデータを格納するための(通常の)新しいテーブルを作成しました。新しく作成したテーブルに既存のすべてのパスワードを挿入しました。ただし、パスワードはこのサイトで説明されている方法で暗号化/ハッシュ化されているようです

一例:ユーザーがを入力するXXXXXと、データベースはを保存し07E4898C06DEF253ます。

新しい(通常の)テーブルに保存されている古いパスワードを使用して認証を実行したい。私の問題は、既存のパスワードがどのようにハッシュ/暗号化されているか正確にわからないため、既存のパスワードを確認する方法がわからないことです。

ora_hashdbms_obfuscation_toolkit.DESDecryptをいじってみましたが、どれも正しい結果が得られませんでした。ユーザーの正しいパスワードを知っていて、このパスワードに対してOracleが生成した値を確認できますが、Oracleがパスワードデータを一般的に「処理」する方法を再現できません。

すべてのパスワードをリセットせずにこの問題を解決する方法はありますか?

4

1 に答える 1

1

コメントでリンクしたJava実装を適応させます。これは近いですが、saltを適切に使用していません。

import java.security.MessageDigest;
import java.util.Formatter;

class Main{

    public static String calculateHash(String password) throws Exception{
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");

        String encodedPassword = "S:71752CE0530476A8B2E0DD218AE59CB71B211D7E1DB70EE23BFB23BDFD48";

        // Convert password to bytes
        byte[] bPassword = password.getBytes("UTF-8");

        // Get salt from encoded password
        String salt = encodedPassword.substring(42, 62);
        System.out.println("Salt is " + salt);

        // Convert salt from hex back to bytes
        // based on http://stackoverflow.com/a/140861/266304
        int len = salt.length();
        byte[] bSalt = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            bSalt[i / 2] = (byte) ((Character.digit(salt.charAt(i), 16) << 4)
                + Character.digit(salt.charAt(i+1), 16));
        }

        // Add converted salt to password bytes
        // based on http://stackoverflow.com/a/80503/266304
        byte[] bData = new byte[bPassword.length + bSalt.length];
        System.arraycopy(bPassword, 0, bData, 0, bPassword.length);
        System.arraycopy(bSalt, 0, bData, bPassword.length, bSalt.length);

        // Hash the final byte array
        crypt.update(bData);
        byte bHash[] = crypt.digest();

        Formatter formatter = new Formatter();
        for (byte b : bHash)
        {
            formatter.format("%02x", b);
        }

        System.out.println("Expected      " + encodedPassword.substring(2,42));

        return formatter.toString().toUpperCase();
    }

    public static void main(String[] args) throws Exception {
        System.out.println("The result is " + calculateHash("ZK3002"));
    }
}

これは出力を与えます:

Salt is 1DB70EE23BFB23BDFD48
Expected      71752CE0530476A8B2E0DD218AE59CB71B211D7E
The result is 71752CE0530476A8B2E0DD218AE59CB71B211D7E

PL/SQLバージョンにはいくつかの変換が含まれます。dbms_crypto.hash()引数を取るRAWので、プレーンテキストのパスワードをに変換してからRAW、抽出されたソルトを連結する必要があります。これはすでに16進数です。(PeteFinniganのブログのPL/ SQLバージョンでは、彼が明示的なhextoraw呼び出しを行っていることに気付くかもしれません。そのため、少し単純化しています)。したがって、この例で渡される引数は、dbms_crypto.hashに相当する16進数(OK、raw)になりますZK3002。これは5A4B33303032、16進数のソルトが連結されたものです。そう5A4B333030321DB70EE23BFB23BDFD48

Javaバージョンの場合、バイト配列を渡しますが、これは、保存されているパスワードから抽出されたソルトを、パスワードに追加する前に16進数から変換する必要があることを意味します。また、有用な文字列表現がない可能性が高いため、バイト配列に直接配置することもできます。したがって、パスワードをバイト配列に変換し、ソルトをバイト配列に変換して、2つの配列を結合します。これが、に渡す値になりますMessageDigest

これが生成するハッシュをOracleハッシュバージョンと比較できます。最初S:のソルトと埋め込まれたソルトはスキップします。

于 2012-08-08T08:37:52.767 に答える