@swtc/sm.js
Version:
SM series cryptography in javascript implementation
160 lines (140 loc) • 3.19 kB
JavaScript
"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)
}