UNPKG

@swtc/sm.js

Version:

SM series cryptography in javascript implementation

160 lines (140 loc) 3.19 kB
"use strict" var BN = require("bn.js") var utils = require("minimalistic-crypto-utils") var assert = require("minimalistic-assert") function Signature(options, enc) { if (options instanceof Signature) return options if (this._importDER(options, enc)) return assert(options.r && options.s, "Signature without r or s") this.r = new BN(options.r, 16) this.s = new BN(options.s, 16) if (options.recoveryParam === undefined) this.recoveryParam = null else this.recoveryParam = options.recoveryParam } module.exports = Signature function Position() { this.place = 0 } function getLength(buf, p) { var initial = buf[p.place++] if (!(initial & 0x80)) { return initial } var octetLen = initial & 0xf // Indefinite length or overflow if (octetLen === 0 || octetLen > 4) { return false } var val = 0 for (var i = 0, off = p.place; i < octetLen; i++, off++) { val <<= 8 val |= buf[off] val >>>= 0 } // Leading zeroes if (val <= 0x7f) { return false } p.place = off return val } function rmPadding(buf) { var i = 0 var len = buf.length - 1 while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) { i++ } if (i === 0) { return buf } return buf.slice(i) } Signature.prototype._importDER = function _importDER(data, enc) { data = utils.toArray(data, enc) var p = new Position() if (data[p.place++] !== 0x30) { return false } var len = getLength(data, p) if (len === false) { return false } if (len + p.place !== data.length) { return false } if (data[p.place++] !== 0x02) { return false } var rlen = getLength(data, p) if (rlen === false) { return false } var r = data.slice(p.place, rlen + p.place) p.place += rlen if (data[p.place++] !== 0x02) { return false } var slen = getLength(data, p) if (slen === false) { return false } if (data.length !== slen + p.place) { return false } var s = data.slice(p.place, slen + p.place) if (r[0] === 0) { if (r[1] & 0x80) { r = r.slice(1) } else { // Leading zeroes return false } } if (s[0] === 0) { if (s[1] & 0x80) { s = s.slice(1) } else { // Leading zeroes return false } } this.r = new BN(r) this.s = new BN(s) this.recoveryParam = null return true } function constructLength(arr, len) { if (len < 0x80) { arr.push(len) return } var octets = 1 + ((Math.log(len) / Math.LN2) >>> 3) arr.push(octets | 0x80) while (--octets) { arr.push((len >>> (octets << 3)) & 0xff) } arr.push(len) } Signature.prototype.toDER = function toDER(enc) { var r = this.r.toArray() var s = this.s.toArray() // Pad values if (r[0] & 0x80) r = [0].concat(r) // Pad values if (s[0] & 0x80) s = [0].concat(s) r = rmPadding(r) s = rmPadding(s) while (!s[0] && !(s[1] & 0x80)) { s = s.slice(1) } var arr = [0x02] constructLength(arr, r.length) arr = arr.concat(r) arr.push(0x02) constructLength(arr, s.length) var backHalf = arr.concat(s) var res = [0x30] constructLength(res, backHalf.length) res = res.concat(backHalf) return utils.encode(res, enc) }