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.
		
		
		
		
		
			
		
			
				
					
					
						
							164 lines
						
					
					
						
							3.8 KiB
						
					
					
				
			
		
		
	
	
							164 lines
						
					
					
						
							3.8 KiB
						
					
					
				var BN = require('bn.js'); | 
						|
var MillerRabin = require('miller-rabin'); | 
						|
var millerRabin = new MillerRabin(); | 
						|
var TWENTYFOUR = new BN(24); | 
						|
var ELEVEN = new BN(11); | 
						|
var TEN = new BN(10); | 
						|
var THREE = new BN(3); | 
						|
var SEVEN = new BN(7); | 
						|
var primes = require('./generatePrime'); | 
						|
var randomBytes = require('randombytes'); | 
						|
module.exports = DH; | 
						|
 | 
						|
function setPublicKey(pub, enc) { | 
						|
  enc = enc || 'utf8'; | 
						|
  if (!Buffer.isBuffer(pub)) { | 
						|
    pub = new Buffer(pub, enc); | 
						|
  } | 
						|
  this._pub = new BN(pub); | 
						|
  return this; | 
						|
} | 
						|
 | 
						|
function setPrivateKey(priv, enc) { | 
						|
  enc = enc || 'utf8'; | 
						|
  if (!Buffer.isBuffer(priv)) { | 
						|
    priv = new Buffer(priv, enc); | 
						|
  } | 
						|
  this._priv = new BN(priv); | 
						|
  return this; | 
						|
} | 
						|
 | 
						|
var primeCache = {}; | 
						|
function checkPrime(prime, generator) { | 
						|
  var gen = generator.toString('hex'); | 
						|
  var hex = [gen, prime.toString(16)].join('_'); | 
						|
  if (hex in primeCache) { | 
						|
    return primeCache[hex]; | 
						|
  } | 
						|
  var error = 0; | 
						|
 | 
						|
  if (prime.isEven() || | 
						|
    !primes.simpleSieve || | 
						|
    !primes.fermatTest(prime) || | 
						|
    !millerRabin.test(prime)) { | 
						|
    //not a prime so +1 | 
						|
    error += 1; | 
						|
 | 
						|
    if (gen === '02' || gen === '05') { | 
						|
      // we'd be able to check the generator | 
						|
      // it would fail so +8 | 
						|
      error += 8; | 
						|
    } else { | 
						|
      //we wouldn't be able to test the generator | 
						|
      // so +4 | 
						|
      error += 4; | 
						|
    } | 
						|
    primeCache[hex] = error; | 
						|
    return error; | 
						|
  } | 
						|
  if (!millerRabin.test(prime.shrn(1))) { | 
						|
    //not a safe prime | 
						|
    error += 2; | 
						|
  } | 
						|
  var rem; | 
						|
  switch (gen) { | 
						|
    case '02': | 
						|
      if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) { | 
						|
        // unsuidable generator | 
						|
        error += 8; | 
						|
      } | 
						|
      break; | 
						|
    case '05': | 
						|
      rem = prime.mod(TEN); | 
						|
      if (rem.cmp(THREE) && rem.cmp(SEVEN)) { | 
						|
        // prime mod 10 needs to equal 3 or 7 | 
						|
        error += 8; | 
						|
      } | 
						|
      break; | 
						|
    default: | 
						|
      error += 4; | 
						|
  } | 
						|
  primeCache[hex] = error; | 
						|
  return error; | 
						|
} | 
						|
 | 
						|
function DH(prime, generator, malleable) { | 
						|
  this.setGenerator(generator); | 
						|
  this.__prime = new BN(prime); | 
						|
  this._prime = BN.mont(this.__prime); | 
						|
  this._primeLen = prime.length; | 
						|
  this._pub = undefined; | 
						|
  this._priv = undefined; | 
						|
  this._primeCode = undefined; | 
						|
  if (malleable) { | 
						|
    this.setPublicKey = setPublicKey; | 
						|
    this.setPrivateKey = setPrivateKey; | 
						|
  } else { | 
						|
    this._primeCode = 8; | 
						|
  } | 
						|
} | 
						|
Object.defineProperty(DH.prototype, 'verifyError', { | 
						|
  enumerable: true, | 
						|
  get: function () { | 
						|
    if (typeof this._primeCode !== 'number') { | 
						|
      this._primeCode = checkPrime(this.__prime, this.__gen); | 
						|
    } | 
						|
    return this._primeCode; | 
						|
  } | 
						|
}); | 
						|
DH.prototype.generateKeys = function () { | 
						|
  if (!this._priv) { | 
						|
    this._priv = new BN(randomBytes(this._primeLen)); | 
						|
  } | 
						|
  this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed(); | 
						|
  return this.getPublicKey(); | 
						|
}; | 
						|
 | 
						|
DH.prototype.computeSecret = function (other) { | 
						|
  other = new BN(other); | 
						|
  other = other.toRed(this._prime); | 
						|
  var secret = other.redPow(this._priv).fromRed(); | 
						|
  var out = new Buffer(secret.toArray()); | 
						|
  var prime = this.getPrime(); | 
						|
  if (out.length < prime.length) { | 
						|
    var front = new Buffer(prime.length - out.length); | 
						|
    front.fill(0); | 
						|
    out = Buffer.concat([front, out]); | 
						|
  } | 
						|
  return out; | 
						|
}; | 
						|
 | 
						|
DH.prototype.getPublicKey = function getPublicKey(enc) { | 
						|
  return formatReturnValue(this._pub, enc); | 
						|
}; | 
						|
 | 
						|
DH.prototype.getPrivateKey = function getPrivateKey(enc) { | 
						|
  return formatReturnValue(this._priv, enc); | 
						|
}; | 
						|
 | 
						|
DH.prototype.getPrime = function (enc) { | 
						|
  return formatReturnValue(this.__prime, enc); | 
						|
}; | 
						|
 | 
						|
DH.prototype.getGenerator = function (enc) { | 
						|
  return formatReturnValue(this._gen, enc); | 
						|
}; | 
						|
 | 
						|
DH.prototype.setGenerator = function (gen, enc) { | 
						|
  enc = enc || 'utf8'; | 
						|
  if (!Buffer.isBuffer(gen)) { | 
						|
    gen = new Buffer(gen, enc); | 
						|
  } | 
						|
  this.__gen = gen; | 
						|
  this._gen = new BN(gen); | 
						|
  return this; | 
						|
}; | 
						|
 | 
						|
function formatReturnValue(bn, enc) { | 
						|
  var buf = new Buffer(bn.toArray()); | 
						|
  if (!enc) { | 
						|
    return buf; | 
						|
  } else { | 
						|
    return buf.toString(enc); | 
						|
  } | 
						|
}
 | 
						|
 |