Javascript의 문자열에서 해시 생성


585

문자열을 해시 형태로 변환해야합니다. 이것이 JavaScript에서 가능합니까?

서버 측 언어를 사용하지 않으므로 그렇게 할 수 없습니다.


7
MD5는 안전하지 않으므로 그 것을 찾지 마십시오.
henrikstroem

166
@henrikstroem 해싱하는 내용에 따라 다릅니다. md5를 사용하여 비보안 목적으로 해시를 만드는 것은 아무 문제가 없습니다.
브래드 코흐

7
@BradKoch 당신이하고있는 것에 달려있다; 보안 목적으로 md5를 사용하는 데 아무런 문제가 없습니다. 암호를 해싱하는 더 좋은 방법이 있지만 md5는 URL 서명과 같은 작업에 적합합니다.
Paul Ferrett

81
MD5가 여기 주석에서 비판되는 동안 거의 모든 답변이 훨씬 나쁜 해시 알고리즘을 권장하고 많은 공감을 얻습니다.
domen

38
MD5를 사용하여 다운로드가 온전한 지 확인하는 것이 마술로 모든 동료에게 암호를 이메일로 보내지는 않습니다.
James M. Lay

답변:


788
Object.defineProperty(String.prototype, 'hashCode', {
  value: function() {
    var hash = 0, i, chr;
    for (i = 0; i < this.length; i++) {
      chr   = this.charCodeAt(i);
      hash  = ((hash << 5) - hash) + chr;
      hash |= 0; // Convert to 32bit integer
    }
    return hash;
  }
});

출처 : http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/


22
이것은 Java에서 사용 된 것과 동일합니다. 은 hash << 5 - hash과 동일 hash * 31 + char훨씬 빠르지 만. 너무 빠르기 때문에 좋으며 31은 소수입니다. 거기에서 승리하십시오.
corsiKa

41
jsperf ( jsperf.com/hashing-strings ) 에서 몇 가지 테스트를 수행 했으며 비트 함수는 실제로 숫자 기반 함수보다 느립니다.
skerit 2016 년

17
@PeterAronZentai 왜 "사용 불가능"입니까? 숫자 기반 코드 (hash * 31) + char로 생성 된 출력 ((hash<<5)-hash)+char은 매우 긴 문자열 (100 만 자 이상을 포함하는 문자열로 테스트 한 경우)에서도 시프트 기반 코드로 생성 된 출력과 동일 하므로 용어로 "사용할 수 없음" 정확성. 숫자 기반 버전과 시프트 기반 버전 모두에서 복잡성은 O (n)이므로 복잡성 측면에서 "사용할 수 없습니다".
TachyonVortex

13
누구나 출력의 고유성에 대해 언급 할 수 있습니까? 특히 길이가보다 작은 문자열에 대해서만이 해시를 사용 하는 경우 충돌이 발생하지 않는 n가장 큰 문자열은 무엇 n입니까?
Don McCurdy

34
이것이 필요하거나 String 프로토 타입에 있어야하는 이유가 있습니까? 예를 들어 덜 효과적이고 효율적일까요? var hashCode = function hashCode (str) {etc...}? 그런 다음 hashCode("mystring")?
rattray

146

편집하다

내 jsperf 테스트를 기반으로 허용되는 답변이 실제로 더 빠릅니다. http://jsperf.com/hashcodelordvlad

기발한

관심이 있다면 개선 된 (더 빠른) 버전이 reduce있습니다.이 기능 은 배열 기능이 없는 오래된 브라우저에서 실패 합니다.

hashCode = function(s){
  return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
}

한 줄 화살표 기능 버전 :

hashCode = s => s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)

3
해시를 얻는 방법이 양수 일뿐입니까?
Prosto Trader 2013

46
기묘한. 방금 테스트 한 결과 허용되는 답변보다 느립니다. jsperf.com/hashcodelordvlad
lordvlad

