짧은 해시를 생성하는 해시 함수?


98

임의의 길이의 문자열을 가져 와서 10 자 이하의 해시를 생성 할 수있는 암호화 방법이 있습니까? 무작위가 아닌 메시지 내용을 기반으로 합리적으로 고유 한 ID를 생성하고 싶습니다.

그러나 임의 길이 문자열이 불가능한 경우 메시지를 정수 값으로 제한하여 살 수 있습니다. 그러나이 경우 해시는 두 개의 연속 정수에 대해 유사하지 않아야합니다.


그것을 해시라고합니다. 독특하지 않을 것입니다.
SLaks

1
이것은 또한 해시 자르기 문제이므로 stackoverflow.com/q/4784335
Peter Krauss

2
참고로, Wikipedia 의 해시 함수 목록을 참조하십시오 .
Basil Bourque

답변:


78

일반적으로 사용 가능한 해시 알고리즘 (예 : SHA-1)을 사용하면 필요한 것보다 약간 더 긴 결과를 얻을 수 있습니다. 결과를 원하는 길이로 자르기 만하면 충분할 수 있습니다.

예를 들어 Python에서 :

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

3
적절한 해시 함수는 잘릴 수 있습니다.
James K. Polk 회장

89
이것이 충돌 위험을 훨씬 더 높이 지 않을까요?
가브리엘 Sanmartin

143
@erasmospunk : 64 기수로 인코딩하는 것은, 충돌 저항 아무것도하지 않기 때문에 경우 hash(a)와 충돌 hash(b)base64(hash(a))와도 충돌한다 base64(hash(b)).
Greg Hewgill 2013

56
@GregHewgill 당신 말이 맞지만 우리는 원래의 해시 알고리즘 충돌에 대해 말하고 있지 않습니다 (예, sha1충돌하지만 이것은 또 다른 이야기입니다). 10 자 해시가있는 경우 base64vs base16(또는 16 진수)로 인코딩하면 더 높은 엔트로피를 얻게 됩니다. 얼마나 높습니까? 와 base16함께, 문자 당 정보의 4 개 비트를 얻을 base64이 그림은 6bits / 문자입니다. 총 10 자 "hex"해시는 40 비트의 엔트로피를 가지며 base64는 60 비트입니다. 그래서 약간 더 저항력 이 있습니다 .
John L. Jegutanis 2013

20
@erasmospunk : 오, 무슨 뜻인지 알겠습니다. 결과에 대한 고정 크기가 제한되어 있다면 base64 인코딩과 16 진수 인코딩으로 더 중요한 비트를 압축 할 수 있습니다.
Greg Hewgill 2013

46

의도적 인 수정에 대해 강력한 알고리즘이 필요하지 않은 경우 꽤 짧은 (~ 8 자) 결과를 생성하는 adler32 라는 알고리즘을 찾았습니다 . 여기 드롭 다운에서 선택하여 사용해보세요.

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


2
아주 오래 됐고 신뢰할 수 없습니다.
Mascarpone

1
@Mascarpone "매우 신뢰할 수 없음"-소스? 한계가 있습니다. 당신이 그것을 안다면 그것이 얼마나 오래되었는지는 중요하지 않습니다.
BT

8
@Mascarpone "약점 감소"-다시, 어떤 약점? 이 알고리즘이 OP 사용에 100 % 완벽하지 않은 이유는 무엇입니까?
BT

3
@Mascarpone OP는 암호 등급 해시를 원한다고 말하지 않습니다. OTOH, Adler32는 해시가 아닌 체크섬이므로 OP가 실제로 수행하는 작업에 따라 적합하지 않을 수 있습니다.
PM 2Ring

2
Adler32에는 한 가지주의 할 점이 있습니다. Wikipedia를 인용하면 다음과 같습니다. Adler-32는 수백 바이트의 짧은 메시지에 대해 약점이 있습니다. 이러한 메시지에 대한 체크섬은 사용 가능한 32 비트의 범위가 좋지 않기 때문입니다.
Basil Bourque

