11

異なるコンピューターで異なるハッシュ値を返す MessageDigest に問題があります。

1 台のコンピュータは Windows Vista で 32 ビット Java を実行しており、もう 1 台は Mac OS で 64 ビット Java を実行しています。MessageDigest がマシンに依存しているためなのか、それともどこかで文字エンコーディングを明示的に指定する必要があるのか​​ 、それともおそらく何か他のものなのかはわかりません。コードは次のとおりです。

public static boolean authenticate(String salt, String encryptedPassword, 
    char[] plainTextPassword ) throws NoSuchAlgorithmException {

    // do I need to explcitly specify character encoding here? -->
    String saltPlusPlainTextPassword = salt + new String(plainTextPassword);

    MessageDigest sha = MessageDigest.getInstance("SHA-512");

    // is this machine dependent? -->
    sha.update(saltPlusPlainTextPassword.getBytes());
    byte[] hashedByteArray = sha.digest();

    // or... perhaps theres a translation problem here? -->
    String hashed = new String(hashedByteArray);

    return hashed.equals(encryptedPassword);
}

このコードは、これら 2 つの異なるマシンで異なる方法で実行する必要がありますか? 私が書いたようにマシンに依存している場合、これらのパスワードをより移植性の高い方法でハッシュする別の方法はありますか? ありがとう!

編集:::::

これは、ソルトを生成するために使用しているコードです。

public static String getSalt() {
   int size = 16;
   byte[] bytes = new byte[size];
   new Random().nextBytes(bytes);
   return org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(bytes);
}

解決:::

受け入れられた解決策のおかげで、コードを修正できました。

public static boolean authenticate_(String salt, String encryptedPassword, 
        char[] plainTextPassword ) throws NoSuchAlgorithmException, UnsupportedEncodingException {

        // This was ok
        String saltPlusPlainTextPassword = salt + new String(plainTextPassword);    

        MessageDigest sha = MessageDigest.getInstance("SHA-512");

        // must specify "UTF-8" encoding
        sha.update(saltPlusPlainTextPassword.getBytes("UTF-8"));
        byte[] hashedByteArray = sha.digest();

        // Use Base64 encoding here -->
        String hashed = org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(hashedByteArray);

        return hashed.equals(encryptedPassword);
    }
4

2 に答える 2

18

エンコーディングが問題を引き起こしています。まずここ:

saltPlusPlainTextPassword.getBytes()

これにより、マシンのデフォルトのエンコーディングが使用されます。悪いアイデア。簡単な解決策として「UTF-8」を指定します。(存在することが保証されています。)

次に、これにより問題が発生します。

String hashed = new String(hashedByteArray);

hashedByteArray任意のバイナリデータです。安全にテキストに変換するには、base-64 エンコーディングまたは 16 進数のみを使用してください。繰り返しますが、現在はデフォルトのエンコーディングを使用していますが、これはマシンによって異なります。Java には、base64 エンコーディング用のサードパーティ ライブラリが多数あります。

于 2010-06-19T21:07:12.053 に答える
5

上記の Jon Skeet の解決策が原因である可能性が高く、彼の推奨事項を確実に考慮に入れる必要がありますが、別の考えられる原因は塩の誤解です。

Salt は、ハッシュの前に String に適用される半秘密のランダム値です。これにより、元の String が何であったかを推測しようとするときにブルート フォース攻撃を実行することが難しくなります。

一般に、ソルト値はインストールごとに異なります。実際の原因は、さまざまなマシンでソルト値が異なるように設定されていることだけである可能性があります。

于 2010-06-19T21:11:40.500 に答える