dh.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. var BN = require('bn.js');
  2. var MillerRabin = require('miller-rabin');
  3. var millerRabin = new MillerRabin();
  4. var TWENTYFOUR = new BN(24);
  5. var ELEVEN = new BN(11);
  6. var TEN = new BN(10);
  7. var THREE = new BN(3);
  8. var SEVEN = new BN(7);
  9. var primes = require('./generatePrime');
  10. var randomBytes = require('randombytes');
  11. module.exports = DH;
  12. function setPublicKey(pub, enc) {
  13. enc = enc || 'utf8';
  14. if (!Buffer.isBuffer(pub)) {
  15. pub = new Buffer(pub, enc);
  16. }
  17. this._pub = new BN(pub);
  18. return this;
  19. }
  20. function setPrivateKey(priv, enc) {
  21. enc = enc || 'utf8';
  22. if (!Buffer.isBuffer(priv)) {
  23. priv = new Buffer(priv, enc);
  24. }
  25. this._priv = new BN(priv);
  26. return this;
  27. }
  28. var primeCache = {};
  29. function checkPrime(prime, generator) {
  30. var gen = generator.toString('hex');
  31. var hex = [gen, prime.toString(16)].join('_');
  32. if (hex in primeCache) {
  33. return primeCache[hex];
  34. }
  35. var error = 0;
  36. if (prime.isEven() ||
  37. !primes.simpleSieve ||
  38. !primes.fermatTest(prime) ||
  39. !millerRabin.test(prime)) {
  40. //not a prime so +1
  41. error += 1;
  42. if (gen === '02' || gen === '05') {
  43. // we'd be able to check the generator
  44. // it would fail so +8
  45. error += 8;
  46. } else {
  47. //we wouldn't be able to test the generator
  48. // so +4
  49. error += 4;
  50. }
  51. primeCache[hex] = error;
  52. return error;
  53. }
  54. if (!millerRabin.test(prime.shrn(1))) {
  55. //not a safe prime
  56. error += 2;
  57. }
  58. var rem;
  59. switch (gen) {
  60. case '02':
  61. if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) {
  62. // unsuidable generator
  63. error += 8;
  64. }
  65. break;
  66. case '05':
  67. rem = prime.mod(TEN);
  68. if (rem.cmp(THREE) && rem.cmp(SEVEN)) {
  69. // prime mod 10 needs to equal 3 or 7
  70. error += 8;
  71. }
  72. break;
  73. default:
  74. error += 4;
  75. }
  76. primeCache[hex] = error;
  77. return error;
  78. }
  79. function DH(prime, generator, malleable) {
  80. this.setGenerator(generator);
  81. this.__prime = new BN(prime);
  82. this._prime = BN.mont(this.__prime);
  83. this._primeLen = prime.length;
  84. this._pub = undefined;
  85. this._priv = undefined;
  86. this._primeCode = undefined;
  87. if (malleable) {
  88. this.setPublicKey = setPublicKey;
  89. this.setPrivateKey = setPrivateKey;
  90. } else {
  91. this._primeCode = 8;
  92. }
  93. }
  94. Object.defineProperty(DH.prototype, 'verifyError', {
  95. enumerable: true,
  96. get: function () {
  97. if (typeof this._primeCode !== 'number') {
  98. this._primeCode = checkPrime(this.__prime, this.__gen);
  99. }
  100. return this._primeCode;
  101. }
  102. });
  103. DH.prototype.generateKeys = function () {
  104. if (!this._priv) {
  105. this._priv = new BN(randomBytes(this._primeLen));
  106. }
  107. this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed();
  108. return this.getPublicKey();
  109. };
  110. DH.prototype.computeSecret = function (other) {
  111. other = new BN(other);
  112. other = other.toRed(this._prime);
  113. var secret = other.redPow(this._priv).fromRed();
  114. var out = new Buffer(secret.toArray());
  115. var prime = this.getPrime();
  116. if (out.length < prime.length) {
  117. var front = new Buffer(prime.length - out.length);
  118. front.fill(0);
  119. out = Buffer.concat([front, out]);
  120. }
  121. return out;
  122. };
  123. DH.prototype.getPublicKey = function getPublicKey(enc) {
  124. return formatReturnValue(this._pub, enc);
  125. };
  126. DH.prototype.getPrivateKey = function getPrivateKey(enc) {
  127. return formatReturnValue(this._priv, enc);
  128. };
  129. DH.prototype.getPrime = function (enc) {
  130. return formatReturnValue(this.__prime, enc);
  131. };
  132. DH.prototype.getGenerator = function (enc) {
  133. return formatReturnValue(this._gen, enc);
  134. };
  135. DH.prototype.setGenerator = function (gen, enc) {
  136. enc = enc || 'utf8';
  137. if (!Buffer.isBuffer(gen)) {
  138. gen = new Buffer(gen, enc);
  139. }
  140. this.__gen = gen;
  141. this._gen = new BN(gen);
  142. return this;
  143. };
  144. function formatReturnValue(bn, enc) {
  145. var buf = new Buffer(bn.toArray());
  146. if (!enc) {
  147. return buf;
  148. } else {
  149. return buf.toString(enc);
  150. }
  151. }