产生短哈希的哈希函数?

问题描述 投票:71回答:9

有没有一种加密方式可以采用任意长度的字符串并产生一个10字符以下的哈希?我想生成合理的唯一ID,但是基于消息内容,而不是随机的。

但是,如果不能使用任意长度的字符串,我可以将消息约束为整数值。但是,在这种情况下,对于两个连续的整数,散列必须不相似。

encryption uniqueidentifier
9个回答
63
投票

您可以使用任何常用的哈希算法(例如SHA-1),这会给您一个比您需要的结果略长的结果。只需将结果截断为所需的长度,这可能足够好。

例如,在Python中:

>>> import hashlib
>>> hash = hashlib.sha1("my message".encode("UTF-8")).hexdigest()
>>> hash
'104ab42f1193c336aa2cf08a2c946d5c6fd0fcdb'
>>> hash[:10]
'104ab42f11'

35
投票

如果你不需要一个强有力的反对故意修改的算法,我发现了一个名为adler32的算法,可以产生相当短的(~8个字符)结果。从下拉列表中选择它以试用它:

http://www.sha1-online.com/


10
投票

您需要散列内容以提供摘要。有许多哈希可用,但结果集中10个字符非常小。回过头来,人们使用CRC-32,它产生33位散列(基本上是4个字符加1位)。还有CRC-64产生65位散列。产生128位散列(16字节/字符)的MD5因加密目的而被视为已损坏,因为可以找到具有相同散列的两条消息。不用说,任何时候你从任意长度的消息中创建一个16字节的摘要,你最终会得到重复。摘要越短,碰撞的风险就越大。

但是,对于两个连续消息(无论是否为整数),散列不相似的问题应该适用于所有散列。即使原始消息中的单个位改变也应该产生截然不同的结果摘要。

因此,使用像CRC-64(以及结果的基础64)这样的东西可以让你进入你正在寻找的邻居。


6
投票

您可以使用现有的哈希算法来生成短的内容,例如MD5(128位)或SHA1(160)。然后,您可以通过将摘要的部分与其他部分进行异或来进一步缩短。这将增加碰撞的机会,但不会像简单地截断摘要那样糟糕。

此外,您可以将原始数据的长度作为结果的一部分,以使其更加独特。例如,使用后半部分对MD5摘要的前半部分进行异或将导致64位。为数据长度添加32位(如果知道长度总是适合更少的位,则更低)。这将导致96位(12字节)结果,然后您可以将其转换为24个字符的十六进制字符串。或者,您可以使用base 64编码使其更短。


6
投票

只是总结一个对我有帮助的答案(注意@ erasgreenunk关于使用base-64编码的评论)。我的目标是拥有一个大多数独特的短字符串......

我不是专家,所以如果它有任何明显的错误,请更正此问题(在Python中再次像接受的答案一样):

import base64
import hashlib
import uuid

unique_id = uuid.uuid4()
# unique_id = UUID('8da617a7-0bd6-4cce-ae49-5d31f2a5a35f')

hash = hashlib.sha1(str(unique_id).encode("UTF-8"))
# hash.hexdigest() = '882efb0f24a03938e5898aa6b69df2038a2c3f0e'

result = base64.b64encode(hash.digest())
# result = b'iC77DySgOTjliYqmtp3yA4osPw4='

这里的result使用的不仅仅是十六进制字符(如果你使用hash.hexdigest()你会得到的)因此它不太可能发生碰撞(也就是说,截断比十六进制摘要更安全)。

注意:使用UUID4(随机)。有关其他类型,请参阅http://en.wikipedia.org/wiki/Universally_unique_identifier


3
投票

如果你需要"sub-10-character hash",你可以使用Fletcher-32算法,它产生8个字符的散列(32位),CRC-32或Adler-32。

CRC-32比Adler32慢20%-100%。

Fletcher-32比Adler-32略微可靠。它的计算成本低于Adler校验和:Fletcher vs Adler comparison

