sign.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. 'use strict';
  2. // much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
  3. var Buffer = require('safe-buffer').Buffer;
  4. var createHmac = require('create-hmac');
  5. var crt = require('browserify-rsa');
  6. var EC = require('elliptic').ec;
  7. var BN = require('bn.js');
  8. var parseKeys = require('parse-asn1');
  9. var curves = require('./curves.json');
  10. var RSA_PKCS1_PADDING = 1;
  11. function sign(hash, key, hashType, signType, tag) {
  12. var priv = parseKeys(key);
  13. if (priv.curve) {
  14. // rsa keys can be interpreted as ecdsa ones in openssl
  15. if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong private key type'); }
  16. return ecSign(hash, priv);
  17. } else if (priv.type === 'dsa') {
  18. if (signType !== 'dsa') { throw new Error('wrong private key type'); }
  19. return dsaSign(hash, priv, hashType);
  20. }
  21. if (signType !== 'rsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong private key type'); }
  22. if (key.padding !== undefined && key.padding !== RSA_PKCS1_PADDING) { throw new Error('illegal or unsupported padding mode'); }
  23. hash = Buffer.concat([tag, hash]);
  24. var len = priv.modulus.byteLength();
  25. var pad = [0, 1];
  26. while (hash.length + pad.length + 1 < len) { pad.push(0xff); }
  27. pad.push(0x00);
  28. var i = -1;
  29. while (++i < hash.length) { pad.push(hash[i]); }
  30. var out = crt(pad, priv);
  31. return out;
  32. }
  33. function ecSign(hash, priv) {
  34. var curveId = curves[priv.curve.join('.')];
  35. if (!curveId) { throw new Error('unknown curve ' + priv.curve.join('.')); }
  36. var curve = new EC(curveId);
  37. var key = curve.keyFromPrivate(priv.privateKey);
  38. var out = key.sign(hash);
  39. return Buffer.from(out.toDER());
  40. }
  41. function dsaSign(hash, priv, algo) {
  42. var x = priv.params.priv_key;
  43. var p = priv.params.p;
  44. var q = priv.params.q;
  45. var g = priv.params.g;
  46. var r = new BN(0);
  47. var k;
  48. var H = bits2int(hash, q).mod(q);
  49. var s = false;
  50. var kv = getKey(x, q, hash, algo);
  51. while (s === false) {
  52. k = makeKey(q, kv, algo);
  53. r = makeR(g, k, p, q);
  54. s = k.invm(q).imul(H.add(x.mul(r))).mod(q);
  55. if (s.cmpn(0) === 0) {
  56. s = false;
  57. r = new BN(0);
  58. }
  59. }
  60. return toDER(r, s);
  61. }
  62. function toDER(r, s) {
  63. r = r.toArray();
  64. s = s.toArray();
  65. // Pad values
  66. if (r[0] & 0x80) { r = [0].concat(r); }
  67. if (s[0] & 0x80) { s = [0].concat(s); }
  68. var total = r.length + s.length + 4;
  69. var res = [
  70. 0x30, total, 0x02, r.length
  71. ];
  72. res = res.concat(r, [0x02, s.length], s);
  73. return Buffer.from(res);
  74. }
  75. function getKey(x, q, hash, algo) {
  76. x = Buffer.from(x.toArray());
  77. if (x.length < q.byteLength()) {
  78. var zeros = Buffer.alloc(q.byteLength() - x.length);
  79. x = Buffer.concat([zeros, x]);
  80. }
  81. var hlen = hash.length;
  82. var hbits = bits2octets(hash, q);
  83. var v = Buffer.alloc(hlen);
  84. v.fill(1);
  85. var k = Buffer.alloc(hlen);
  86. k = createHmac(algo, k).update(v).update(Buffer.from([0])).update(x).update(hbits).digest();
  87. v = createHmac(algo, k).update(v).digest();
  88. k = createHmac(algo, k).update(v).update(Buffer.from([1])).update(x).update(hbits).digest();
  89. v = createHmac(algo, k).update(v).digest();
  90. return { k: k, v: v };
  91. }
  92. function bits2int(obits, q) {
  93. var bits = new BN(obits);
  94. var shift = (obits.length << 3) - q.bitLength();
  95. if (shift > 0) { bits.ishrn(shift); }
  96. return bits;
  97. }
  98. function bits2octets(bits, q) {
  99. bits = bits2int(bits, q);
  100. bits = bits.mod(q);
  101. var out = Buffer.from(bits.toArray());
  102. if (out.length < q.byteLength()) {
  103. var zeros = Buffer.alloc(q.byteLength() - out.length);
  104. out = Buffer.concat([zeros, out]);
  105. }
  106. return out;
  107. }
  108. function makeKey(q, kv, algo) {
  109. var t;
  110. var k;
  111. do {
  112. t = Buffer.alloc(0);
  113. while (t.length * 8 < q.bitLength()) {
  114. kv.v = createHmac(algo, kv.k).update(kv.v).digest();
  115. t = Buffer.concat([t, kv.v]);
  116. }
  117. k = bits2int(t, q);
  118. kv.k = createHmac(algo, kv.k).update(kv.v).update(Buffer.from([0])).digest();
  119. kv.v = createHmac(algo, kv.k).update(kv.v).digest();
  120. } while (k.cmp(q) !== -1);
  121. return k;
  122. }
  123. function makeR(g, k, p, q) {
  124. return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q);
  125. }
  126. module.exports = sign;
  127. module.exports.getKey = getKey;
  128. module.exports.makeKey = makeKey;