UNPKG

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