【问题标题】:"Alphanumeric" hash - A-Z, 0-9“字母数字”哈希 - A-Z、0-9
【发布时间】:2012-07-25 16:21:45
【问题描述】:

我正在寻找一个可以生成“字母数字哈希”的函数。给定一个源字符串,它会生成一个确定的结果字符串,该字符串可以包含任何字母 a-z 或数字 0-9,并且不能通过逆向工程来生成源。这将用于为基于机密数据的系统生成密码,因此 8 到 12 个字符之间的字符串是理想的,安全哈希也是理想的。

我想我可以使用普通的按位散列,将其异或折叠为 64 位(例如,如果我使用 SHA256),然后一次取 5 位的结果(产生一个数字 0-31)并从索引有序集合中查找要使用的字符代码。有 26 个字母和 10 位数字,这意味着我必须省略一些(可能会删除如果手写可能会被误认为其他字符的字符)。 64 位,每次 5 位,将产生一个 12 字符的字符串,剩下 4 位。

但是,我担心两件事:首先,通过采用非 2 的位数来引入偏差;其次,如何处理剩余的位。我是按原样使用它们,知道只有 16 种可能性,我是不使用它们(并丢失可能引入偏差的数据),还是我再合并一个位来制作一个 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();
    }

【问题讨论】:

    标签: language-agnostic hash alphanumeric


    【解决方案1】:

    如何生成您的 SHA256,然后对结果进行Base36 编码?没有剩余的位,没有偏见......

    这样您就拥有了经过验证的算法的加密强度(记得加盐并使用多次哈希迭代)以及您需要的字母数字表示。

    【讨论】:

    • 如果您只是想伪装您用于散列的系统并且不希望结果很容易被散列函数的输出逆转,只需执行此操作并对其应用凯撒移位 -简单,古老,但仍然可以给事情带来有趣的转折:)
    • 这个解决方案可以正常工作,但值得注意的是仍然存在偏见。如果 2^{256} 的 base-36 表示形式的第一个数字为 6(我认为确实如此,但我只是草率地检查了),那么每个编码值在该位置的值都将介于 0 和 6 之间。跨度>
    • @David:你会有角色位置的偏差,但这没关系。 Base36 只是一个完全无偏的 256 位数字的人类方便的表示
    • 是的,我完全同意。我刚刚提到它是因为 OP 提到了对有偏见的字符的担忧(当他已经在谈论一个完全无偏见的 64 位数字的人类方便表示时)。
    • 这是个好主意,在 64 位数字上微不足道。存储在多个字节中的数字稍微复杂一些,但仍然完全有可能。
    【解决方案2】:

    如果你只是按原样使用这些位(这样一个字符只有 16 种可能性),你仍然拥有完整的 64 位熵。如果您对 64 位熵感到满意(听起来确实如此),那么没有理由介意一个字符的范围有限。

    如果您有某种理由(美学?)更喜欢所有字符都具有完整范围,那么您可以删除这 4 位,但您会将自己的熵降低到 60 位。如果您对 8 个字符的密码感到满意,那么听起来 60 位也足够了。

    因此,无论哪个更容易,都应该可以正常工作。

    【讨论】:

      猜你喜欢
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-11
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      • 1970-01-01
      相关资源
      最近更新 更多