javascript 实现sm3哈希算法

674 阅读2分钟

各位看官直接上code,随copy随食用。

分别建三个js文件:

  • sm_utils.js

    var utils = exports

    utils.strToBytes = strToBytes

    function strToBytes(s) { var ch, st, re = []; for (var i = 0; i < s.length; i++ ) { ch = s.charCodeAt(i); // get char st = []; // set up "stack" do { st.push( ch & 0xFF ); // push byte to stack ch = ch >> 8; // shift value down by 1 byte } while ( ch ); re = re.concat( st.reverse() ); } return re; }

  • sm_sm3.js

    /**

    • SM3 hash algorithm */

    var utils = require('./sm_utils');

    /**

    • SM3 Hasher */ function SM3() { if (!(this instanceof SM3)) { return new SM3(); }

    this.reg = new Array(8); this.chunk = []; this.size = 0;

    this.reset(); } module.exports = SM3;

    SM3.prototype.reset = function() { this.reg[0] = 0x7380166f; this.reg[1] = 0x4914b2b9; this.reg[2] = 0x172442d7; this.reg[3] = 0xda8a0600; this.reg[4] = 0xa96f30bc; this.reg[5] = 0x163138aa; this.reg[6] = 0xe38dee4d; this.reg[7] = 0xb0fb0e4e; this.chunk = []; this.size = 0; }

    /**

    • Stream hashing method
    • Calling sum() to get hash of the whole data writed in. */ SM3.prototype.write = function(msg) { var m = (typeof msg === 'string') ? utils.strToBytes(msg) : msg; this.size += m.length; var i = 64 - this.chunk.length; if (m.length < i) { this.chunk = this.chunk.concat(m); return; }

    this.chunk = this.chunk.concat(m.slice(0, i)); while (this.chunk.length >= 64) { this._compress(this.chunk); if (i < m.length) { this.chunk = m.slice(i, Math.min(i + 64, m.length)); } else { this.chunk = []; } i += 64; } }

    /**

    • Get the 256-bit digest
    • If @msg is not null, the digest is for @msg,
    • else the digest is for previous inputs with write().
    • The output could be a byte array, or a hex string with @enc set to 'hex'
    • After calling sum(), the hasher will reset to the initial state. */ SM3.prototype.sum = function(msg, enc) { if (msg) { this.reset(); this.write(msg); }

    this._fill(); for (var i = 0; i < this.chunk.length; i += 64){ this._compress(this.chunk.slice(i, i+64)); }

    var digest = null; if (enc == 'hex') { digest = ""; for (var i = 0; i < 8; i++) { digest += this.reg[i].toString(16); } } else { var digest = new Array(32); for (var i = 0; i < 8; i++) { var h; h = this.reg[i]; digest[i4+3] = (h & 0xff) >>> 0; h >>>= 8; digest[i4+2] = (h & 0xff) >>> 0; h >>>= 8; digest[i4+1] = (h & 0xff) >>> 0; h >>>= 8; digest[i4] = (h & 0xff) >>> 0; } }

    this.reset(); return digest; }

    SM3.prototype._compress = function(m) { if (m < 64) { console.error("compress error: not enough data"); return; } var w = _expand(m); var r = this.reg.slice(0); for (var j = 0; j < 64; j++) { var ss1 = _rotl(r[0], 12) + r[4] + _rotl(_t(j), j) ss1 = (ss1 & 0xffffffff) >>> 0; ss1 = _rotl(ss1, 7);

    var ss2 = (ss1 ^ _rotl(r[0], 12)) >>> 0;
    
    var tt1 = _ff(j, r[0], r[1], r[2]);
    tt1 =  tt1 + r[3] + ss2 + w[j+68];
    tt1 = (tt1 & 0xffffffff) >>> 0;
    
    var tt2 = _gg(j, r[4], r[5], r[6]);
    tt2 = tt2 + r[7] + ss1 + w[j];
    tt2 = (tt2 & 0xffffffff) >>> 0;
    
    r[3] = r[2];
    r[2] = _rotl(r[1], 9);
    r[1] = r[0];
    r[0] = tt1;
    r[7] = r[6]
    r[6] = _rotl(r[5], 19);
    r[5] = r[4];
    r[4] = (tt2 ^ _rotl(tt2, 9) ^ _rotl(tt2, 17)) >>> 0;
    

    }

    for (var i = 0; i < 8; i++) { this.reg[i] = (this.reg[i] ^ r[i]) >>> 0; } }

    // fill chunk to length of n*512 SM3.prototype._fill = function() { var l = this.size * 8; var len = this.chunk.push(0x80) % 64; if (64 - len < 8) { len -= 64; } for (; len < 56; len++) { this.chunk.push(0x00); }

    for (var i = 0; i < 4; i++) { var hi = Math.floor(l / 0x100000000); this.chunk.push((hi >>> ((3 - i) * 8)) & 0xff); } for (var i = 0; i < 4; i++) { this.chunk.push((l >>> ((3 - i) * 8)) & 0xff); }

    }

    function _expand(b) { var w = new Array(132); for (var i = 0; i < 16; i++) { w[i] = b[i4] << 24; w[i] |= b[i4+1] << 16; w[i] |= b[i4+2] << 8; w[i] |= b[i4+3]; w[i] >>>= 0; }

    for (var j = 16; j < 68; j++) { var x; x = w[j-16] ^ w[j-9] ^ _rotl(w[j-3], 15); x = x ^ _rotl(x, 15) ^ _rotl(x, 23); w[j] = (x ^ _rotl(w[j-13], 7) ^ w[j-6]) >>> 0; }

    for (var j = 0; j < 64; j++) { w[j+68] = (w[j] ^ w[j+4]) >>> 0; }

    return w; }

    function _rotl(x, n) { n %= 32; return ((x << n) | (x >>> (32 - n))) >>> 0; }

    function _t(j) { if (0 <= j && j < 16) { return 0x79cc4519; } else if (16 <= j && j < 64) { return 0x7a879d8a; } else { console.error("invalid j for constant Tj"); } }

    function _ff(j, x, y, z) { if (0 <= j && j < 16) { return (x ^ y ^ z) >>> 0; } else if (16 <= j && j < 64) { return ((x & y) | (x & z) | (y & z)) >>> 0; } else { console.error("invalid j for bool function FF"); return 0; } }

    function _gg(j, x, y, z) { if (0 <= j && j < 16) { return (x ^ y ^ z) >>> 0; } else if (16 <= j && j < 64) { return ((x & y) | (~x & z)) >>> 0; } else { console.error("invalid j for bool function GG"); return 0; } }

  • SM3Sign.js

    var sm3 = require('./sm_sm3');

    function sm3Digest(msg){ var _sm3 = new sm3(); var rawData = Array.from(msg); var digest = _sm3.sum(rawData); var hashHex = Array.from(digest, function(byte) {return ('0' + (byte & 0xFF).toString(16)).slice(-2);}).join(''); return hashHex; }

    exports.sm3Digest = sm3Digest;

一招毙命 , 打完收工,✿✿ヽ(°▽°)ノ✿

如果喜欢我的文章请用鞭子三连。