0

オブジェクトのコレクションがあり、このオブジェクトのコレクションから (SHA256 を使用して) ハッシュ値を生成したいと考えています。

これらのオブジェクトをハッシュ化するこのプロセスは、ゼロ知識証明システムの一部であり、証明者が証明を生成し、後で検証者によって検証されます。この証明は、実際にはハッシュ関数の出力です。

これらのオブジェクトにはすべて、3 つまたは 4 つの大きな BigInteger 値 (2048 ビットのオーダー) が含まれています。オブジェクトの数は可変ですが、4 ~ 10 の間になります。

可変数のオブジェクトからハッシュ値を生成するための次のメソッドを作成しました。

public byte[] buildHashFromHashcodes(final Object... listOfObjects) {

    for (Object obj : listOfObjects) {

        if (obj == null) {
            throw new Exception(
                "Input objects cannot be null");
        }

        _md.update(intToBytes(obj.hashCode()));
    }

    return _md.digest();
}

private byte[] intToBytes(final int intValue) {
    return new byte[] {(byte) (intValue >> 24),
            (byte) (intValue >> 16), (byte) (intValue >> 8),
            (byte) intValue };
}

私の質問は、このコードでの hashCode メソッドの使用に関連しています。具体的には、 hashCode メソッドの使用がシステムのセキュリティを弱めるかどうかを判断しようとしています.32ビットの数値しか生成しないため、各反復中にハッシュは32ビットの情報でのみ更新されます. したがって、プロセスのこの時点でのこの情報の損失がシステムを本当に弱体化させるかどうかはわかりません.

これらのオブジェクトの hashCode メソッドの実装では、大きな BigInteger 値を使用してハッシュ コードを生成しますが、数値は返される前に int に切り捨てられます。

私の懸念の一部は、一部のオブジェクトのハッシュ コード間で衝突が発生する可能性が比較的高いという事実から生じます。しかし、繰り返しますが、ハッシュはループ内で数回更新されるため、1 回の衝突は大きな問題にはなりません。

オブジェクトのコレクションに 4 つのオブジェクトがあったとします。ループの最初の繰り返しでは、ハッシュの更新に 32 ビットが使用され、2 回目の繰り返しでは別の 32 ビットがハッシュの更新に使用されます。

updateメソッドが呼び出された後にハッシュアルゴリズムが実行されることは私の理解です。128 ビット (4 つのオブジェクト) がバッファに格納され、それらの 128 ビットを入力として使用してハッシュ アルゴリズムが実行されるわけではありません。

したがって、最終更新後のハッシュの状態の総数は (2^32) * (2^32) * (2^32) * (2^32) と言えますか? (実際には、いくつかのポイントで切り捨てられるため、これはもちろん発生しません)。

各反復中に update メソッドが呼び出されるという事実を考えると、 hashCode の使用は安全なアプローチであると私は信じています。

オブジェクト間の衝突のリスクを回避するための代替アプローチは、各オブジェクトの toString() メソッドを使用することです。これは、各オブジェクトのエントロピーの全量を含む文字列を返します (大きな BigInteger 数値の値は文字列)。これは、ループの各反復中にハッシュがより多くの情報で更新されることを意味しますが、これが必要かどうかはわかりません。

それで、私の質問は、このコードで hashCode メソッドを使用すると、システムの強度が弱まるのでしょうか?

4

2 に答える 2

7

これはひどい考えです。暗号化ハッシュ関数の目的は、すべての入力ビットがすべての出力ビットに影響するように、入力データを完全に混合することです。

中間hashCodeの s を導入することで、各入力BigIntegerが 1 つの 32 ビット hashCode にのみ影響を与える機会を持つようにします。したがって、単一の 32 ビット hashCode で衝突が発生すると、最終的な hash で完全な衝突が発生します

したがって、攻撃者はスキームを攻撃するために、入力 BigInteger オブジェクトの1 つと同じ hashCode を持つ BigInteger を見つけるだけで済みます。これは完全に安全ではありません。

于 2014-10-02T18:51:12.837 に答える
1

呼び出しの代わりにすべきことはhashCode、それ自体で衝突が発生するため、標準エンコーディングをバイト単位でハッシュすることです。BigIntegerただし、各数値にはバイト配列として独自のエンコードがあります。ただし、すべてのオブジェクトがそのような正規エンコーディングを持っているわけではないため、そのためのジェネリック メソッドを作成することはできません。

さらに、値を別々に保つ方法も必要です (たとえば、11 は 1 と 1 の連結、または数値 11 である可能性があります)。最も簡単な方法は、値のサイズを値の前に付けることです。

public static byte[] buildHashFromSeparatedCanonicalValues(final BigInteger ... numbers) {
    MessageDigest md;
    try {
        md = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e) {
        throw new IllegalStateException("SHA-256 should always be available", e);
    }

    final ByteBuffer lengthBuffer = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
    for (BigInteger number : numbers) {

        if (number == null) {
            throw new IllegalArgumentException(
                "Input objects cannot be null");
        }

        final byte[] encodedNumber = number.toByteArray();
        lengthBuffer.putInt(encodedNumber.length);
        lengthBuffer.flip();
        md.update(lengthBuffer);
        lengthBuffer.clear();
        md.update(encodedNumber);
    }

    return md.digest();
}

これはBigInteger値に固有です。オブジェクト ( を実装する) をシリアル化することで、これをより一般的なものにすることができますがSerializable、シリアル化の落とし穴に注意してください。

于 2014-10-03T02:20:23.370 に答える