import createHmac from "../create-hmac"; import crt from "../browserify-rsa"; import elliptic from "../elliptic"; import BN from "../bn.js"; import parseKeys from "../parse-asn1"; import * as curves from "./curves.json"; var EC = elliptic.ec; function sign(hash, key, hashType, signType, tag) { var priv = parseKeys(key); if (priv.curve) { // rsa keys can be interpreted as ecdsa ones in openssl if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type'); return ecSign(hash, priv); } else if (priv.type === 'dsa') { if (signType !== 'dsa') throw new Error('wrong private key type'); return dsaSign(hash, priv, hashType); } else { if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type'); } hash = Buffer.concat([tag, hash]); var len = priv.modulus.byteLength(); var pad = [0, 1]; while (hash.length + pad.length + 1 < len) pad.push(0xff); pad.push(0x00); var i = -1; while (++i < hash.length) pad.push(hash[i]); var out = crt(pad, priv); return out; } function ecSign(hash, priv) { var curveId = curves[priv.curve.join('.')]; if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.')); var curve = new EC(curveId); var key = curve.keyFromPrivate(priv.privateKey); var out = key.sign(hash); return Buffer.from(out.toDER()); } function dsaSign(hash, priv, algo) { var x = priv.params.priv_key; var p = priv.params.p; var q = priv.params.q; var g = priv.params.g; var r = new BN(0); var k; var H = bits2int(hash, q).mod(q); var s = false; var kv = getKey(x, q, hash, algo); while (s === false) { k = makeKey(q, kv, algo); r = makeR(g, k, p, q); s = k.invm(q).imul(H.add(x.mul(r))).mod(q); if (s.cmpn(0) === 0) { s = false; r = new BN(0); } } return toDER(r, s); } function toDER(r, s) { r = r.toArray(); s = s.toArray(); // Pad values if (r[0] & 0x80) r = [0].concat(r); if (s[0] & 0x80) s = [0].concat(s); var total = r.length + s.length + 4; var res = [0x30, total, 0x02, r.length]; res = res.concat(r, [0x02, s.length], s); return Buffer.from(res); } function getKey(x, q, hash, algo) { x = Buffer.from(x.toArray()); if (x.length < q.byteLength()) { var zeros = Buffer.alloc(q.byteLength() - x.length); x = Buffer.concat([zeros, x]); } var hlen = hash.length; var hbits = bits2octets(hash, q); var v = Buffer.alloc(hlen); v.fill(1); var k = Buffer.alloc(hlen); k = createHmac(algo, k).update(v).update(Buffer.from([0])).update(x).update(hbits).digest(); v = createHmac(algo, k).update(v).digest(); k = createHmac(algo, k).update(v).update(Buffer.from([1])).update(x).update(hbits).digest(); v = createHmac(algo, k).update(v).digest(); return { k: k, v: v }; } function bits2int(obits, q) { var bits = new BN(obits); var shift = (obits.length << 3) - q.bitLength(); if (shift > 0) bits.ishrn(shift); return bits; } function bits2octets(bits, q) { bits = bits2int(bits, q); bits = bits.mod(q); var out = Buffer.from(bits.toArray()); if (out.length < q.byteLength()) { var zeros = Buffer.alloc(q.byteLength() - out.length); out = Buffer.concat([zeros, out]); } return out; } function makeKey(q, kv, algo) { var t; var k; do { t = Buffer.alloc(0); while (t.length * 8 < q.bitLength()) { kv.v = createHmac(algo, kv.k).update(kv.v).digest(); t = Buffer.concat([t, kv.v]); } k = bits2int(t, q); kv.k = createHmac(algo, kv.k).update(kv.v).update(Buffer.from([0])).digest(); kv.v = createHmac(algo, kv.k).update(kv.v).digest(); } while (k.cmp(q) !== -1); return k; } function makeR(g, k, p, q) { return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q); } export default sign; export { getKey }; export { makeKey };