source: trip-planner-front/node_modules/sshpk/lib/dhe.js@ 6c1585f

Last change on this file since 6c1585f was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.4 KB
Line 
1// Copyright 2017 Joyent, Inc.
2
3module.exports = {
4 DiffieHellman: DiffieHellman,
5 generateECDSA: generateECDSA,
6 generateED25519: generateED25519
7};
8
9var assert = require('assert-plus');
10var crypto = require('crypto');
11var Buffer = require('safer-buffer').Buffer;
12var algs = require('./algs');
13var utils = require('./utils');
14var nacl = require('tweetnacl');
15
16var Key = require('./key');
17var PrivateKey = require('./private-key');
18
19var CRYPTO_HAVE_ECDH = (crypto.createECDH !== undefined);
20
21var ecdh = require('ecc-jsbn');
22var ec = require('ecc-jsbn/lib/ec');
23var jsbn = require('jsbn').BigInteger;
24
25function DiffieHellman(key) {
26 utils.assertCompatible(key, Key, [1, 4], 'key');
27 this._isPriv = PrivateKey.isPrivateKey(key, [1, 3]);
28 this._algo = key.type;
29 this._curve = key.curve;
30 this._key = key;
31 if (key.type === 'dsa') {
32 if (!CRYPTO_HAVE_ECDH) {
33 throw (new Error('Due to bugs in the node 0.10 ' +
34 'crypto API, node 0.12.x or later is required ' +
35 'to use DH'));
36 }
37 this._dh = crypto.createDiffieHellman(
38 key.part.p.data, undefined,
39 key.part.g.data, undefined);
40 this._p = key.part.p;
41 this._g = key.part.g;
42 if (this._isPriv)
43 this._dh.setPrivateKey(key.part.x.data);
44 this._dh.setPublicKey(key.part.y.data);
45
46 } else if (key.type === 'ecdsa') {
47 if (!CRYPTO_HAVE_ECDH) {
48 this._ecParams = new X9ECParameters(this._curve);
49
50 if (this._isPriv) {
51 this._priv = new ECPrivate(
52 this._ecParams, key.part.d.data);
53 }
54 return;
55 }
56
57 var curve = {
58 'nistp256': 'prime256v1',
59 'nistp384': 'secp384r1',
60 'nistp521': 'secp521r1'
61 }[key.curve];
62 this._dh = crypto.createECDH(curve);
63 if (typeof (this._dh) !== 'object' ||
64 typeof (this._dh.setPrivateKey) !== 'function') {
65 CRYPTO_HAVE_ECDH = false;
66 DiffieHellman.call(this, key);
67 return;
68 }
69 if (this._isPriv)
70 this._dh.setPrivateKey(key.part.d.data);
71 this._dh.setPublicKey(key.part.Q.data);
72
73 } else if (key.type === 'curve25519') {
74 if (this._isPriv) {
75 utils.assertCompatible(key, PrivateKey, [1, 5], 'key');
76 this._priv = key.part.k.data;
77 }
78
79 } else {
80 throw (new Error('DH not supported for ' + key.type + ' keys'));
81 }
82}
83
84DiffieHellman.prototype.getPublicKey = function () {
85 if (this._isPriv)
86 return (this._key.toPublic());
87 return (this._key);
88};
89
90DiffieHellman.prototype.getPrivateKey = function () {
91 if (this._isPriv)
92 return (this._key);
93 else
94 return (undefined);
95};
96DiffieHellman.prototype.getKey = DiffieHellman.prototype.getPrivateKey;
97
98DiffieHellman.prototype._keyCheck = function (pk, isPub) {
99 assert.object(pk, 'key');
100 if (!isPub)
101 utils.assertCompatible(pk, PrivateKey, [1, 3], 'key');
102 utils.assertCompatible(pk, Key, [1, 4], 'key');
103
104 if (pk.type !== this._algo) {
105 throw (new Error('A ' + pk.type + ' key cannot be used in ' +
106 this._algo + ' Diffie-Hellman'));
107 }
108
109 if (pk.curve !== this._curve) {
110 throw (new Error('A key from the ' + pk.curve + ' curve ' +
111 'cannot be used with a ' + this._curve +
112 ' Diffie-Hellman'));
113 }
114
115 if (pk.type === 'dsa') {
116 assert.deepEqual(pk.part.p, this._p,
117 'DSA key prime does not match');
118 assert.deepEqual(pk.part.g, this._g,
119 'DSA key generator does not match');
120 }
121};
122
123DiffieHellman.prototype.setKey = function (pk) {
124 this._keyCheck(pk);
125
126 if (pk.type === 'dsa') {
127 this._dh.setPrivateKey(pk.part.x.data);
128 this._dh.setPublicKey(pk.part.y.data);
129
130 } else if (pk.type === 'ecdsa') {
131 if (CRYPTO_HAVE_ECDH) {
132 this._dh.setPrivateKey(pk.part.d.data);
133 this._dh.setPublicKey(pk.part.Q.data);
134 } else {
135 this._priv = new ECPrivate(
136 this._ecParams, pk.part.d.data);
137 }
138
139 } else if (pk.type === 'curve25519') {
140 var k = pk.part.k;
141 if (!pk.part.k)
142 k = pk.part.r;
143 this._priv = k.data;
144 if (this._priv[0] === 0x00)
145 this._priv = this._priv.slice(1);
146 this._priv = this._priv.slice(0, 32);
147 }
148 this._key = pk;
149 this._isPriv = true;
150};
151DiffieHellman.prototype.setPrivateKey = DiffieHellman.prototype.setKey;
152
153DiffieHellman.prototype.computeSecret = function (otherpk) {
154 this._keyCheck(otherpk, true);
155 if (!this._isPriv)
156 throw (new Error('DH exchange has not been initialized with ' +
157 'a private key yet'));
158
159 var pub;
160 if (this._algo === 'dsa') {
161 return (this._dh.computeSecret(
162 otherpk.part.y.data));
163
164 } else if (this._algo === 'ecdsa') {
165 if (CRYPTO_HAVE_ECDH) {
166 return (this._dh.computeSecret(
167 otherpk.part.Q.data));
168 } else {
169 pub = new ECPublic(
170 this._ecParams, otherpk.part.Q.data);
171 return (this._priv.deriveSharedSecret(pub));
172 }
173
174 } else if (this._algo === 'curve25519') {
175 pub = otherpk.part.A.data;
176 while (pub[0] === 0x00 && pub.length > 32)
177 pub = pub.slice(1);
178 var priv = this._priv;
179 assert.strictEqual(pub.length, 32);
180 assert.strictEqual(priv.length, 32);
181
182 var secret = nacl.box.before(new Uint8Array(pub),
183 new Uint8Array(priv));
184
185 return (Buffer.from(secret));
186 }
187
188 throw (new Error('Invalid algorithm: ' + this._algo));
189};
190
191DiffieHellman.prototype.generateKey = function () {
192 var parts = [];
193 var priv, pub;
194 if (this._algo === 'dsa') {
195 this._dh.generateKeys();
196
197 parts.push({name: 'p', data: this._p.data});
198 parts.push({name: 'q', data: this._key.part.q.data});
199 parts.push({name: 'g', data: this._g.data});
200 parts.push({name: 'y', data: this._dh.getPublicKey()});
201 parts.push({name: 'x', data: this._dh.getPrivateKey()});
202 this._key = new PrivateKey({
203 type: 'dsa',
204 parts: parts
205 });
206 this._isPriv = true;
207 return (this._key);
208
209 } else if (this._algo === 'ecdsa') {
210 if (CRYPTO_HAVE_ECDH) {
211 this._dh.generateKeys();
212
213 parts.push({name: 'curve',
214 data: Buffer.from(this._curve)});
215 parts.push({name: 'Q', data: this._dh.getPublicKey()});
216 parts.push({name: 'd', data: this._dh.getPrivateKey()});
217 this._key = new PrivateKey({
218 type: 'ecdsa',
219 curve: this._curve,
220 parts: parts
221 });
222 this._isPriv = true;
223 return (this._key);
224
225 } else {
226 var n = this._ecParams.getN();
227 var r = new jsbn(crypto.randomBytes(n.bitLength()));
228 var n1 = n.subtract(jsbn.ONE);
229 priv = r.mod(n1).add(jsbn.ONE);
230 pub = this._ecParams.getG().multiply(priv);
231
232 priv = Buffer.from(priv.toByteArray());
233 pub = Buffer.from(this._ecParams.getCurve().
234 encodePointHex(pub), 'hex');
235
236 this._priv = new ECPrivate(this._ecParams, priv);
237
238 parts.push({name: 'curve',
239 data: Buffer.from(this._curve)});
240 parts.push({name: 'Q', data: pub});
241 parts.push({name: 'd', data: priv});
242
243 this._key = new PrivateKey({
244 type: 'ecdsa',
245 curve: this._curve,
246 parts: parts
247 });
248 this._isPriv = true;
249 return (this._key);
250 }
251
252 } else if (this._algo === 'curve25519') {
253 var pair = nacl.box.keyPair();
254 priv = Buffer.from(pair.secretKey);
255 pub = Buffer.from(pair.publicKey);
256 priv = Buffer.concat([priv, pub]);
257 assert.strictEqual(priv.length, 64);
258 assert.strictEqual(pub.length, 32);
259
260 parts.push({name: 'A', data: pub});
261 parts.push({name: 'k', data: priv});
262 this._key = new PrivateKey({
263 type: 'curve25519',
264 parts: parts
265 });
266 this._isPriv = true;
267 return (this._key);
268 }
269
270 throw (new Error('Invalid algorithm: ' + this._algo));
271};
272DiffieHellman.prototype.generateKeys = DiffieHellman.prototype.generateKey;
273
274/* These are helpers for using ecc-jsbn (for node 0.10 compatibility). */
275
276function X9ECParameters(name) {
277 var params = algs.curves[name];
278 assert.object(params);
279
280 var p = new jsbn(params.p);
281 var a = new jsbn(params.a);
282 var b = new jsbn(params.b);
283 var n = new jsbn(params.n);
284 var h = jsbn.ONE;
285 var curve = new ec.ECCurveFp(p, a, b);
286 var G = curve.decodePointHex(params.G.toString('hex'));
287
288 this.curve = curve;
289 this.g = G;
290 this.n = n;
291 this.h = h;
292}
293X9ECParameters.prototype.getCurve = function () { return (this.curve); };
294X9ECParameters.prototype.getG = function () { return (this.g); };
295X9ECParameters.prototype.getN = function () { return (this.n); };
296X9ECParameters.prototype.getH = function () { return (this.h); };
297
298function ECPublic(params, buffer) {
299 this._params = params;
300 if (buffer[0] === 0x00)
301 buffer = buffer.slice(1);
302 this._pub = params.getCurve().decodePointHex(buffer.toString('hex'));
303}
304
305function ECPrivate(params, buffer) {
306 this._params = params;
307 this._priv = new jsbn(utils.mpNormalize(buffer));
308}
309ECPrivate.prototype.deriveSharedSecret = function (pubKey) {
310 assert.ok(pubKey instanceof ECPublic);
311 var S = pubKey._pub.multiply(this._priv);
312 return (Buffer.from(S.getX().toBigInteger().toByteArray()));
313};
314
315function generateED25519() {
316 var pair = nacl.sign.keyPair();
317 var priv = Buffer.from(pair.secretKey);
318 var pub = Buffer.from(pair.publicKey);
319 assert.strictEqual(priv.length, 64);
320 assert.strictEqual(pub.length, 32);
321
322 var parts = [];
323 parts.push({name: 'A', data: pub});
324 parts.push({name: 'k', data: priv.slice(0, 32)});
325 var key = new PrivateKey({
326 type: 'ed25519',
327 parts: parts
328 });
329 return (key);
330}
331
332/* Generates a new ECDSA private key on a given curve. */
333function generateECDSA(curve) {
334 var parts = [];
335 var key;
336
337 if (CRYPTO_HAVE_ECDH) {
338 /*
339 * Node crypto doesn't expose key generation directly, but the
340 * ECDH instances can generate keys. It turns out this just
341 * calls into the OpenSSL generic key generator, and we can
342 * read its output happily without doing an actual DH. So we
343 * use that here.
344 */
345 var osCurve = {
346 'nistp256': 'prime256v1',
347 'nistp384': 'secp384r1',
348 'nistp521': 'secp521r1'
349 }[curve];
350
351 var dh = crypto.createECDH(osCurve);
352 dh.generateKeys();
353
354 parts.push({name: 'curve',
355 data: Buffer.from(curve)});
356 parts.push({name: 'Q', data: dh.getPublicKey()});
357 parts.push({name: 'd', data: dh.getPrivateKey()});
358
359 key = new PrivateKey({
360 type: 'ecdsa',
361 curve: curve,
362 parts: parts
363 });
364 return (key);
365 } else {
366
367 var ecParams = new X9ECParameters(curve);
368
369 /* This algorithm taken from FIPS PUB 186-4 (section B.4.1) */
370 var n = ecParams.getN();
371 /*
372 * The crypto.randomBytes() function can only give us whole
373 * bytes, so taking a nod from X9.62, we round up.
374 */
375 var cByteLen = Math.ceil((n.bitLength() + 64) / 8);
376 var c = new jsbn(crypto.randomBytes(cByteLen));
377
378 var n1 = n.subtract(jsbn.ONE);
379 var priv = c.mod(n1).add(jsbn.ONE);
380 var pub = ecParams.getG().multiply(priv);
381
382 priv = Buffer.from(priv.toByteArray());
383 pub = Buffer.from(ecParams.getCurve().
384 encodePointHex(pub), 'hex');
385
386 parts.push({name: 'curve', data: Buffer.from(curve)});
387 parts.push({name: 'Q', data: pub});
388 parts.push({name: 'd', data: priv});
389
390 key = new PrivateKey({
391 type: 'ecdsa',
392 curve: curve,
393 parts: parts
394 });
395 return (key);
396 }
397}
Note: See TracBrowser for help on using the repository browser.