113
좋은 사람 @lordvlad는 실제로 자신의 답변을 테스트 한 다음 속도가 느릴 때보 고합니다.
mikemaccana

9
방금 깨달았습니다 : 내 버전은 문자열을 먼저 배열로 바꾸어 새 메모리를 할당하고 모든 문자를 복사해야하기 때문에 허용되는 답변이 더 빠르다는 것은 완벽합니다.
lordvlad

5
[] .reduce.call (str, (p, c, i, a) => (p << 5)-p + a.charCodeAt (i), 0);
Dizzy

108

참고 : 최상의 32 비트 해시라도 조만간 충돌 발생합니다.

해시 충돌 probablility은 다음과 같이 계산 될 수 1-e ^ (-k (k-1) / 2N로 aproximated, k ^ 2 / 2N ( 여기 참조 ). 이는 직감이 제안한 것보다 높을 수 있습니다
. 32 비트 해시 및 k = 10,000 항목을 가정하면 확률 1.2 %로 충돌이 발생합니다. 77,163 개의 샘플에서 확률은 50 %가됩니다! ( 계산기 ).
하단에 해결 방법을 제안합니다.

이 질문에 대한 답변으로 고유성과 속도에 가장 적합한 해싱 알고리즘은 무엇입니까? Ian Boyd는 심층 분석 결과를 올렸다 . 한마디로 (내가 해석 한대로), 그는 Murmur가 최고라는 결론에 도달 한 다음 FNV-1a를 따릅니다.
esmiralha가 제안한 Java의 String.hashCode () 알고리즘은 DJB2의 변형 인 것 같습니다.

  • FNV-1a는 DJB2보다 더 나은 분포를 가지고 있지만 느립니다.
  • DJB2는 FNV-1a보다 빠르지 만 더 많은 충돌을 일으키는 경향이 있습니다.
  • MurmurHash3는 DJB2 및 FNV-1a보다 낫고 빠릅니다 (그러나 최적화 된 구현에는 FNV 및 DJB2보다 더 많은 코드 줄이 필요함)

여기에 큰 입력 문자열 일부 벤치 마크 : http://jsperf.com/32-bit-hash
짧은 입력 문자열을 해시, DJ2B 및 FNV-1A에 비해 잡음의 성능 방울 : http://jsperf.com/32- 비트 해시 / 3

따라서 일반적으로 murmur3을 권장합니다.
JavaScript 구현에 대해서는 여기를 참조하십시오 : https://github.com/garycourt/murmurhash-js

입력 문자열이 짧고 분배 품질보다 성능이 더 중요한 경우, esmiralha의 승인 된 답변에서 제안한대로 DJB2를 사용하십시오.

품질과 작은 코드 크기가 속도보다 중요한 경우 FNV-1a 구현 ( 이 코드 기반 )을 사용합니다.

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as 
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

충돌 확률 향상

여기설명 된 대로이 트릭을 사용하여 해시 비트 크기를 확장 할 수 있습니다.

function hash64(str) {
    var h1 = hash32(str);  // returns 32 bit (as 8 byte hex string)
    return h1 + hash32(h1 + str);  // 64 bit (as 16 byte hex string)
}

조심해서 사용하고 너무 많이 기대하지 마십시오.


왜합니까 ("0000000" + (hval >>> 0).toString(16)).substr(-8);? 그것과 같지 (hval >>> 0).toString(16)않습니까?
Manuel Meurer

3
결과적으로 해시의 길이가 항상 8자가되도록 선행 '0'을 추가하십시오. 출력물에서 읽고 인식하기가 쉽지만 제 개인적 의견입니다
mar10

아 알았어. 작은 들어 hval, (hval >>> 0).toString(16)제로와 당신 때문에 패드가 미만 8 자 수 있습니다. 나는 (hval >>> 0).toString(16)항상 정확히 8 개의 문자열을 얻었 기 때문에 혼란 스러웠다 .
Manuel Meurer

3
이 답변은 sooo가 훨씬 더 나은 분산 해시를 생성하기 때문에 좋아합니다. 여기에 제안 된 다른 함수는 결과 해시 값을 만듭니다. 예를 들어`hash ( "example1")-hash ( "example2") == 1 "인데, 이것은 훨씬 더 예측할 수 없습니다.
GavinoGrifoni

1
"FNV-1a는 DJB2보다 더 나은 분포를 갖지만 느리다"에 대한 응답으로 ES6 Math.imul기능을 사용하여 구현할 때 FNV1a가 매우 빠를 수 있다고 합니다. 이것만으로도 최고의 벤치 마크가되며 결국 DJB2보다 더 나은 선택입니다.
bryc

64

ES6 에서 허용 된 답변 을 기반으로 합니다. 작고 유지 관리가 가능하며 최신 브라우저에서 작동합니다.

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));

편집 (2019-11-04) :

한 줄 화살표 기능 버전 :

const hashCode = s => s.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0)

// test
console.log(hashCode('Hello!'))


1
비 문자열이 매개 변수로 전달 될 때 str += ""발생하는 예외를 피하기 위해 해싱 전에 추가 한 공유 주셔서 감사합니다str.split is not a function
BeetleJuice

4
그러나 다음 중 어느 것보다 훨씬 느리다 : https://jsperf.com/hashing-strings
AndyO

또한 줄 바꿈을 제거하여 길이가 3 줄 밖에되지 않으면 가장 빠른 "레트로"솔루션이 실제로 더 작다는 것을 알았습니다.
AndyO

2
이 방법으로 긍정적이지만 여전히 독특한 결과를 얻을 수 있습니까?
DIDS

3
@deekshith 허용되는 답변은 hash |= 032 비트 int로 변환하는 데 사용 됩니다. 이 구현은 그렇지 않습니다. 이것이 버그입니까?
Sukima

48

답변의 거의 절반은 Java 구현으로 String.hashCode, 고품질도 빠르지도 않습니다. 너무 특별하지는 않습니다. 각 캐릭터마다 31을 곱하면됩니다. 한 줄로 간단하고 효율적으로 구현할 수 있으며 다음과 같이 훨씬 빠릅니다 Math.imul.

hashCode=s=>{for(var i=0,h;i<s.length;i++)h=Math.imul(31,h)+s.charCodeAt(i)|0;return h}

그런데, better- 여기의 뭔가의 밖으로 cyrb53 , 단순하지만 고품질의 53 비트 해시입니다. 매우 빠르며 매우 우수한 해시 분포를 제공하며 모든 32 비트 해시에 비해 충돌 률이 상당히 낮습니다 .

const cyrb53 = function(str, seed = 0) {
    let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
    for (let i = 0, ch; i < str.length; i++) {
        ch = str.charCodeAt(i);
        h1 = Math.imul(h1 ^ ch, 2654435761);
        h2 = Math.imul(h2 ^ ch, 1597334677);
    }
    h1 = Math.imul(h1 ^ h1>>>16, 2246822507) ^ Math.imul(h2 ^ h2>>>13, 3266489909);
    h2 = Math.imul(h2 ^ h2>>>16, 2246822507) ^ Math.imul(h1 ^ h1>>>13, 3266489909);
    return 4294967296 * (2097151 & h2) + (h1>>>0);
};

잘 알려진 MurmurHash / xxHash 알고리즘과 유사 하게 곱셈과 Xorshift 의 조합을 사용 하여 해시를 생성하지만 철저하지는 않습니다. 결과적으로 JavaScript보다 빠르며 구현이 훨씬 간단합니다.

눈사태 (엄격하지 않음)를 달성합니다. 기본적으로 입력의 작은 변화가 출력에 큰 변화가있어 결과 해시가 무작위로 나타납니다.

0xc2ba782c97901 = cyrb53("a")
0xeda5bc254d2bf = cyrb53("b")
0xe64cc3b748385 = cyrb53("revenge")
0xd85148d13f93a = cyrb53("revenue")

동일한 입력의 대체 스트림에 시드를 제공 할 수도 있습니다.

0xee5e6598ccd5c = cyrb53("revenue", 1)
0x72e2831253862 = cyrb53("revenue", 2)
0x0de31708e6ab7 = cyrb53("revenue", 3)

기술적으로 64 비트 해시 (2 개의 상관되지 않은 32 비트 해시 병렬)이지만 JavaScript는 53 비트 정수로 제한됩니다. 필요한 경우 16 진 문자열 또는 배열의 리턴 라인을 변경하여 완전한 64 비트 출력을 계속 사용할 수 있습니다 .

16 진 문자열을 구성하면 성능이 중요한 상황에서 일괄 처리 속도가 크게 느려질 수 있습니다.

return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];

그리고 재미로, FNV 또는 DJB2보다 높은 품질의 89 개 문자 로 된 최소 32 비트 해시가 있습니다 .

TSH=s=>{for(var i=0,h=9;i<s.length;)h=Math.imul(h^s.charCodeAt(i++),9**9);return h^h>>>9}

4
와우, 이것은 짧은 (또는 비슷한) 입력에 대해 일반적인 * 31보다 훨씬 낫습니다. :)
lapo

2
어디에서 ch초기화 되나요?
hellowill89

3
@ hellowill89 woops, 나는 그것을 선언하는 것을 잊었고 세계적인 범위로 피가 흘렀다.
고침

IE 11에서 실패 : 개체가 속성 또는 메서드를 지원하지 않습니다 'imul'.
BachT

2
@BachT 폴리 또는 전체 ES6 심을 사용할 수 있습니다 . 그러나 IE11은 2009 년에 업데이트없이 비극적으로 중단되었습니다.
bryc

28

그것이 누군가에게 도움이된다면, 상위 2 개의 답변을 구식 브라우저 허용 버전으로 결합 reduce했습니다.

/**
 * @see http://stackoverflow.com/q/7616461/940217
 * @return {number}
 */
String.prototype.hashCode = function(){
    if (Array.prototype.reduce){
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
    } 
    var hash = 0;
    if (this.length === 0) return hash;
    for (var i = 0; i < this.length; i++) {
        var character  = this.charCodeAt(i);
        hash  = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

사용법은 다음과 같습니다.

var hash = "some string to be hashed".hashCode();

이 코드를 최적화하여 모든 브라우저에서 더 빠르게 실행하는 방법 String.prototype.hashCode = function(){ var hash = 5381; if (this.length === 0) return hash; for (var i = 0; i < this.length; i++) { var character = this.charCodeAt(i); hash = ((hash<<5)+hash)^character; // Convert to 32bit integer } return hash; }
Musakkhir Sayyed

26

이것은 세련되고 성능이 뛰어난 변형입니다.

String.prototype.hashCode = function() {
    var hash = 0, i = 0, len = this.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
    }
    return hash;
};

이것은 Java의 표준 구현과 일치합니다. object.hashCode()

다음은 양의 해시 코드 만 반환하는 것입니다.

String.prototype.hashcode = function() {
    return (this.hashCode() + 2147483647) + 1;
};

그리고 다음은 양의 해시 코드 만 반환하는 Java와 일치하는 것입니다.

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}

즐겨!


2
좋은 대답이지만 << 0의 목적은 무엇입니까?
koolaang

8
@koolaang 그것은 왼쪽 똥 연산자입니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
mmm

29
@momomo 왼쪽으로 이동 했습니까 ?
wdh

2
@ momomo 나는 그것이 왜 0 비트의 왼쪽 시프트인지 묻고 있다고 생각합니다.
jpfx1342

3
@ Maykonn (2 ^
32-1

24

아직 새로운 SubtleCrypto API 에 대해 아무도 이야기하지 않은 것에 약간 놀랐습니다 .

문자열에서 해시를 얻으려면 다음 subtle.digest방법을 사용할 수 있습니다 .

function getHash(str, algo = "SHA-256") {
  let strBuf = new TextEncoder('utf-8').encode(str);
  return crypto.subtle.digest(algo, strBuf)
    .then(hash => {
      window.hash = hash;
      // here hash is an arrayBuffer, 
      // so we'll connvert it to its hex version
      let result = '';
      const view = new DataView(hash);
      for (let i = 0; i < hash.byteLength; i += 4) {
        result += ('00000000' + view.getUint32(i).toString(16)).slice(-8);
      }
      return result;
    });
}

getHash('hello world')
  .then(hash => {
    console.log(hash);
  });


4
동의한다. 16 진수로의 변환은 조금 다를 수 있습니다 ...var promise = crypto.subtle.digest({name: "SHA-256"}, Uint8Array.from(data)); promise.then(function(result){ console.log(Array.prototype.map.call(new Uint8Array(result), x => x.toString(16).padStart(2, '0')).join('')); });
Denis Giffeler

3
문자열에 대한 암호화 해시 함수는 약간 과잉입니다. crypto정확하게 수행되지 않습니다.
bryc

테스트를 실행하는 사람들, 내장 (사용자 정의 구현이 필요하지 않음), 시드 가능에 의존하지 않고 신뢰할 수있는 품질의 무작위이며 게임 맵을 생성하기 위해 수백 개의 숫자 만 필요했기 때문에 완벽했습니다. 그러나 동기식으로 수행 할 수있는 방법은 절대적으로 없습니다. 시드 랜덤 엔진을 호출 할 때마다 비동기 콜백을 제공해야하므로 코드를 읽을 수없고 우스운 것처럼 보입니다. 나는이 crappy crypto.subtle 인터페이스를 만든 사람을 얻지 못하므로 결국이 답변에서 xmur3 + sfc32를 사용해야했습니다 : stackoverflow.com/a/47593316/1201863
Luc

7

mar10의 예제 덕분에 FNV-1a에 대해 C # AND Javascript에서 동일한 결과를 얻는 방법을 찾았습니다. 유니 코드 문자가 있으면 성능 향상을 위해 상단 부분이 삭제됩니다. URL 경로 만 해싱하는 것처럼 해싱 할 때 유지 관리하는 것이 왜 유용한 지 모르겠습니다.

C # 버전

private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5;   // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193;     // 16777619

// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
    // byte[] arr = Encoding.UTF8.GetBytes(s);      // 8 bit expanded unicode array
    char[] arr = s.ToCharArray();                   // 16 bit unicode is native .net 

    UInt32 hash = FNV_OFFSET_32;
    for (var i = 0; i < s.Length; i++)
    {
        // Strips unicode bits, only the lower 8 bits of the values are used
        hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
        hash = hash * FNV_PRIME_32;
    }
    return hash;
}

// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
    return unchecked((int)s.HashFnv32u());
}

자바 스크립트 버전

var utils = utils || {};

utils.FNV_OFFSET_32 = 0x811c9dc5;

utils.hashFnv32a = function (input) {
    var hval = utils.FNV_OFFSET_32;

    // Strips unicode bits, only the lower 8 bits of the values are used
    for (var i = 0; i < input.length; i++) {
        hval = hval ^ (input.charCodeAt(i) & 0xFF);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }

    return hval >>> 0;
}

utils.toHex = function (val) {
    return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}

@mathiasrw 유니 코드 문자가 메모리에서 8 비트를 초과 할 수 있으므로 0xFF는 단순히 해당 범위 밖의 모든 것을 마스크로 가정합니다. charCodeAt ()에 대한 자세한 내용은 여기를 참조하십시오 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
djabraham

ES6을 사용할 수있는 경우 (모든 최신 엔진이 지원하는 경우) Math.imul곱셈 단계에 사용할 수 있으므로 성능크게 향상됩니다 . 유일한 문제는 shim 없이 IE11에서 작동하지 않는다는 것입니다 .
bryc

6

여기 에서 적응 한 빠르고 간결한 것 :

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}

5

사용자 이름과 현재 시간을 기반으로 고유 ID를 생성하려면 비슷한 기능 (그러나 다른)이 필요했습니다. 그래서:

window.newId = ->
  # create a number based on the username
  unless window.userNumber?
    window.userNumber = 0
  for c,i in window.MyNamespace.userName
    char = window.MyNamespace.userName.charCodeAt(i)
    window.MyNamespace.userNumber+=char
  ((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()

생산 :

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc 

2015 년 6 월 편집 : 새 코드의 경우 shortid를 사용합니다 : https://www.npmjs.com/package/shortid


2
@ t0r0X 이제 shortid라는 모듈을 사용합니다 : npmjs.com/package/shortid
jcollum

1
shortid로 사용자 이름을 어떻게 사용하고 있습니까? 단지 ID를 생성하는 것 같다하지만 난 당신이 문자열에서 해시를 생성하는 데 사용하는 표시되지 않습니다
cyberwombat

1
이 답변에는 3 개의 다운 보트가 있습니다. 내 인생에서 나는 왜 그런지 상상할 수 없다. 아무도 ... 아무 말도하지 않았다 : - /
jcollum

1
@jcollum 그렇기 때문에 나는 거의 오래된 질문에 대답하지 않습니다. 답을 고친 후에도 아무도 균형을 맞추지 않습니다.
bryc

5

FNV의 Multiply+Xor방법을 기반으로 한 빠른 (매우 긴) 라이너 :

my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);

5

SubtleCrypto.digest

서버 측 언어를 사용하지 않으므로 그렇게 할 수 없습니다.

당신은 확실히 당신은 그것을 할 수없는 그런 식으로 ?

진화하는 언어 인 Javascript를 사용하고 있다는 사실을 잊었습니까?

시도하십시오 SubtleCrypto. SHA-1, SHA-128, SHA-256 및 SHA-512 해시 기능을 지원합니다.


async function hash(message/*: string */) {
	const text_encoder = new TextEncoder;
	const data = text_encoder.encode(message);
	const message_digest = await window.crypto.subtle.digest("SHA-512", data);
	return message_digest;
} // -> ArrayBuffer

function in_hex(data/*: ArrayBuffer */) {
	const octets = new Uint8Array(data);
	const hex = [].map.call(octets, octet => octet.toString(16).padStart(2, "0")).join("");
	return hex;
} // -> string

(async function demo() {
	console.log(in_hex(await hash("Thanks for the magic.")));
})();


2 년 전 Kaiido의 답변과 다른 점은 무엇입니까?
Luc

@Luc 분명히 아닙니다.
Константин Ван

3

나는 파티에 늦었지만이 모듈을 사용할 수 있습니다 : crypto :

const crypto = require('crypto');

const SALT = '$ome$alt';

function generateHash(pass) {
  return crypto.createHmac('sha256', SALT)
    .update(pass)
    .digest('hex');
}

이 함수의 결과는 항상 64문자열입니다. 이 같은:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"


2

나는 두 가지 솔루션 (사용자 esmiralha 및 lordvlad)을 결합하여 js 기능 reduce () 를 지원 하고 여전히 이전 브라우저와 호환되는 브라우저에 더 빠른 기능을 얻습니다 .

String.prototype.hashCode = function() {

    if (Array.prototype.reduce) {
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);   
    } else {

        var hash = 0, i, chr, len;
        if (this.length == 0) return hash;
        for (i = 0, len = this.length; i < len; i++) {
        chr   = this.charCodeAt(i);
        hash  = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
        }
        return hash;
    }
};

예:

my_string = 'xyz';
my_string.hashCode();

2

충돌을 피하려면 SHA-256 과 같은 보안 해시 를 사용하십시오 . 몇 가지 JavaScript SHA-256 구현이 있습니다.

여러 해시 구현을 비교하는 테스트를 작성했습니다 ( https://github.com/brillout/test-javascript-hash-implementations 참조) .

또는 http://brillout.github.io/test-javascript-hash-implementations/ 로 이동 하여 테스트를 실행하십시오.


1
안전한 암호화 해시 사용은 매우 느릴 수 있습니다. 충돌을 피하는 것은 보안이 아닌 비트 폭의 곱입니다. 128 비트 비 암호 해시 또는 64 비트는 대부분의 목적에 충분해야합니다. MurmurHash3_x86_128 은 매우 빠르며 충돌 가능성이 매우 낮습니다.
bryc December

2

이것은 다른 답변보다 약간 더 안전한 해시이어야하지만 미리로드 된 소스가없는 함수

기본적으로 단순화 된 sha1 버전을 만들었습니다 .
문자열의 바이트를 가져 와서 4 ~ 32 비트 "워드"로 그룹화합니다.
그런 다음 8 워드를 40 워드로 확장하여 결과에 더 큰 영향을줍니다.
이것은 현재 상태와 입력으로 일부 수학을 수행하는 해싱 함수 (마지막 감소)로 이동합니다. 우리는 항상 4 단어를 꺼냅니다.
이것은 루프 대신 map, reduce ...를 사용하는 거의 한 명령 / 한 줄 버전이지만 여전히 빠릅니다.

String.prototype.hash = function(){
    var rot = (word, shift) => word << shift | word >>> (32 - shift);
    return unescape(encodeURIComponent(this.valueOf())).split("").map(char =>
            char.charCodeAt(0)
        ).reduce((done, byte, idx, arr) =>
            idx % 4 == 0 ? [...done, arr.slice(idx, idx + 4)] : done
        , []).reduce((done, group) =>
            [...done, group[0] << 24 | group[1] << 16 | group[2] << 8 | group[3]]
        , []).reduce((done, word, idx, arr) =>
            idx % 8 == 0 ? [...done, arr.slice(idx, idx + 8)] : done
        , []).map(group => {
            while(group.length < 40)
                group.push(rot(group[group.length - 2] ^ group[group.length - 5] ^ group[group.length - 8], 3));
            return group;
        }).flat().reduce((state, word, idx, arr) => {
            var temp = ((state[0] + rot(state[1], 5) + word + idx + state[3]) & 0xffffffff) ^ state[idx % 2 == 0 ? 4 : 5](state[0], state[1], state[2]);
            state[0] = rot(state[1] ^ state[2], 11);
            state[1] = ~state[2] ^ rot(~state[3], 19);
            state[2] = rot(~state[3], 11);
            state[3] = temp;
            return state;
        }, [0xbd173622, 0x96d8975c, 0x3a6d1a23, 0xe5843775,
            (w1, w2, w3) => (w1 & rot(w2, 5)) | (~rot(w1, 11) & w3),
            (w1, w2, w3) => w1 ^ rot(w2, 5) ^ rot(w3, 11)]
        ).slice(0, 4).map(p =>
            p >>> 0
        ).map(word =>
            ("0000000" + word.toString(16)).slice(-8)
        ).join("");
};

또한 단어 배열 대신 문자열을 얻기 위해 출력을 16 진수로 변환합니다.
사용법이 간단합니다. expample "a string".hash()반환합니다"88a09e8f9cc6f8c71c4497fbb36f84cd"


1

16 진수 문자열로 변환 된 char 코드를 간단히 연결했습니다. 이것은 상대적으로 좁은 목적, 즉 SHORT 문자열 (예 : 제목, 태그)의 해시 표현을 서버 측과 교환하여 관련이없는 이유로 허용 된 hashCode Java 포트를 쉽게 구현할 수 없도록하는 것입니다. 여기에는 보안 응용 프로그램이 없습니다.

String.prototype.hash = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.map.call(range, function(i) {
    return self.charCodeAt(i).toString(16);
  }).join('');
}

Underscore를 사용하면 더 간결하고 브라우저에 잘 견딜 수 있습니다. 예:

"Lorem Ipsum".hash()
"4c6f72656d20497073756d"

비슷한 방식으로 더 큰 문자열을 해시하려면 개별 문자를 함께 연결하는 대신 문자 코드를 줄이고 결과 합계를 16 진수로 만들 수 있다고 가정합니다.

String.prototype.hashLarge = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.reduce.call(range, function(sum, i) {
    return sum + self.charCodeAt(i);
  }, 0).toString(16);
}

'One time, I hired a monkey to take notes for me in class. I would just sit back with my mind completely blank while the monkey scribbled on little pieces of paper. At the end of the week, the teacher said, "Class, I want you to write a paper using your notes." So I wrote a paper that said, "Hello! My name is Bingo! I like to climb on things! Can I have a banana? Eek, eek!" I got an F. When I told my mom about it, she said, "I told you, never trust a monkey!"'.hashLarge()
"9ce7"

자연스럽게이 방법과 충돌 할 위험이 있지만 감소의 산술을 피할 수는 있지만 해시를 다양 화하고 길게하고 싶었습니다.


1

@esmiralha의 답변이 약간 단순화 된 버전입니다.

이 버전에서는 String을 재정의하지 않습니다. 원하지 않는 동작이 발생할 수 있습니다.

function hashCode(str) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
        hash = ~~(((hash << 5) - hash) + str.charCodeAt(i));
    }
    return hash;
}

1

아직 아무도 없기 때문에 이것을 추가하면 해시로 많은 것을 요청하고 구현하는 것처럼 보이지만 항상 매우 좋지 않습니다.

이것은 문자열 입력과 해시와 같을 최대 수를 취하고 문자열 입력에 따라 고유 한 숫자를 생성합니다.

이를 사용하여 이미지 배열로 고유 한 인덱스를 생성 할 수 있습니다 (사용자에 대해 특정 아바타를 반환하고 임의로 선택했지만 이름을 기준으로 선택한 경우 항상 해당 이름을 가진 사람에게 할당됩니다) ).

물론 이것을 사용하여 다른 사람의 이름을 기반으로 고유 한 아바타 배경색을 생성하는 것과 같이 색인을 여러 색상으로 반환 할 수도 있습니다.

function hashInt (str, max = 1000) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
      hash = ((hash << 5) - hash) + str.charCodeAt(i);
      hash = hash & hash;
    }
    return Math.round(max * Math.abs(hash) / 2147483648);
}

-1

객체 해시 라이브러리 등과 같은 즉시 사용 가능한 솔루션 대신이 복잡하고 복잡한 암호화 코드를 사용해야 할 이유가 없습니다. 공급 업체에 의존하는 것이 더 생산적이고 시간을 절약하며 유지 관리 비용을 절감합니다.

https://github.com/puleos/object-hash를 사용 하십시오.

var hash = require('object-hash');

hash({foo: 'bar'}) // => '67b69634f9880a282c14a0f0cb7ba20cf5d677e9'
hash([1, 2, 2.718, 3.14159]) // => '136b9b88375971dff9f1af09d7356e3e04281951'

그 lib의 소스 코드는 읽을 수 없습니다. 단지 50k의 축소 된 코드입니다.
bryc

1
@bryc 그 공급 업체 코드가 같은 : 당신은 확인하실 수 있습니다 소스를 찾기 위해 가정 방법 github.com/puleos/object-hash/blob/master/index.js을
올렉 Abrazhaev을

축소 된 코드는 35.4KB이고 전체 소스는 14.2KB입니까? 말이되지 않습니다.
bryc

2
@bryc이 라인을 고려 했습니까? var crypto = require('crypto');. 빌드 중에 축소 버전으로 공급 업체 의이 종속성 코드를 추가한다고 생각합니다.
Oleg Abrazhaev

객체를 해시 해야하는 경우 정렬 키로 모든 객체를 직렬화 하는 직렬화를 작성한 다음 cyrb53 을 작성하여 base36 해시를 생성합니다.
Polv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.