dh.js 4.0 KB

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