下面给出了一个带有一些Fletcher实现的示例程序:

    #include <stdio.h>
    #include <string.h>
    #include <stdint.h> // for uint32_t

    uint32_t fletcher32_1(const uint16_t *data, size_t len)
    {
            uint32_t c0, c1;
            unsigned int i;

            for (c0 = c1 = 0; len >= 360; len -= 360) {
                    for (i = 0; i < 360; ++i) {
                            c0 = c0 + *data++;
                            c1 = c1 + c0;
                    }
                    c0 = c0 % 65535;
                    c1 = c1 % 65535;
            }
            for (i = 0; i < len; ++i) {
                    c0 = c0 + *data++;
                    c1 = c1 + c0;
            }
            c0 = c0 % 65535;
            c1 = c1 % 65535;
            return (c1 << 16 | c0);
    }

    uint32_t fletcher32_2(const uint16_t *data, size_t l)
    {
        uint32_t sum1 = 0xffff, sum2 = 0xffff;

        while (l) {
            unsigned tlen = l > 359 ? 359 : l;
            l -= tlen;
            do {
                sum2 += sum1 += *data++;
            } while (--tlen);
            sum1 = (sum1 & 0xffff) + (sum1 >> 16);
            sum2 = (sum2 & 0xffff) + (sum2 >> 16);
        }
        /* Second reduction step to reduce sums to 16 bits */
        sum1 = (sum1 & 0xffff) + (sum1 >> 16);
        sum2 = (sum2 & 0xffff) + (sum2 >> 16);
        return (sum2 << 16) | sum1;
    }

    int main()
    {
        char *str1 = "abcde";  
        char *str2 = "abcdef";

        size_t len1 = (strlen(str1)+1) / 2; //  '\0' will be used for padding 
        size_t len2 = (strlen(str2)+1) / 2; // 

        uint32_t f1 = fletcher32_1(str1,  len1);
        uint32_t f2 = fletcher32_2(str1,  len1);

        printf("%u %X \n",    f1,f1);
        printf("%u %X \n\n",  f2,f2);

        f1 = fletcher32_1(str2,  len2);
        f2 = fletcher32_2(str2,  len2);

        printf("%u %X \n",f1,f1);
        printf("%u %X \n",f2,f2);

        return 0;
    }

输出:

4031760169 F04FC729                                                                                                                                                                                                                              
4031760169 F04FC729                                                                                                                                                                                                                              

1448095018 56502D2A                                                                                                                                                                                                                              
1448095018 56502D2A                                                                                                                                                                                                                              

同意Test vectors

"abcde"  -> 4031760169 (0xF04FC729)
"abcdef" -> 1448095018 (0x56502D2A)

Adler-32对于具有几百个字节的短消息具有弱点,因为这些消息的校验和对32个可用位的覆盖率较差。检查一下:

The Adler32 algorithm is not complex enough to compete with comparable checksums


2
投票

您可以使用具有PHP,Javascript,Python等实现的哈希库。有关详细信息,请查看this link


0
投票

只需在终端(在MacOS或Linux上)运行:

crc32 <(echo "some string")

8个字符长。


-1
投票

我最近需要一些简单的字符串缩减功能。基本上,代码看起来像这样(前面的C / C ++代码):

size_t ReduceString(char *Dest, size_t DestSize, const char *Src, size_t SrcSize, bool Normalize)
{
    size_t x, x2 = 0, z = 0;

    memset(Dest, 0, DestSize);

    for (x = 0; x < SrcSize; x++)
    {
        Dest[x2] = (char)(((unsigned int)(unsigned char)Dest[x2]) * 37 + ((unsigned int)(unsigned char)Src[x]));
        x2++;

        if (x2 == DestSize - 1)
        {
            x2 = 0;
            z++;
        }
    }

    // Normalize the alphabet if it looped.
    if (z && Normalize)
    {
        unsigned char TempChr;
        y = (z > 1 ? DestSize - 1 : x2);
        for (x = 1; x < y; x++)
        {
            TempChr = ((unsigned char)Dest[x]) & 0x3F;

            if (TempChr < 10)  TempChr += '0';
            else if (TempChr < 36)  TempChr = TempChr - 10 + 'A';
            else if (TempChr < 62)  TempChr = TempChr - 36 + 'a';
            else if (TempChr == 62)  TempChr = '_';
            else  TempChr = '-';

            Dest[x] = (char)TempChr;
        }
    }

    return (SrcSize < DestSize ? SrcSize : DestSize);
}

它可能比可能需要的更多冲突,但它不打算用作加密哈希函数。如果碰撞太多,您可以尝试各种乘数(即将37更改为另一个素数)。这个片段的一个有趣特性是,当Src比Dest短时,Dest会以输入字符串结束(0 * 37 + value = value)。如果您希望在过程结束时“可读”某些内容,则Normalize将以增加冲突为代价调整转换后的字节。

资源:

https://github.com/cubiclesoft/cross-platform-cpp/blob/master/sync/sync_util.cpp

© www.soinside.com 2019 - 2024. All rights reserved.