You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.1 KiB
134 lines
4.1 KiB
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 };
|
|
|