195 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			195 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | var BN = require("./bn.js"); | ||
|  | 
 | ||
|  | var MillerRabin = require("./miller-rabin.js"); | ||
|  | 
 | ||
|  | 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 Buffer = require("./safe-buffer.js").Buffer; | ||
|  | 
 | ||
|  | var primes = require("./generatePrime.js"); | ||
|  | 
 | ||
|  | var randomBytes = require("./randombytes.js"); | ||
|  | 
 | ||
|  | 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 = 128; | ||
|  |   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); | ||
|  |   } | ||
|  | } |