17

「英数字ハッシュ」を生成する関数を探しています。ソース文字列を指定すると、任意の文字 a ~ z または数字 0 ~ 9 を含む確定結果文字列が生成され、ソースを生成するためにリバース エンジニアリングすることはできません。これは、秘密データに基づいてシステムのパスワードを生成するために使用されるため、8 ~ 12 文字の文字列が理想的であり、安全なハッシュも理想的です。

通常のビットごとのハッシュを使用して、それを 64 ビットに XOR フォールドし (たとえば SHA256 を使用する場合)、一度に 5 ビットの結果を取得し (数値 0-31 を生成)、ルックアップできると考えています。インデックス付きの順序付きコレクションから使用する文字コード。26 文字と 10 桁の数字があるため、一部を省略しなければなりません (おそらく、手書きの場合に他の文字と間違えられる可能性のある文字を削除するため)。64 ビット、一度に 5 ビット、残りの 4 ビットで 12 文字の文字列が生成されます。

ただし、2 つの点が心配です。1 つ目は、2 のべき乗でないビット数を使用することによるバイアスの導入です。次に、残ったビットをどうするかです。16 の可能性しかないことを知ってそのまま使用するか、それらを除外しますか (そして、データが失われて偏りが生じる可能性があります)、またはもう 1 ビットを組み込んで 13 文字の文字列を作成しますか (最後のビットはどこに置くべきか)から来る)?

編集:これが私の現在の刺し傷です。列挙可能なバイト (ほとんどのハッシュ アルゴリズムで生成されるバイト配列と同様) を取り、文字列を返します。

    /// <summary>
    /// Converts an IEnumerable of bytes to a string representation which can have any lowercase letter a-z except for l, o, q and z, and any digit 0-9.
    /// Uses 5 bits of the byte array at a time to generate numbers from 0 to 31, which are then translated to letters or numbers.
    /// </summary>
    /// <param name="toConvert">the byte array to convert.</param>
    /// <returns>A string containing the alphanumeric case-insensitive representation of the bytes in the array.</returns>
    public static string ToInsensitiveAlphaNumericString(this IEnumerable<byte> toConvert)
    {
        var chars = new[]
                        {
                            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'r', 's', 't',
                            'u', 'v', 'w', 'x', 'y', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
                        };

        var enumerator = toConvert.GetEnumerator();
        enumerator.MoveNext();

        int buffer = enumerator.Current;
        short bufferLength = 8;
        const int valueLength = 5;

        var builder = new StringBuilder();

        while (true)
        {
            var value = buffer >> (bufferLength - valueLength);

            builder.Append(chars[value]);

            buffer = buffer - (value << (bufferLength - valueLength));
            bufferLength -= valueLength;

            if(bufferLength < valueLength )
            {
                if (enumerator.MoveNext())
                {
                    buffer = (buffer << 8) + enumerator.Current;
                    bufferLength += 8;
                }
                else
                {
                    //here's the main question; to include, or not to include?
                    if (bufferLength > 0)
                        builder.Append(chars[buffer]);
                    break;
                }
            }
        }

        return builder.ToString();
    }
4

2 に答える 2

16

SHA256 を生成してから、結果をBase36でエンコードするのはどうですか? 残りビットなし、バイアスなし...

そうすれば、必要な英数字表現とともに、実績のあるアルゴリズムの暗号強度 (複数のハッシュ反復をソルトして使用することを忘れないでください) を得ることができます。

于 2012-07-27T01:09:18.380 に答える
0

これらのビットをそのまま使用する場合 (1 文字の可能性が 16 のみになるように)、完全な 64 ビットのエントロピーが得られます。64 ビットのエントロピーに満足している場合 (そう思われるかもしれません)、1 つの文字の範囲が制限されていることを気にする必要はありません。

なんらかの理由 (美学?) があり、すべての文字が全範囲を使用することを好む場合は、それらの 4 ビットを削除できますが、エントロピーを 60 ビットにまで下げることになります。8 文字のパスワードで満足するなら、60 ビットでも十分に思えます。

したがって、どちらが簡単でもうまくいくはずです。

于 2012-07-27T01:15:30.080 に答える