产生短哈希的哈希函数?

时间:2010-12-30 23:32:30

标签: encryption uniqueidentifier

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

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

10 个答案:

答案 0 :(得分:62)

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

例如,在Python中:

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

答案 1 :(得分:34)

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

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

答案 2 :(得分:10)

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

但是,你担心两个连续消息(无论是否为整数)的散列不相似应该对所有散列都是真的。即使原始消息中的单个位更改也会产生截然不同的结果摘要。

所以,使用像CRC-64这样的东西(以及结果的基础-64')可以让你进入你正在寻找的社区。

答案 3 :(得分:6)

您可以将hashlib库用于Python。 shake_128 shake_256 算法提供了可变长度的哈希。这是一些工作代码(Python3):

import hashlib
>>> my_string = 'hello shake'
>>> hashlib.shake_256(my_string.encode()).hexdigest(5)
'34177f6a0a'

请注意,使用长度参数 x (例如5),该函数将返回长度为 2x 的哈希值。

答案 4 :(得分:5)

总结一个对我有帮助的答案(注意@ 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

答案 5 :(得分: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

答案 6 :(得分:2)

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

答案 7 :(得分:0)

只需在终端(在MacOS或Linux上)上运行此程序即可:

ProcessInfo.processInfo.environment["SKIP_VERIFICATION"]

8个字符长。

答案 8 :(得分:0)

现在是2019年,还有更好的选择。即xxhash

~ echo test | xxhsum                                                           
2d7f1808da1fa63c  stdin

答案 9 :(得分:-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