Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80552 views
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
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
22
function 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
31
var primeCache = {};
32
function 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
85
function defineError (self, error) {
86
try {
87
Object.defineProperty(self, 'verifyError', {
88
enumerable: true,
89
value: error,
90
writable: false
91
});
92
} catch(e) {
93
self.verifyError = error;
94
}
95
}
96
function DH(prime, generator, malleable) {
97
this.setGenerator(generator);
98
this.__prime = new BN(prime);
99
this._prime = BN.mont(this.__prime);
100
this._primeLen = prime.length;
101
this._pub = void 0;
102
this._priv = void 0;
103
104
if (malleable) {
105
this.setPublicKey = setPublicKey;
106
this.setPrivateKey = setPrivateKey;
107
defineError(this, checkPrime(this.__prime, generator));
108
} else {
109
defineError(this, 8);
110
}
111
}
112
113
DH.prototype.generateKeys = function () {
114
if (!this._priv) {
115
this._priv = new BN(randomBytes(this._primeLen));
116
}
117
this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed();
118
return this.getPublicKey();
119
};
120
121
DH.prototype.computeSecret = function (other) {
122
other = new BN(other);
123
other = other.toRed(this._prime);
124
var secret = other.redPow(this._priv).fromRed();
125
var out = new Buffer(secret.toArray());
126
var prime = this.getPrime();
127
if (out.length < prime.length) {
128
var front = new Buffer(prime.length - out.length);
129
front.fill(0);
130
out = Buffer.concat([front, out]);
131
}
132
return out;
133
};
134
135
DH.prototype.getPublicKey = function getPublicKey(enc) {
136
return formatReturnValue(this._pub, enc);
137
};
138
139
DH.prototype.getPrivateKey = function getPrivateKey(enc) {
140
return formatReturnValue(this._priv, enc);
141
};
142
143
DH.prototype.getPrime = function (enc) {
144
return formatReturnValue(this.__prime, enc);
145
};
146
147
DH.prototype.getGenerator = function (enc) {
148
return formatReturnValue(this._gen, enc);
149
};
150
151
DH.prototype.setGenerator = function (gen, enc) {
152
enc = enc || 'utf8';
153
if (!Buffer.isBuffer(gen)) {
154
gen = new Buffer(gen, enc);
155
}
156
this._gen = new BN(gen);
157
return this;
158
};
159
160
function formatReturnValue(bn, enc) {
161
var buf = new Buffer(bn.toArray());
162
if (!enc) {
163
return buf;
164
} else {
165
return buf.toString(enc);
166
}
167
}
168