123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- 'use strict';
- // much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
- var Buffer = require('safe-buffer').Buffer;
- var createHmac = require('create-hmac');
- var crt = require('browserify-rsa');
- var EC = require('elliptic').ec;
- var BN = require('bn.js');
- var parseKeys = require('parse-asn1');
- var curves = require('./curves.json');
- var RSA_PKCS1_PADDING = 1;
- 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);
- }
- if (signType !== 'rsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong private key type'); }
- if (key.padding !== undefined && key.padding !== RSA_PKCS1_PADDING) { throw new Error('illegal or unsupported padding mode'); }
- 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);
- }
- module.exports = sign;
- module.exports.getKey = getKey;
- module.exports.makeKey = makeKey;
|