Skip to content

Instantly share code, notes, and snippets.

@Kreijstal
Forked from rumkin/sha-256.js
Last active November 15, 2024 12:28
Show Gist options
  • Select an option

  • Save Kreijstal/db65b1d39e99ce7640a5af359be2c83a to your computer and use it in GitHub Desktop.

Select an option

Save Kreijstal/db65b1d39e99ce7640a5af359be2c83a to your computer and use it in GitHub Desktop.

Revisions

  1. Kreijstal revised this gist Nov 15, 2024. 1 changed file with 93 additions and 0 deletions.
    93 changes: 93 additions & 0 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -323,6 +323,99 @@ function md5(input) {
    .join('');
    }

    function sha1(message, rounds = 80) {
    let bytes;
    if (typeof message === 'string') {
    const encoder = new TextEncoder();
    bytes = encoder.encode(message);
    } else if (message instanceof Uint8Array) {
    bytes = message;
    } else {
    throw new Error("Invalid input type. Expected Uint8Array or string.");
    }

    let h0 = 0x67452301;
    let h1 = 0xEFCDAB89;
    let h2 = 0x98BADCFE;
    let h3 = 0x10325476;
    let h4 = 0xC3D2E1F0;

    let ml = bytes.length * 8;

    // Pre-processing
    let paddedBytes = new Uint8Array([...bytes, 0x80]);
    while ((paddedBytes.length * 8) % 512 !== 448) {
    paddedBytes = new Uint8Array([...paddedBytes, 0x00]);
    }

    const mlBytes = new Uint8Array(8);
    for (let i = 7; i >= 0; i--) {
    mlBytes[i] = ml & 0xFF;
    ml = ml >>> 8;
    }
    paddedBytes = new Uint8Array([...paddedBytes, ...mlBytes]);

    // Process the message in successive 512-bit chunks
    for (let i = 0; i < paddedBytes.length; i += 64) {
    const chunk = paddedBytes.slice(i, i + 64);
    let w = new Array(rounds).fill(0);

    for (let j = 0; j < 16; j++) {
    w[j] = (chunk[j * 4] << 24) | (chunk[j * 4 + 1] << 16) | (chunk[j * 4 + 2] << 8) | chunk[j * 4 + 3];
    }

    for (let j = 16; j < rounds; j++) {
    w[j] = ROTL(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
    }

    let a = h0;
    let b = h1;
    let c = h2;
    let d = h3;
    let e = h4;

    for (let j = 0; j < rounds; j++) {
    let f, k;
    if (0 <= j && j <= 19) {
    f = (b & c) | ((~b) & d);
    k = 0x5A827999;
    } else if (20 <= j && j <= 39) {
    f = b ^ c ^ d;
    k = 0x6ED9EBA1;
    } else if (40 <= j && j <= 59) {
    f = (b & c) | (b & d) | (c & d);
    k = 0x8F1BBCDC;
    } else if (60 <= j && j <= 79) {
    f = b ^ c ^ d;
    k = 0xCA62C1D6;
    } else {
    f = b ^ c ^ d;
    k = 0xCA62C1D6;
    }

    const temp = safeAdd32(ROTL(a, 5), safeAdd32(safeAdd32(safeAdd32(f, e), k), w[j]));
    e = d;
    d = c;
    c = ROTL(b, 30);
    b = a;
    a = temp;
    }

    h0 = safeAdd32(h0, a);
    h1 = safeAdd32(h1, b);
    h2 = safeAdd32(h2, c);
    h3 = safeAdd32(h3, d);
    h4 = safeAdd32(h4, e);
    }

    const hh = (h0 >>> 0).toString(16).padStart(8, '0') +
    (h1 >>> 0).toString(16).padStart(8, '0') +
    (h2 >>> 0).toString(16).padStart(8, '0') +
    (h3 >>> 0).toString(16).padStart(8, '0') +
    (h4 >>> 0).toString(16).padStart(8, '0');

    return hh;
    }


    function sha256(msgBytes, rounds = 64) {
  2. Kreijstal revised this gist Nov 14, 2024. 1 changed file with 6 additions and 13 deletions.
    19 changes: 6 additions & 13 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -1,14 +1,7 @@
    function safe_add(x, y)
    {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
    }

    /*
    * Bitwise rotate a 32-bit number to the left.
    */
    function rol(num, cnt)
    function ROTL(num, cnt)
    {
    return (num << cnt) | (num >>> (32 - cnt));
    }
    @@ -19,7 +12,7 @@ function rol(num, cnt)
    */
    function md4_cmn(q, a, b, x, s, t)
    {
    return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
    return safeAdd32(ROTL(safeAdd32(safeAdd32(a, q), safeAdd32(x, t)), s), b);
    }
    function md4_ff(a, b, c, d, x, s)
    {
    @@ -103,10 +96,10 @@ function core_md4(x, len)
    c = md4_hh(c, d, a, b, x[i+ 7], 11);
    b = md4_hh(b, c, d, a, x[i+15], 15);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    a = safeAdd32(a, olda);
    b = safeAdd32(b, oldb);
    c = safeAdd32(c, oldc);
    d = safeAdd32(d, oldd);

    }
    return Array(a, b, c, d);
  3. Kreijstal revised this gist Nov 14, 2024. 1 changed file with 157 additions and 0 deletions.
    157 changes: 157 additions & 0 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,160 @@
    function safe_add(x, y)
    {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
    }

    /*
    * Bitwise rotate a 32-bit number to the left.
    */
    function rol(num, cnt)
    {
    return (num << cnt) | (num >>> (32 - cnt));
    }

    /*
    * These functions implement the basic operation for each round of the
    * algorithm.
    */
    function md4_cmn(q, a, b, x, s, t)
    {
    return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
    }
    function md4_ff(a, b, c, d, x, s)
    {
    return md4_cmn((b & c) | ((~b) & d), a, 0, x, s, 0);
    }
    function md4_gg(a, b, c, d, x, s)
    {
    return md4_cmn((b & c) | (b & d) | (c & d), a, 0, x, s, 1518500249);
    }
    function md4_hh(a, b, c, d, x, s)
    {
    return md4_cmn(b ^ c ^ d, a, 0, x, s, 1859775393);
    }

    function core_md4(x, len)
    {
    /* append padding */
    x[len >> 5] |= 0x80 << (len % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;

    var a = 1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d = 271733878;

    for(var i = 0; i < x.length; i += 16)
    {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md4_ff(a, b, c, d, x[i+ 0], 3 );
    d = md4_ff(d, a, b, c, x[i+ 1], 7 );
    c = md4_ff(c, d, a, b, x[i+ 2], 11);
    b = md4_ff(b, c, d, a, x[i+ 3], 19);
    a = md4_ff(a, b, c, d, x[i+ 4], 3 );
    d = md4_ff(d, a, b, c, x[i+ 5], 7 );
    c = md4_ff(c, d, a, b, x[i+ 6], 11);
    b = md4_ff(b, c, d, a, x[i+ 7], 19);
    a = md4_ff(a, b, c, d, x[i+ 8], 3 );
    d = md4_ff(d, a, b, c, x[i+ 9], 7 );
    c = md4_ff(c, d, a, b, x[i+10], 11);
    b = md4_ff(b, c, d, a, x[i+11], 19);
    a = md4_ff(a, b, c, d, x[i+12], 3 );
    d = md4_ff(d, a, b, c, x[i+13], 7 );
    c = md4_ff(c, d, a, b, x[i+14], 11);
    b = md4_ff(b, c, d, a, x[i+15], 19);

    a = md4_gg(a, b, c, d, x[i+ 0], 3 );
    d = md4_gg(d, a, b, c, x[i+ 4], 5 );
    c = md4_gg(c, d, a, b, x[i+ 8], 9 );
    b = md4_gg(b, c, d, a, x[i+12], 13);
    a = md4_gg(a, b, c, d, x[i+ 1], 3 );
    d = md4_gg(d, a, b, c, x[i+ 5], 5 );
    c = md4_gg(c, d, a, b, x[i+ 9], 9 );
    b = md4_gg(b, c, d, a, x[i+13], 13);
    a = md4_gg(a, b, c, d, x[i+ 2], 3 );
    d = md4_gg(d, a, b, c, x[i+ 6], 5 );
    c = md4_gg(c, d, a, b, x[i+10], 9 );
    b = md4_gg(b, c, d, a, x[i+14], 13);
    a = md4_gg(a, b, c, d, x[i+ 3], 3 );
    d = md4_gg(d, a, b, c, x[i+ 7], 5 );
    c = md4_gg(c, d, a, b, x[i+11], 9 );
    b = md4_gg(b, c, d, a, x[i+15], 13);

    a = md4_hh(a, b, c, d, x[i+ 0], 3 );
    d = md4_hh(d, a, b, c, x[i+ 8], 9 );
    c = md4_hh(c, d, a, b, x[i+ 4], 11);
    b = md4_hh(b, c, d, a, x[i+12], 15);
    a = md4_hh(a, b, c, d, x[i+ 2], 3 );
    d = md4_hh(d, a, b, c, x[i+10], 9 );
    c = md4_hh(c, d, a, b, x[i+ 6], 11);
    b = md4_hh(b, c, d, a, x[i+14], 15);
    a = md4_hh(a, b, c, d, x[i+ 1], 3 );
    d = md4_hh(d, a, b, c, x[i+ 9], 9 );
    c = md4_hh(c, d, a, b, x[i+ 5], 11);
    b = md4_hh(b, c, d, a, x[i+13], 15);
    a = md4_hh(a, b, c, d, x[i+ 3], 3 );
    d = md4_hh(d, a, b, c, x[i+11], 9 );
    c = md4_hh(c, d, a, b, x[i+ 7], 11);
    b = md4_hh(b, c, d, a, x[i+15], 15);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);

    }
    return Array(a, b, c, d);

    }
    function md4(input) {
    // Handle string input by converting to Uint8Array
    let data = input;
    if (typeof input === 'string') {
    data = new TextEncoder().encode(input);
    }

    // Calculate input length in bits
    const bitLength = data.length * 8;

    // Calculate padding length (ensure room for length at end)
    // Need at least 1 byte for 0x80 and 8 bytes for length
    // Total length must be multiple of 64 bits (8 bytes)
    const paddingLength = (56 - (data.length + 1) % 64 + 64) % 64;

    // Create padded array
    const paddedLength = data.length + 1 + paddingLength + 8;
    const paddedData = new Uint8Array(paddedLength);

    // Copy original data
    paddedData.set(data);

    // Add padding byte 0x80
    paddedData[data.length] = 0x80;

    // Add original length in bits as little-endian 64-bit integer
    const view = new DataView(paddedData.buffer);
    view.setUint32(paddedLength - 8, bitLength, true);
    view.setUint32(paddedLength - 4, 0, true);

    // Convert to 32-bit array for core_md4
    const words = new Uint32Array(paddedData.buffer);

    // Process with core_md4
    const result = core_md4(Array.from(words), bitLength);

    // Convert result to hex string
    return [...new Uint8Array(new Uint32Array(result).buffer)]
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
    }


    function safeAdd32(a, b) {
    return (a + b) & 0xFFFFFFFF;
    }
  4. Kreijstal revised this gist Nov 14, 2024. 1 changed file with 162 additions and 194 deletions.
    356 changes: 162 additions & 194 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -1,192 +1,181 @@
    function md5cycle(x, k) {
    var a = x[0], b = x[1], c = x[2], d = x[3];

    a = ff(a, b, c, d, k[0], 7, -680876936);
    d = ff(d, a, b, c, k[1], 12, -389564586);
    c = ff(c, d, a, b, k[2], 17, 606105819);
    b = ff(b, c, d, a, k[3], 22, -1044525330);
    a = ff(a, b, c, d, k[4], 7, -176418897);
    d = ff(d, a, b, c, k[5], 12, 1200080426);
    c = ff(c, d, a, b, k[6], 17, -1473231341);
    b = ff(b, c, d, a, k[7], 22, -45705983);
    a = ff(a, b, c, d, k[8], 7, 1770035416);
    d = ff(d, a, b, c, k[9], 12, -1958414417);
    c = ff(c, d, a, b, k[10], 17, -42063);
    b = ff(b, c, d, a, k[11], 22, -1990404162);
    a = ff(a, b, c, d, k[12], 7, 1804603682);
    d = ff(d, a, b, c, k[13], 12, -40341101);
    c = ff(c, d, a, b, k[14], 17, -1502002290);
    b = ff(b, c, d, a, k[15], 22, 1236535329);

    a = gg(a, b, c, d, k[1], 5, -165796510);
    d = gg(d, a, b, c, k[6], 9, -1069501632);
    c = gg(c, d, a, b, k[11], 14, 643717713);
    b = gg(b, c, d, a, k[0], 20, -373897302);
    a = gg(a, b, c, d, k[5], 5, -701558691);
    d = gg(d, a, b, c, k[10], 9, 38016083);
    c = gg(c, d, a, b, k[15], 14, -660478335);
    b = gg(b, c, d, a, k[4], 20, -405537848);
    a = gg(a, b, c, d, k[9], 5, 568446438);
    d = gg(d, a, b, c, k[14], 9, -1019803690);
    c = gg(c, d, a, b, k[3], 14, -187363961);
    b = gg(b, c, d, a, k[8], 20, 1163531501);
    a = gg(a, b, c, d, k[13], 5, -1444681467);
    d = gg(d, a, b, c, k[2], 9, -51403784);
    c = gg(c, d, a, b, k[7], 14, 1735328473);
    b = gg(b, c, d, a, k[12], 20, -1926607734);

    a = hh(a, b, c, d, k[5], 4, -378558);
    d = hh(d, a, b, c, k[8], 11, -2022574463);
    c = hh(c, d, a, b, k[11], 16, 1839030562);
    b = hh(b, c, d, a, k[14], 23, -35309556);
    a = hh(a, b, c, d, k[1], 4, -1530992060);
    d = hh(d, a, b, c, k[4], 11, 1272893353);
    c = hh(c, d, a, b, k[7], 16, -155497632);
    b = hh(b, c, d, a, k[10], 23, -1094730640);
    a = hh(a, b, c, d, k[13], 4, 681279174);
    d = hh(d, a, b, c, k[0], 11, -358537222);
    c = hh(c, d, a, b, k[3], 16, -722521979);
    b = hh(b, c, d, a, k[6], 23, 76029189);
    a = hh(a, b, c, d, k[9], 4, -640364487);
    d = hh(d, a, b, c, k[12], 11, -421815835);
    c = hh(c, d, a, b, k[15], 16, 530742520);
    b = hh(b, c, d, a, k[2], 23, -995338651);

    a = ii(a, b, c, d, k[0], 6, -198630844);
    d = ii(d, a, b, c, k[7], 10, 1126891415);
    c = ii(c, d, a, b, k[14], 15, -1416354905);
    b = ii(b, c, d, a, k[5], 21, -57434055);
    a = ii(a, b, c, d, k[12], 6, 1700485571);
    d = ii(d, a, b, c, k[3], 10, -1894986606);
    c = ii(c, d, a, b, k[10], 15, -1051523);
    b = ii(b, c, d, a, k[1], 21, -2054922799);
    a = ii(a, b, c, d, k[8], 6, 1873313359);
    d = ii(d, a, b, c, k[15], 10, -30611744);
    c = ii(c, d, a, b, k[6], 15, -1560198380);
    b = ii(b, c, d, a, k[13], 21, 1309151649);
    a = ii(a, b, c, d, k[4], 6, -145523070);
    d = ii(d, a, b, c, k[11], 10, -1120210379);
    c = ii(c, d, a, b, k[2], 15, 718787259);
    b = ii(b, c, d, a, k[9], 21, -343485551);

    x[0] = add32(a, x[0]);
    x[1] = add32(b, x[1]);
    x[2] = add32(c, x[2]);
    x[3] = add32(d, x[3]);
    function safeAdd32(a, b) {
    return (a + b) & 0xFFFFFFFF;
    }

    function ROTR(n, x) {
    return (x >>> n) | (x << (32 - n));
    }

    function md5cycle(x, k) {
    let a = x[0], b = x[1], c = x[2], d = x[3];

    // Round 1
    a = ff(a, b, c, d, k[0], 7, -680876936);
    d = ff(d, a, b, c, k[1], 12, -389564586);
    c = ff(c, d, a, b, k[2], 17, 606105819);
    b = ff(b, c, d, a, k[3], 22, -1044525330);
    a = ff(a, b, c, d, k[4], 7, -176418897);
    d = ff(d, a, b, c, k[5], 12, 1200080426);
    c = ff(c, d, a, b, k[6], 17, -1473231341);
    b = ff(b, c, d, a, k[7], 22, -45705983);
    a = ff(a, b, c, d, k[8], 7, 1770035416);
    d = ff(d, a, b, c, k[9], 12, -1958414417);
    c = ff(c, d, a, b, k[10], 17, -42063);
    b = ff(b, c, d, a, k[11], 22, -1990404162);
    a = ff(a, b, c, d, k[12], 7, 1804603682);
    d = ff(d, a, b, c, k[13], 12, -40341101);
    c = ff(c, d, a, b, k[14], 17, -1502002290);
    b = ff(b, c, d, a, k[15], 22, 1236535329);

    // Round 2
    a = gg(a, b, c, d, k[1], 5, -165796510);
    d = gg(d, a, b, c, k[6], 9, -1069501632);
    c = gg(c, d, a, b, k[11], 14, 643717713);
    b = gg(b, c, d, a, k[0], 20, -373897302);
    a = gg(a, b, c, d, k[5], 5, -701558691);
    d = gg(d, a, b, c, k[10], 9, 38016083);
    c = gg(c, d, a, b, k[15], 14, -660478335);
    b = gg(b, c, d, a, k[4], 20, -405537848);
    a = gg(a, b, c, d, k[9], 5, 568446438);
    d = gg(d, a, b, c, k[14], 9, -1019803690);
    c = gg(c, d, a, b, k[3], 14, -187363961);
    b = gg(b, c, d, a, k[8], 20, 1163531501);
    a = gg(a, b, c, d, k[13], 5, -1444681467);
    d = gg(d, a, b, c, k[2], 9, -51403784);
    c = gg(c, d, a, b, k[7], 14, 1735328473);
    b = gg(b, c, d, a, k[12], 20, -1926607734);

    // Round 3
    a = hh(a, b, c, d, k[5], 4, -378558);
    d = hh(d, a, b, c, k[8], 11, -2022574463);
    c = hh(c, d, a, b, k[11], 16, 1839030562);
    b = hh(b, c, d, a, k[14], 23, -35309556);
    a = hh(a, b, c, d, k[1], 4, -1530992060);
    d = hh(d, a, b, c, k[4], 11, 1272893353);
    c = hh(c, d, a, b, k[7], 16, -155497632);
    b = hh(b, c, d, a, k[10], 23, -1094730640);
    a = hh(a, b, c, d, k[13], 4, 681279174);
    d = hh(d, a, b, c, k[0], 11, -358537222);
    c = hh(c, d, a, b, k[3], 16, -722521979);
    b = hh(b, c, d, a, k[6], 23, 76029189);
    a = hh(a, b, c, d, k[9], 4, -640364487);
    d = hh(d, a, b, c, k[12], 11, -421815835);
    c = hh(c, d, a, b, k[15], 16, 530742520);
    b = hh(b, c, d, a, k[2], 23, -995338651);

    // Round 4
    a = ii(a, b, c, d, k[0], 6, -198630844);
    d = ii(d, a, b, c, k[7], 10, 1126891415);
    c = ii(c, d, a, b, k[14], 15, -1416354905);
    b = ii(b, c, d, a, k[5], 21, -57434055);
    a = ii(a, b, c, d, k[12], 6, 1700485571);
    d = ii(d, a, b, c, k[3], 10, -1894986606);
    c = ii(c, d, a, b, k[10], 15, -1051523);
    b = ii(b, c, d, a, k[1], 21, -2054922799);
    a = ii(a, b, c, d, k[8], 6, 1873313359);
    d = ii(d, a, b, c, k[15], 10, -30611744);
    c = ii(c, d, a, b, k[6], 15, -1560198380);
    b = ii(b, c, d, a, k[13], 21, 1309151649);
    a = ii(a, b, c, d, k[4], 6, -145523070);
    d = ii(d, a, b, c, k[11], 10, -1120210379);
    c = ii(c, d, a, b, k[2], 15, 718787259);
    b = ii(b, c, d, a, k[9], 21, -343485551);

    x[0] = safeAdd32(a, x[0]);
    x[1] = safeAdd32(b, x[1]);
    x[2] = safeAdd32(c, x[2]);
    x[3] = safeAdd32(d, x[3]);
    }

    function cmn(q, a, b, x, s, t) {
    a = add32(add32(a, q), add32(x, t));
    return add32((a << s) | (a >>> (32 - s)), b);
    a = safeAdd32(safeAdd32(a, q), safeAdd32(x, t));
    return safeAdd32(ROTR(32 - s, a), b);
    }

    function ff(a, b, c, d, x, s, t) {
    return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }

    function gg(a, b, c, d, x, s, t) {
    return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }

    function hh(a, b, c, d, x, s, t) {
    return cmn(b ^ c ^ d, a, b, x, s, t);
    return cmn(b ^ c ^ d, a, b, x, s, t);
    }

    function ii(a, b, c, d, x, s, t) {
    return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }

    function md51(s) {
    txt = '';
    var n = s.length,
    state = [1732584193, -271733879, -1732584194, 271733878], i;
    for (i=64; i<=s.length; i+=64) {
    md5cycle(state, md5blk(s.substring(i-64, i)));
    }
    s = s.substring(i-64);
    var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
    for (i=0; i<s.length; i++)
    tail[i>>2] |= s.charCodeAt(i) << ((i%4) << 3);
    tail[i>>2] |= 0x80 << ((i%4) << 3);
    if (i > 55) {
    md5cycle(state, tail);
    for (i=0; i<16; i++) tail[i] = 0;
    }
    tail[14] = n*8;
    md5cycle(state, tail);
    return state;
    }

    /* there needs to be support for Unicode here,
    * unless we pretend that we can redefine the MD-5
    * algorithm for multi-byte characters (perhaps
    * by adding every four 16-bit characters and
    * shortening the sum to 32 bits). Otherwise
    * I suggest performing MD-5 as if every character
    * was two bytes--e.g., 0040 0025 = @%--but then
    * how will an ordinary MD-5 sum be matched?
    * There is no way to standardize text to something
    * like UTF-8 before transformation; speed cost is
    * utterly prohibitive. The JavaScript standard
    * itself needs to look at this: it should start
    * providing access to strings as preformed UTF-8
    * 8-bit unsigned value arrays.
    */
    function md5blk(s) { /* I figured global was faster. */
    var md5blks = [], i; /* Andy King said do it this way. */
    for (i=0; i<64; i+=4) {
    md5blks[i>>2] = s.charCodeAt(i)
    + (s.charCodeAt(i+1) << 8)
    + (s.charCodeAt(i+2) << 16)
    + (s.charCodeAt(i+3) << 24);
    }
    return md5blks;
    }

    var hex_chr = '0123456789abcdef'.split('');

    function rhex(n)
    {
    var s='', j=0;
    for(; j<4; j++)
    s += hex_chr[(n >> (j * 8 + 4)) & 0x0F]
    + hex_chr[(n >> (j * 8)) & 0x0F];
    return s;
    }

    function hex(x) {
    for (var i=0; i<x.length; i++)
    x[i] = rhex(x[i]);
    return x.join('');
    return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }

    function md5(s) {
    return hex(md51(s));
    function processBlock(state, input, offset) {
    const chunk = new Int32Array(16);
    const dv = new DataView(input.buffer, input.byteOffset);

    for (let j = 0; j < 16; j++) {
    chunk[j] = dv.getUint32(offset + (j * 4), true);
    }

    md5cycle(state, chunk);
    }

    /* this function is much faster,
    so if possible we use it. Some IEs
    are the only ones I know of that
    need the idiotic second function,
    generated by an if clause. */
    function md5(input) {
    // Convert string to Uint8Array if needed
    let data;
    if (typeof input === 'string') {
    data = new TextEncoder().encode(input);
    } else if (input instanceof Uint8Array) {
    data = input;
    } else {
    throw new Error('Input must be a string or Uint8Array');
    }

    function add32(a, b) {
    return (a + b) & 0xFFFFFFFF;
    }
    // Initialize hash values
    const state = new Int32Array([
    1732584193, // A
    -271733879, // B
    -1732584194, // C
    271733878 // D
    ]);

    // Pre-processing: pad the input
    const originalLength = data.length;
    const paddedLength = Math.ceil((originalLength + 9) / 64) * 64;
    const padded = new Uint8Array(paddedLength);

    // Copy original data
    padded.set(data);

    // Append padding bits
    padded[originalLength] = 0x80;

    // Append original length in bits as little-endian 64-bit integer
    const bitLength = originalLength * 8;
    const dv = new DataView(padded.buffer);
    dv.setUint32(paddedLength - 8, bitLength, true);
    dv.setUint32(paddedLength - 4, 0, true);

    // Process each 64-byte chunk
    for (let i = 0; i < paddedLength; i += 64) {
    processBlock(state, padded, i);
    }

    if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
    function add32(x, y) {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF),
    msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
    }
    // Convert state to bytes
    const result = new Uint8Array(16);
    const resultView = new DataView(result.buffer);
    for (let i = 0; i < 4; i++) {
    resultView.setInt32(i * 4, state[i], true);
    }

    // Convert to hex string
    return Array.from(result)
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
    }



    function sha256(msgBytes, rounds = 64) {
    // Constants [§4.2.2]
    const K = [
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    @@ -198,53 +187,43 @@ function sha256(msgBytes, rounds = 64) {
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
    ];

    // Initial hash value [§5.3.1]
    const H = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
    ];

    // PREPROCESSING

    // Create a new array with padding
    const paddedLength = Math.ceil((msgBytes.length + 9) / 64) * 64; // +9 for 0x80 byte and 64-bit length
    const paddedLength = Math.ceil((msgBytes.length + 9) / 64) * 64;
    const paddedBytes = new Uint8Array(paddedLength);
    paddedBytes.set(msgBytes);
    paddedBytes[msgBytes.length] = 0x80; // Add trailing '1' bit (+ 0's padding)
    paddedBytes[msgBytes.length] = 0x80;

    // Add length (in bits) into final pair of 32-bit integers (big-endian)
    const msgLengthBits = msgBytes.length * 8;
    const dv = new DataView(paddedBytes.buffer);
    dv.setUint32(paddedLength - 8, Math.floor(msgLengthBits / Math.pow(2, 32)), false); // high-order bits
    dv.setUint32(paddedLength - 4, msgLengthBits & 0xffffffff, false); // low-order bits
    dv.setUint32(paddedLength - 8, Math.floor(msgLengthBits / Math.pow(2, 32)), false);
    dv.setUint32(paddedLength - 4, msgLengthBits & 0xffffffff, false);

    // Process the message in successive 512-bit (64-byte) chunks
    const N = paddedLength / 64;
    const M = new Array(N);

    for (let i = 0; i < N; i++) {
    M[i] = new Array(16);
    for (let j = 0; j < 16; j++) {
    M[i][j] = (paddedBytes[i * 64 + j * 4] << 24) |
    (paddedBytes[i * 64 + j * 4 + 1] << 16) |
    (paddedBytes[i * 64 + j * 4 + 2] << 8) |
    (paddedBytes[i * 64 + j * 4 + 3]);
    (paddedBytes[i * 64 + j * 4 + 1] << 16) |
    (paddedBytes[i * 64 + j * 4 + 2] << 8) |
    (paddedBytes[i * 64 + j * 4 + 3]);
    }
    }

    // HASH COMPUTATION [§6.1.2]
    const W = new Array(64);
    let a, b, c, d, e, f, g, h;

    for (let i = 0; i < N; i++) {
    // 1 - Prepare message schedule 'W'
    for (let t = 0; t < 16; t++) W[t] = M[i][t];
    for (let t = 16; t < 64; t++) W[t] = (σ1(W[t - 2]) + W[t - 7] + σ0(W[t - 15]) + W[t - 16]) >>> 0;

    // 2 - Initialize working variables
    a = H[0]; b = H[1]; c = H[2]; d = H[3];
    e = H[4]; f = H[5]; g = H[6]; h = H[7];

    // 3 - Main loop
    for (let t = 0; t < rounds; t++) {
    const T1 = (h + Σ1(e) + Ch(e, f, g) + K[t] + W[t]) >>> 0;
    const T2 = (Σ0(a) + Maj(a, b, c)) >>> 0;
    @@ -258,7 +237,6 @@ function sha256(msgBytes, rounds = 64) {
    a = (T1 + T2) >>> 0;
    }

    // 4 - Compute the new intermediate hash value
    H[0] = (H[0] + a) >>> 0;
    H[1] = (H[1] + b) >>> 0;
    H[2] = (H[2] + c) >>> 0;
    @@ -269,10 +247,8 @@ function sha256(msgBytes, rounds = 64) {
    H[7] = (H[7] + h) >>> 0;
    }

    // Convert the final hash to hex string
    return H.map(n => n.toString(16).padStart(8, '0')).join('');

    function ROTR(n, x) { return (x >>> n) | (x << (32 - n)); }
    function Σ0(x) { return ROTR(2, x) ^ ROTR(13, x) ^ ROTR(22, x); }
    function Σ1(x) { return ROTR(6, x) ^ ROTR(11, x) ^ ROTR(25, x); }
    function σ0(x) { return ROTR(7, x) ^ ROTR(18, x) ^ (x >>> 3); }
    @@ -282,7 +258,6 @@ function sha256(msgBytes, rounds = 64) {
    }

    function hmac(key, message, hash, blockSize = 64) {
    // Helper function to convert hex string to Uint8Array
    function hexToBytes(hex) {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < hex.length; i += 2) {
    @@ -291,15 +266,12 @@ function hmac(key, message, hash, blockSize = 64) {
    return bytes;
    }

    // Helper function to compute the block-sized key
    function computeBlockSizedKey(key, hash, blockSize) {
    let keyBytes = typeof key === 'string' ? new TextEncoder().encode(key) : key;
    // Keys longer than blockSize are shortened by hashing them
    if (keyBytes.length > blockSize) {
    const hashedKey = hash(keyBytes);
    keyBytes = hexToBytes(hashedKey);
    }
    // Keys shorter than blockSize are padded to blockSize by padding with zeros on the right
    if (keyBytes.length < blockSize) {
    const paddedKey = new Uint8Array(blockSize);
    paddedKey.set(keyBytes);
    @@ -308,23 +280,19 @@ function hmac(key, message, hash, blockSize = 64) {
    return keyBytes;
    }

    // Compute the block-sized key
    const blockSizedKey = computeBlockSizedKey(key, hash, blockSize);

    // Create the outer and inner padded keys
    const oKeyPad = new Uint8Array(blockSize);
    const iKeyPad = new Uint8Array(blockSize);
    for (let i = 0; i < blockSize; i++) {
    oKeyPad[i] = blockSizedKey[i] ^ 0x5c;
    iKeyPad[i] = blockSizedKey[i] ^ 0x36;
    }

    // Convert message to Uint8Array if it's a string
    const messageBytes = typeof message === 'string'
    ? new TextEncoder().encode(message)
    const messageBytes = typeof message === 'string'
    ? new TextEncoder().encode(message)
    : message;

    // Compute the HMAC
    const innerHashHex = hash(new Uint8Array([...iKeyPad, ...messageBytes]));
    const innerHashBytes = hexToBytes(innerHashHex);
    const hmacValue = hash(new Uint8Array([...oKeyPad, ...innerHashBytes]));
  5. Kreijstal revised this gist Nov 13, 2024. 1 changed file with 187 additions and 0 deletions.
    187 changes: 187 additions & 0 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,190 @@
    function md5cycle(x, k) {
    var a = x[0], b = x[1], c = x[2], d = x[3];

    a = ff(a, b, c, d, k[0], 7, -680876936);
    d = ff(d, a, b, c, k[1], 12, -389564586);
    c = ff(c, d, a, b, k[2], 17, 606105819);
    b = ff(b, c, d, a, k[3], 22, -1044525330);
    a = ff(a, b, c, d, k[4], 7, -176418897);
    d = ff(d, a, b, c, k[5], 12, 1200080426);
    c = ff(c, d, a, b, k[6], 17, -1473231341);
    b = ff(b, c, d, a, k[7], 22, -45705983);
    a = ff(a, b, c, d, k[8], 7, 1770035416);
    d = ff(d, a, b, c, k[9], 12, -1958414417);
    c = ff(c, d, a, b, k[10], 17, -42063);
    b = ff(b, c, d, a, k[11], 22, -1990404162);
    a = ff(a, b, c, d, k[12], 7, 1804603682);
    d = ff(d, a, b, c, k[13], 12, -40341101);
    c = ff(c, d, a, b, k[14], 17, -1502002290);
    b = ff(b, c, d, a, k[15], 22, 1236535329);

    a = gg(a, b, c, d, k[1], 5, -165796510);
    d = gg(d, a, b, c, k[6], 9, -1069501632);
    c = gg(c, d, a, b, k[11], 14, 643717713);
    b = gg(b, c, d, a, k[0], 20, -373897302);
    a = gg(a, b, c, d, k[5], 5, -701558691);
    d = gg(d, a, b, c, k[10], 9, 38016083);
    c = gg(c, d, a, b, k[15], 14, -660478335);
    b = gg(b, c, d, a, k[4], 20, -405537848);
    a = gg(a, b, c, d, k[9], 5, 568446438);
    d = gg(d, a, b, c, k[14], 9, -1019803690);
    c = gg(c, d, a, b, k[3], 14, -187363961);
    b = gg(b, c, d, a, k[8], 20, 1163531501);
    a = gg(a, b, c, d, k[13], 5, -1444681467);
    d = gg(d, a, b, c, k[2], 9, -51403784);
    c = gg(c, d, a, b, k[7], 14, 1735328473);
    b = gg(b, c, d, a, k[12], 20, -1926607734);

    a = hh(a, b, c, d, k[5], 4, -378558);
    d = hh(d, a, b, c, k[8], 11, -2022574463);
    c = hh(c, d, a, b, k[11], 16, 1839030562);
    b = hh(b, c, d, a, k[14], 23, -35309556);
    a = hh(a, b, c, d, k[1], 4, -1530992060);
    d = hh(d, a, b, c, k[4], 11, 1272893353);
    c = hh(c, d, a, b, k[7], 16, -155497632);
    b = hh(b, c, d, a, k[10], 23, -1094730640);
    a = hh(a, b, c, d, k[13], 4, 681279174);
    d = hh(d, a, b, c, k[0], 11, -358537222);
    c = hh(c, d, a, b, k[3], 16, -722521979);
    b = hh(b, c, d, a, k[6], 23, 76029189);
    a = hh(a, b, c, d, k[9], 4, -640364487);
    d = hh(d, a, b, c, k[12], 11, -421815835);
    c = hh(c, d, a, b, k[15], 16, 530742520);
    b = hh(b, c, d, a, k[2], 23, -995338651);

    a = ii(a, b, c, d, k[0], 6, -198630844);
    d = ii(d, a, b, c, k[7], 10, 1126891415);
    c = ii(c, d, a, b, k[14], 15, -1416354905);
    b = ii(b, c, d, a, k[5], 21, -57434055);
    a = ii(a, b, c, d, k[12], 6, 1700485571);
    d = ii(d, a, b, c, k[3], 10, -1894986606);
    c = ii(c, d, a, b, k[10], 15, -1051523);
    b = ii(b, c, d, a, k[1], 21, -2054922799);
    a = ii(a, b, c, d, k[8], 6, 1873313359);
    d = ii(d, a, b, c, k[15], 10, -30611744);
    c = ii(c, d, a, b, k[6], 15, -1560198380);
    b = ii(b, c, d, a, k[13], 21, 1309151649);
    a = ii(a, b, c, d, k[4], 6, -145523070);
    d = ii(d, a, b, c, k[11], 10, -1120210379);
    c = ii(c, d, a, b, k[2], 15, 718787259);
    b = ii(b, c, d, a, k[9], 21, -343485551);

    x[0] = add32(a, x[0]);
    x[1] = add32(b, x[1]);
    x[2] = add32(c, x[2]);
    x[3] = add32(d, x[3]);

    }

    function cmn(q, a, b, x, s, t) {
    a = add32(add32(a, q), add32(x, t));
    return add32((a << s) | (a >>> (32 - s)), b);
    }

    function ff(a, b, c, d, x, s, t) {
    return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }

    function gg(a, b, c, d, x, s, t) {
    return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }

    function hh(a, b, c, d, x, s, t) {
    return cmn(b ^ c ^ d, a, b, x, s, t);
    }

    function ii(a, b, c, d, x, s, t) {
    return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }

    function md51(s) {
    txt = '';
    var n = s.length,
    state = [1732584193, -271733879, -1732584194, 271733878], i;
    for (i=64; i<=s.length; i+=64) {
    md5cycle(state, md5blk(s.substring(i-64, i)));
    }
    s = s.substring(i-64);
    var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
    for (i=0; i<s.length; i++)
    tail[i>>2] |= s.charCodeAt(i) << ((i%4) << 3);
    tail[i>>2] |= 0x80 << ((i%4) << 3);
    if (i > 55) {
    md5cycle(state, tail);
    for (i=0; i<16; i++) tail[i] = 0;
    }
    tail[14] = n*8;
    md5cycle(state, tail);
    return state;
    }

    /* there needs to be support for Unicode here,
    * unless we pretend that we can redefine the MD-5
    * algorithm for multi-byte characters (perhaps
    * by adding every four 16-bit characters and
    * shortening the sum to 32 bits). Otherwise
    * I suggest performing MD-5 as if every character
    * was two bytes--e.g., 0040 0025 = @%--but then
    * how will an ordinary MD-5 sum be matched?
    * There is no way to standardize text to something
    * like UTF-8 before transformation; speed cost is
    * utterly prohibitive. The JavaScript standard
    * itself needs to look at this: it should start
    * providing access to strings as preformed UTF-8
    * 8-bit unsigned value arrays.
    */
    function md5blk(s) { /* I figured global was faster. */
    var md5blks = [], i; /* Andy King said do it this way. */
    for (i=0; i<64; i+=4) {
    md5blks[i>>2] = s.charCodeAt(i)
    + (s.charCodeAt(i+1) << 8)
    + (s.charCodeAt(i+2) << 16)
    + (s.charCodeAt(i+3) << 24);
    }
    return md5blks;
    }

    var hex_chr = '0123456789abcdef'.split('');

    function rhex(n)
    {
    var s='', j=0;
    for(; j<4; j++)
    s += hex_chr[(n >> (j * 8 + 4)) & 0x0F]
    + hex_chr[(n >> (j * 8)) & 0x0F];
    return s;
    }

    function hex(x) {
    for (var i=0; i<x.length; i++)
    x[i] = rhex(x[i]);
    return x.join('');
    }

    function md5(s) {
    return hex(md51(s));
    }

    /* this function is much faster,
    so if possible we use it. Some IEs
    are the only ones I know of that
    need the idiotic second function,
    generated by an if clause. */

    function add32(a, b) {
    return (a + b) & 0xFFFFFFFF;
    }

    if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
    function add32(x, y) {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF),
    msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
    }
    }



    function sha256(msgBytes, rounds = 64) {
    // Constants [§4.2.2]
    const K = [
  6. Kreijstal revised this gist Nov 13, 2024. 1 changed file with 51 additions and 0 deletions.
    51 changes: 51 additions & 0 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -92,4 +92,55 @@ function sha256(msgBytes, rounds = 64) {
    function σ1(x) { return ROTR(17, x) ^ ROTR(19, x) ^ (x >>> 10); }
    function Ch(x, y, z) { return (x & y) ^ (~x & z); }
    function Maj(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); }
    }

    function hmac(key, message, hash, blockSize = 64) {
    // Helper function to convert hex string to Uint8Array
    function hexToBytes(hex) {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < hex.length; i += 2) {
    bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
    }
    return bytes;
    }

    // Helper function to compute the block-sized key
    function computeBlockSizedKey(key, hash, blockSize) {
    let keyBytes = typeof key === 'string' ? new TextEncoder().encode(key) : key;
    // Keys longer than blockSize are shortened by hashing them
    if (keyBytes.length > blockSize) {
    const hashedKey = hash(keyBytes);
    keyBytes = hexToBytes(hashedKey);
    }
    // Keys shorter than blockSize are padded to blockSize by padding with zeros on the right
    if (keyBytes.length < blockSize) {
    const paddedKey = new Uint8Array(blockSize);
    paddedKey.set(keyBytes);
    return paddedKey;
    }
    return keyBytes;
    }

    // Compute the block-sized key
    const blockSizedKey = computeBlockSizedKey(key, hash, blockSize);

    // Create the outer and inner padded keys
    const oKeyPad = new Uint8Array(blockSize);
    const iKeyPad = new Uint8Array(blockSize);
    for (let i = 0; i < blockSize; i++) {
    oKeyPad[i] = blockSizedKey[i] ^ 0x5c;
    iKeyPad[i] = blockSizedKey[i] ^ 0x36;
    }

    // Convert message to Uint8Array if it's a string
    const messageBytes = typeof message === 'string'
    ? new TextEncoder().encode(message)
    : message;

    // Compute the HMAC
    const innerHashHex = hash(new Uint8Array([...iKeyPad, ...messageBytes]));
    const innerHashBytes = hexToBytes(innerHashHex);
    const hmacValue = hash(new Uint8Array([...oKeyPad, ...innerHashBytes]));

    return hmacValue;
    }
  7. Kreijstal revised this gist Nov 13, 2024. 1 changed file with 92 additions and 166 deletions.
    258 changes: 92 additions & 166 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -1,169 +1,95 @@
    ;(function(){
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    /* SHA-256 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */
    /* */
    /* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
    /* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    /* jshint node:true *//* global define, escape, unescape */
    'use strict';


    /**
    * SHA-256 hash function reference implementation.
    *
    * @namespace
    */
    var Sha256 = {};


    /**
    * Generates SHA-256 hash of string.
    *
    * @param {string} msg - String to be hashed
    * @returns {string} Hash of msg as hex character string
    */
    Sha256.hash = function(msg) {
    // convert string to UTF-8, as SHA only deals with byte-streams
    msg = msg.utf8Encode();

    // constants [§4.2.2]
    var K = [
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ];
    // initial hash value [§5.3.1]
    var H = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ];

    // PREPROCESSING

    msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]

    // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
    var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
    var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
    var M = new Array(N);

    for (var i=0; i<N; i++) {
    M[i] = new Array(16);
    for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
    M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
    (msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
    } // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
    }
    // add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
    // note: most significant word would be (len-1)*8 >>> 32, but since JS converts
    // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
    M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]);
    M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;


    // HASH COMPUTATION [§6.1.2]

    var W = new Array(64); var a, b, c, d, e, f, g, h;
    for (var i=0; i<N; i++) {

    // 1 - prepare message schedule 'W'
    for (var t=0; t<16; t++) W[t] = M[i][t];
    for (var t=16; t<64; t++) W[t] = (Sha256.σ1(W[t-2]) + W[t-7] + Sha256.σ0(W[t-15]) + W[t-16]) & 0xffffffff;

    // 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value
    a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7];

    // 3 - main loop (note 'addition modulo 2^32')
    for (var t=0; t<64; t++) {
    var T1 = h + Sha256.Σ1(e) + Sha256.Ch(e, f, g) + K[t] + W[t];
    var T2 = Sha256.Σ0(a) + Sha256.Maj(a, b, c);
    h = g;
    g = f;
    f = e;
    e = (d + T1) & 0xffffffff;
    d = c;
    c = b;
    b = a;
    a = (T1 + T2) & 0xffffffff;
    }
    // 4 - compute the new intermediate hash value (note 'addition modulo 2^32')
    H[0] = (H[0]+a) & 0xffffffff;
    H[1] = (H[1]+b) & 0xffffffff;
    H[2] = (H[2]+c) & 0xffffffff;
    H[3] = (H[3]+d) & 0xffffffff;
    H[4] = (H[4]+e) & 0xffffffff;
    H[5] = (H[5]+f) & 0xffffffff;
    H[6] = (H[6]+g) & 0xffffffff;
    H[7] = (H[7]+h) & 0xffffffff;
    function sha256(msgBytes, rounds = 64) {
    // Constants [§4.2.2]
    const K = [
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
    ];

    // Initial hash value [§5.3.1]
    const H = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
    ];

    // PREPROCESSING

    // Create a new array with padding
    const paddedLength = Math.ceil((msgBytes.length + 9) / 64) * 64; // +9 for 0x80 byte and 64-bit length
    const paddedBytes = new Uint8Array(paddedLength);
    paddedBytes.set(msgBytes);
    paddedBytes[msgBytes.length] = 0x80; // Add trailing '1' bit (+ 0's padding)

    // Add length (in bits) into final pair of 32-bit integers (big-endian)
    const msgLengthBits = msgBytes.length * 8;
    const dv = new DataView(paddedBytes.buffer);
    dv.setUint32(paddedLength - 8, Math.floor(msgLengthBits / Math.pow(2, 32)), false); // high-order bits
    dv.setUint32(paddedLength - 4, msgLengthBits & 0xffffffff, false); // low-order bits

    // Process the message in successive 512-bit (64-byte) chunks
    const N = paddedLength / 64;
    const M = new Array(N);

    for (let i = 0; i < N; i++) {
    M[i] = new Array(16);
    for (let j = 0; j < 16; j++) {
    M[i][j] = (paddedBytes[i * 64 + j * 4] << 24) |
    (paddedBytes[i * 64 + j * 4 + 1] << 16) |
    (paddedBytes[i * 64 + j * 4 + 2] << 8) |
    (paddedBytes[i * 64 + j * 4 + 3]);
    }

    return Sha256.toHexStr(H[0]) + Sha256.toHexStr(H[1]) + Sha256.toHexStr(H[2]) + Sha256.toHexStr(H[3]) +
    Sha256.toHexStr(H[4]) + Sha256.toHexStr(H[5]) + Sha256.toHexStr(H[6]) + Sha256.toHexStr(H[7]);
    };


    /**
    * Rotates right (circular right shift) value x by n positions [§3.2.4].
    * @private
    */
    Sha256.ROTR = function(n, x) {
    return (x >>> n) | (x << (32-n));
    };

    /**
    * Logical functions [§4.1.2].
    * @private
    */
    Sha256.Σ0 = function(x) { return Sha256.ROTR(2, x) ^ Sha256.ROTR(13, x) ^ Sha256.ROTR(22, x); };
    Sha256.Σ1 = function(x) { return Sha256.ROTR(6, x) ^ Sha256.ROTR(11, x) ^ Sha256.ROTR(25, x); };
    Sha256.σ0 = function(x) { return Sha256.ROTR(7, x) ^ Sha256.ROTR(18, x) ^ (x>>>3); };
    Sha256.σ1 = function(x) { return Sha256.ROTR(17, x) ^ Sha256.ROTR(19, x) ^ (x>>>10); };
    Sha256.Ch = function(x, y, z) { return (x & y) ^ (~x & z); };
    Sha256.Maj = function(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); };


    /**
    * Hexadecimal representation of a number.
    * @private
    */
    Sha256.toHexStr = function(n) {
    // note can't use toString(16) as it is implementation-dependant,
    // and in IE returns signed numbers when used on full words
    var s="", v;
    for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
    return s;
    };


    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


    /** Extend String object with method to encode multi-byte string to utf8
    * - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */
    if (typeof String.prototype.utf8Encode == 'undefined') {
    String.prototype.utf8Encode = function() {
    return unescape( encodeURIComponent( this ) );
    };
    }

    /** Extend String object with method to decode utf8 string to multi-byte */
    if (typeof String.prototype.utf8Decode == 'undefined') {
    String.prototype.utf8Decode = function() {
    try {
    return decodeURIComponent( escape( this ) );
    } catch (e) {
    return this; // invalid UTF-8? return as-is
    }
    };

    // HASH COMPUTATION [§6.1.2]
    const W = new Array(64);
    let a, b, c, d, e, f, g, h;

    for (let i = 0; i < N; i++) {
    // 1 - Prepare message schedule 'W'
    for (let t = 0; t < 16; t++) W[t] = M[i][t];
    for (let t = 16; t < 64; t++) W[t] = (σ1(W[t - 2]) + W[t - 7] + σ0(W[t - 15]) + W[t - 16]) >>> 0;

    // 2 - Initialize working variables
    a = H[0]; b = H[1]; c = H[2]; d = H[3];
    e = H[4]; f = H[5]; g = H[6]; h = H[7];

    // 3 - Main loop
    for (let t = 0; t < rounds; t++) {
    const T1 = (h + Σ1(e) + Ch(e, f, g) + K[t] + W[t]) >>> 0;
    const T2 = (Σ0(a) + Maj(a, b, c)) >>> 0;
    h = g;
    g = f;
    f = e;
    e = (d + T1) >>> 0;
    d = c;
    c = b;
    b = a;
    a = (T1 + T2) >>> 0;
    }

    // 4 - Compute the new intermediate hash value
    H[0] = (H[0] + a) >>> 0;
    H[1] = (H[1] + b) >>> 0;
    H[2] = (H[2] + c) >>> 0;
    H[3] = (H[3] + d) >>> 0;
    H[4] = (H[4] + e) >>> 0;
    H[5] = (H[5] + f) >>> 0;
    H[6] = (H[6] + g) >>> 0;
    H[7] = (H[7] + h) >>> 0;
    }


    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (typeof module != 'undefined' && module.exports) module.exports = Sha256; // CommonJs export
    if (typeof define == 'function' && define.amd) define([], function() { return Sha256; }); // AMD
    if (typeof window !== 'undefined') window.Sha256 = Sha256;
    })();

    // Convert the final hash to hex string
    return H.map(n => n.toString(16).padStart(8, '0')).join('');

    function ROTR(n, x) { return (x >>> n) | (x << (32 - n)); }
    function Σ0(x) { return ROTR(2, x) ^ ROTR(13, x) ^ ROTR(22, x); }
    function Σ1(x) { return ROTR(6, x) ^ ROTR(11, x) ^ ROTR(25, x); }
    function σ0(x) { return ROTR(7, x) ^ ROTR(18, x) ^ (x >>> 3); }
    function σ1(x) { return ROTR(17, x) ^ ROTR(19, x) ^ (x >>> 10); }
    function Ch(x, y, z) { return (x & y) ^ (~x & z); }
    function Maj(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); }
    }
  8. @rumkin rumkin created this gist Feb 6, 2016.
    169 changes: 169 additions & 0 deletions sha-256.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,169 @@
    ;(function(){
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    /* SHA-256 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */
    /* */
    /* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
    /* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    /* jshint node:true *//* global define, escape, unescape */
    'use strict';


    /**
    * SHA-256 hash function reference implementation.
    *
    * @namespace
    */
    var Sha256 = {};


    /**
    * Generates SHA-256 hash of string.
    *
    * @param {string} msg - String to be hashed
    * @returns {string} Hash of msg as hex character string
    */
    Sha256.hash = function(msg) {
    // convert string to UTF-8, as SHA only deals with byte-streams
    msg = msg.utf8Encode();

    // constants [§4.2.2]
    var K = [
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ];
    // initial hash value [§5.3.1]
    var H = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ];

    // PREPROCESSING

    msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]

    // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
    var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
    var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
    var M = new Array(N);

    for (var i=0; i<N; i++) {
    M[i] = new Array(16);
    for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
    M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
    (msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
    } // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
    }
    // add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
    // note: most significant word would be (len-1)*8 >>> 32, but since JS converts
    // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
    M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]);
    M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;


    // HASH COMPUTATION [§6.1.2]

    var W = new Array(64); var a, b, c, d, e, f, g, h;
    for (var i=0; i<N; i++) {

    // 1 - prepare message schedule 'W'
    for (var t=0; t<16; t++) W[t] = M[i][t];
    for (var t=16; t<64; t++) W[t] = (Sha256.σ1(W[t-2]) + W[t-7] + Sha256.σ0(W[t-15]) + W[t-16]) & 0xffffffff;

    // 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value
    a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7];

    // 3 - main loop (note 'addition modulo 2^32')
    for (var t=0; t<64; t++) {
    var T1 = h + Sha256.Σ1(e) + Sha256.Ch(e, f, g) + K[t] + W[t];
    var T2 = Sha256.Σ0(a) + Sha256.Maj(a, b, c);
    h = g;
    g = f;
    f = e;
    e = (d + T1) & 0xffffffff;
    d = c;
    c = b;
    b = a;
    a = (T1 + T2) & 0xffffffff;
    }
    // 4 - compute the new intermediate hash value (note 'addition modulo 2^32')
    H[0] = (H[0]+a) & 0xffffffff;
    H[1] = (H[1]+b) & 0xffffffff;
    H[2] = (H[2]+c) & 0xffffffff;
    H[3] = (H[3]+d) & 0xffffffff;
    H[4] = (H[4]+e) & 0xffffffff;
    H[5] = (H[5]+f) & 0xffffffff;
    H[6] = (H[6]+g) & 0xffffffff;
    H[7] = (H[7]+h) & 0xffffffff;
    }

    return Sha256.toHexStr(H[0]) + Sha256.toHexStr(H[1]) + Sha256.toHexStr(H[2]) + Sha256.toHexStr(H[3]) +
    Sha256.toHexStr(H[4]) + Sha256.toHexStr(H[5]) + Sha256.toHexStr(H[6]) + Sha256.toHexStr(H[7]);
    };


    /**
    * Rotates right (circular right shift) value x by n positions [§3.2.4].
    * @private
    */
    Sha256.ROTR = function(n, x) {
    return (x >>> n) | (x << (32-n));
    };

    /**
    * Logical functions [§4.1.2].
    * @private
    */
    Sha256.Σ0 = function(x) { return Sha256.ROTR(2, x) ^ Sha256.ROTR(13, x) ^ Sha256.ROTR(22, x); };
    Sha256.Σ1 = function(x) { return Sha256.ROTR(6, x) ^ Sha256.ROTR(11, x) ^ Sha256.ROTR(25, x); };
    Sha256.σ0 = function(x) { return Sha256.ROTR(7, x) ^ Sha256.ROTR(18, x) ^ (x>>>3); };
    Sha256.σ1 = function(x) { return Sha256.ROTR(17, x) ^ Sha256.ROTR(19, x) ^ (x>>>10); };
    Sha256.Ch = function(x, y, z) { return (x & y) ^ (~x & z); };
    Sha256.Maj = function(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); };


    /**
    * Hexadecimal representation of a number.
    * @private
    */
    Sha256.toHexStr = function(n) {
    // note can't use toString(16) as it is implementation-dependant,
    // and in IE returns signed numbers when used on full words
    var s="", v;
    for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
    return s;
    };


    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


    /** Extend String object with method to encode multi-byte string to utf8
    * - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */
    if (typeof String.prototype.utf8Encode == 'undefined') {
    String.prototype.utf8Encode = function() {
    return unescape( encodeURIComponent( this ) );
    };
    }

    /** Extend String object with method to decode utf8 string to multi-byte */
    if (typeof String.prototype.utf8Decode == 'undefined') {
    String.prototype.utf8Decode = function() {
    try {
    return decodeURIComponent( escape( this ) );
    } catch (e) {
    return this; // invalid UTF-8? return as-is
    }
    };
    }


    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (typeof module != 'undefined' && module.exports) module.exports = Sha256; // CommonJs export
    if (typeof define == 'function' && define.amd) define([], function() { return Sha256; }); // AMD
    if (typeof window !== 'undefined') window.Sha256 = Sha256;
    })();