13

다이제스트를 만들려면 콘텐츠를 해시해야합니다. 많은 해시를 사용할 수 있지만 결과 집합에 대해 10 개의 문자는 매우 작습니다. 과거에 사람들은 33 비트 해시 (기본적으로 4 자 + 1 비트)를 생성하는 CRC-32를 사용했습니다. 65 비트 해시를 생성하는 CRC-64도 있습니다. 128 비트 해시 (16 바이트 / 문자)를 생성하는 MD5는 동일한 해시를 가진 두 개의 메시지를 찾을 수 있기 때문에 암호화 목적으로 손상된 것으로 간주됩니다. 임의의 길이의 메시지에서 16 바이트 다이제스트를 만들 때마다 중복으로 끝날 것이라는 것은 말할 필요도 없습니다. 다이제스트가 짧을수록 충돌 위험이 커집니다.

그러나 두 개의 연속 메시지 (정수 여부에 관계없이)에 대해 해시가 유사하지 않다는 우려는 모든 해시에서 참이어야합니다. 원본 메시지에서 한 비트 만 변경해도 매우 다른 결과 다이제스트가 생성됩니다.

따라서 CRC-64와 같은 것을 사용하면 (그리고 결과는 base-64'ing) 당신이 찾고있는 이웃에 도착할 것입니다.


1
SHA-1 해시를 CRC하고 결과를 base-64로 처리하면 결과 ID가 충돌에 더 강합니까?

5
"그러나 두 개의 연속 메시지에 대해 해시가 유사하지 않다는 우려는 [...] 모든 해시에 대해 참이어야합니다." -반드시 사실은 아닙니다. 예를 들어, 클러스터링 또는 클론 감지에 사용되는 해시 함수의 경우 실제로는 정반대입니다. 유사한 문서가 유사한 (또는 동일한) 해시 값을 생성하기 를 원합니다 . 유사한 입력에 대해 동일한 값을 생성하도록 특별히 설계된 해시 알고리즘의 잘 알려진 예 는 Soundex입니다.
Jörg W Mittag

메시지의 서명을 인증하기 위해 해시를 사용하고 있습니다. 따라서 기본적으로 알려진 메시지 및 지정된 서명의 경우 해시가 정확해야합니다. 하지만 오탐의 비율이 적더라도 상관 없습니다. 완전히 받아 들일 수 있습니다. 저는 현재 편의를 위해 base62로 압축 된 잘린 SHA-512 해시 (빠르게 정리 한 것)를 사용합니다.

@ JörgWMittag SoundEx에 대한 훌륭한 포인트입니다. 나는 바로 잡았다. 모든 해시가 동일한 특성을 갖는 것은 아닙니다 .

12

나에게 도움이 된 답변을 요약하면 (base-64 인코딩 사용에 대한 @erasmospunk의 의견에 주목). 내 목표는 대부분 고유 한 짧은 문자열을 갖는 것이 었습니다 .

나는 전문가가 아니므로 눈에 띄는 오류가 있으면 수정하십시오 (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 를 참조하십시오 .


7

MD5 (128 비트) 또는 SHA1 (160)과 같이 짧은 것을 생성하는 기존 해시 알고리즘을 사용할 수 있습니다. 그런 다음 다이제스트 섹션을 다른 섹션과 XORing하여 더 짧게 만들 수 있습니다. 이것은 충돌 가능성을 증가 시키지만 단순히 다이제스트를 자르는 것만 큼 나쁘지는 않습니다.

또한 결과의 일부로 원본 데이터의 길이를 포함하여 더 고유하게 만들 수 있습니다. 예를 들어, MD5 다이제스트의 전반을 후반과 XOR하면 64 비트가됩니다. 데이터 길이에 대해 32 비트를 추가합니다 (또는 길이가 항상 더 적은 비트에 맞는다는 것을 알고있는 경우 더 낮음). 그러면 96 비트 (12 바이트) 결과가 생성되어 24 자 16 진수 문자열로 변환 할 수 있습니다. 또는 base 64 인코딩을 사용하여 더 짧게 만들 수 있습니다.


2
FWIW, 이것은 XOR- 폴딩으로 알려져 있습니다.
PM 2Ring

7

필요한 경우 8 문자 해시 (32 비트), CRC-32 또는 Adler-32 를 생성 "sub-10-character hash" 하는 Fletcher-32 알고리즘을 사용할 수 있습니다 .

CRC-32는 Adler32보다 20 %-100 % 느립니다.

Fletcher-32는 Adler-32보다 약간 더 안정적입니다. Adler 체크섬 : Fletcher 대 Adler 비교 보다 계산 비용이 낮습니다 .

몇 가지 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                                                                                                                                                                                                                              

테스트 벡터에 동의합니다 .

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

Adler-32는 수백 바이트의 짧은 메시지에 대해 약점이 있습니다. 이러한 메시지에 대한 체크섬은 사용 가능한 32 비트의 범위가 좋지 않기 때문입니다. 이것을 확인하십시오 :

Adler32 알고리즘은 비교 가능한 체크섬과 경쟁 할만큼 복잡하지 않습니다 .


6

터미널 (MacOS 또는 Linux)에서 실행하기 만하면됩니다.

crc32 <(echo "some string")

8 자입니다.


4

Python 용 hashlib 라이브러리를 사용할 수 있습니다 . shake_128shake_256 알고리즘은 가변 길이의 해쉬를 제공한다. 다음은 몇 가지 작동 코드 (Python3)입니다.

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

길이 매개 변수 x (예 : 5)를 사용하면 함수가 길이 2x 의 해시 값을 반환합니다 .


1

이제 2019 년이며 더 나은 옵션이 있습니다. 즉, xxhash 입니다.

~ echo test | xxhsum                                                           
2d7f1808da1fa63c  stdin

이 링크는 끊어졌습니다. 보다 완전한 답변을 제공하는 것이 좋습니다.
eri0o

0

최근에 간단한 문자열 감소 기능이 필요했습니다. 기본적으로 코드는 다음과 같습니다 (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 + 값 = 값)로 끝납니다. 프로세스가 끝날 때 "읽을 수있는"것을 원하면 Normalize는 충돌이 증가하는 대신 변환 된 바이트를 조정합니다.

출처:

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


std :: hash는 특정 사용 사례를 해결하지 못합니다 (예 : 추가 코드 줄 몇 줄이면 충분할 때 bloaty std :: 템플릿에서 드래그하지 않음). 여기에는 어리석은 것이 없습니다. Mac OSX의 주요 제한 사항을 처리하기 위해 신중하게 고려되었습니다. 나는 정수를 원하지 않았습니다. 이를 위해 djb2를 사용할 수 있었지만 여전히 std :: 템플릿 사용을 피할 수있었습니다.
CubicleSoft 2016

이것은 여전히 ​​어리석은 소리입니다. 왜 것 이제까지 용도 DestSize해시 자체가 너무 엉터리 때 4 (32 비트) 이상을? int보다 큰 출력이 제공하는 충돌 저항을 원하면 SHA를 사용합니다.
Navin 2016

이건 정말 전통적인 해시가 아닙니다. 특정 OS (예 : Mac OSX)에서 매우 제한된 버퍼 공간이있는 곳에서 사용자가 문자열 크기를 선언 할 수 있고 결과가 실제 파일 이름의 제한된 도메인에 맞아야하며 자르기를 원하지 않는 유용한 속성이 있습니다. 이름은 그 WOULD가 충돌을 일으키기 때문입니다 (그러나 짧은 문자열은 그대로 남습니다). 암호화 해시가 항상 정답은 아니며 std :: hash도 항상 정답은 아닙니다.
CubicleSoft 2016
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.