398 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			398 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2017 Joyent, Inc.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = {
							 | 
						||
| 
								 | 
							
									DiffieHellman: DiffieHellman,
							 | 
						||
| 
								 | 
							
									generateECDSA: generateECDSA,
							 | 
						||
| 
								 | 
							
									generateED25519: generateED25519
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var assert = require('assert-plus');
							 | 
						||
| 
								 | 
							
								var crypto = require('crypto');
							 | 
						||
| 
								 | 
							
								var Buffer = require('safer-buffer').Buffer;
							 | 
						||
| 
								 | 
							
								var algs = require('./algs');
							 | 
						||
| 
								 | 
							
								var utils = require('./utils');
							 | 
						||
| 
								 | 
							
								var nacl = require('tweetnacl');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var Key = require('./key');
							 | 
						||
| 
								 | 
							
								var PrivateKey = require('./private-key');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var CRYPTO_HAVE_ECDH = (crypto.createECDH !== undefined);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var ecdh = require('ecc-jsbn');
							 | 
						||
| 
								 | 
							
								var ec = require('ecc-jsbn/lib/ec');
							 | 
						||
| 
								 | 
							
								var jsbn = require('jsbn').BigInteger;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function DiffieHellman(key) {
							 | 
						||
| 
								 | 
							
									utils.assertCompatible(key, Key, [1, 4], 'key');
							 | 
						||
| 
								 | 
							
									this._isPriv = PrivateKey.isPrivateKey(key, [1, 3]);
							 | 
						||
| 
								 | 
							
									this._algo = key.type;
							 | 
						||
| 
								 | 
							
									this._curve = key.curve;
							 | 
						||
| 
								 | 
							
									this._key = key;
							 | 
						||
| 
								 | 
							
									if (key.type === 'dsa') {
							 | 
						||
| 
								 | 
							
										if (!CRYPTO_HAVE_ECDH) {
							 | 
						||
| 
								 | 
							
											throw (new Error('Due to bugs in the node 0.10 ' +
							 | 
						||
| 
								 | 
							
											    'crypto API, node 0.12.x or later is required ' +
							 | 
						||
| 
								 | 
							
											    'to use DH'));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										this._dh = crypto.createDiffieHellman(
							 | 
						||
| 
								 | 
							
										    key.part.p.data, undefined,
							 | 
						||
| 
								 | 
							
										    key.part.g.data, undefined);
							 | 
						||
| 
								 | 
							
										this._p = key.part.p;
							 | 
						||
| 
								 | 
							
										this._g = key.part.g;
							 | 
						||
| 
								 | 
							
										if (this._isPriv)
							 | 
						||
| 
								 | 
							
											this._dh.setPrivateKey(key.part.x.data);
							 | 
						||
| 
								 | 
							
										this._dh.setPublicKey(key.part.y.data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (key.type === 'ecdsa') {
							 | 
						||
| 
								 | 
							
										if (!CRYPTO_HAVE_ECDH) {
							 | 
						||
| 
								 | 
							
											this._ecParams = new X9ECParameters(this._curve);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (this._isPriv) {
							 | 
						||
| 
								 | 
							
												this._priv = new ECPrivate(
							 | 
						||
| 
								 | 
							
												    this._ecParams, key.part.d.data);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var curve = {
							 | 
						||
| 
								 | 
							
											'nistp256': 'prime256v1',
							 | 
						||
| 
								 | 
							
											'nistp384': 'secp384r1',
							 | 
						||
| 
								 | 
							
											'nistp521': 'secp521r1'
							 | 
						||
| 
								 | 
							
										}[key.curve];
							 | 
						||
| 
								 | 
							
										this._dh = crypto.createECDH(curve);
							 | 
						||
| 
								 | 
							
										if (typeof (this._dh) !== 'object' ||
							 | 
						||
| 
								 | 
							
										    typeof (this._dh.setPrivateKey) !== 'function') {
							 | 
						||
| 
								 | 
							
											CRYPTO_HAVE_ECDH = false;
							 | 
						||
| 
								 | 
							
											DiffieHellman.call(this, key);
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (this._isPriv)
							 | 
						||
| 
								 | 
							
											this._dh.setPrivateKey(key.part.d.data);
							 | 
						||
| 
								 | 
							
										this._dh.setPublicKey(key.part.Q.data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (key.type === 'curve25519') {
							 | 
						||
| 
								 | 
							
										if (this._isPriv) {
							 | 
						||
| 
								 | 
							
											utils.assertCompatible(key, PrivateKey, [1, 5], 'key');
							 | 
						||
| 
								 | 
							
											this._priv = key.part.k.data;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										throw (new Error('DH not supported for ' + key.type + ' keys'));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.getPublicKey = function () {
							 | 
						||
| 
								 | 
							
									if (this._isPriv)
							 | 
						||
| 
								 | 
							
										return (this._key.toPublic());
							 | 
						||
| 
								 | 
							
									return (this._key);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.getPrivateKey = function () {
							 | 
						||
| 
								 | 
							
									if (this._isPriv)
							 | 
						||
| 
								 | 
							
										return (this._key);
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										return (undefined);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.getKey = DiffieHellman.prototype.getPrivateKey;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype._keyCheck = function (pk, isPub) {
							 | 
						||
| 
								 | 
							
									assert.object(pk, 'key');
							 | 
						||
| 
								 | 
							
									if (!isPub)
							 | 
						||
| 
								 | 
							
										utils.assertCompatible(pk, PrivateKey, [1, 3], 'key');
							 | 
						||
| 
								 | 
							
									utils.assertCompatible(pk, Key, [1, 4], 'key');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (pk.type !== this._algo) {
							 | 
						||
| 
								 | 
							
										throw (new Error('A ' + pk.type + ' key cannot be used in ' +
							 | 
						||
| 
								 | 
							
										    this._algo + ' Diffie-Hellman'));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (pk.curve !== this._curve) {
							 | 
						||
| 
								 | 
							
										throw (new Error('A key from the ' + pk.curve + ' curve ' +
							 | 
						||
| 
								 | 
							
										    'cannot be used with a ' + this._curve +
							 | 
						||
| 
								 | 
							
										    ' Diffie-Hellman'));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (pk.type === 'dsa') {
							 | 
						||
| 
								 | 
							
										assert.deepEqual(pk.part.p, this._p,
							 | 
						||
| 
								 | 
							
										    'DSA key prime does not match');
							 | 
						||
| 
								 | 
							
										assert.deepEqual(pk.part.g, this._g,
							 | 
						||
| 
								 | 
							
										    'DSA key generator does not match');
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.setKey = function (pk) {
							 | 
						||
| 
								 | 
							
									this._keyCheck(pk);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (pk.type === 'dsa') {
							 | 
						||
| 
								 | 
							
										this._dh.setPrivateKey(pk.part.x.data);
							 | 
						||
| 
								 | 
							
										this._dh.setPublicKey(pk.part.y.data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (pk.type === 'ecdsa') {
							 | 
						||
| 
								 | 
							
										if (CRYPTO_HAVE_ECDH) {
							 | 
						||
| 
								 | 
							
											this._dh.setPrivateKey(pk.part.d.data);
							 | 
						||
| 
								 | 
							
											this._dh.setPublicKey(pk.part.Q.data);
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											this._priv = new ECPrivate(
							 | 
						||
| 
								 | 
							
											    this._ecParams, pk.part.d.data);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (pk.type === 'curve25519') {
							 | 
						||
| 
								 | 
							
										var k = pk.part.k;
							 | 
						||
| 
								 | 
							
										if (!pk.part.k)
							 | 
						||
| 
								 | 
							
											k = pk.part.r;
							 | 
						||
| 
								 | 
							
										this._priv = k.data;
							 | 
						||
| 
								 | 
							
										if (this._priv[0] === 0x00)
							 | 
						||
| 
								 | 
							
											this._priv = this._priv.slice(1);
							 | 
						||
| 
								 | 
							
										this._priv = this._priv.slice(0, 32);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									this._key = pk;
							 | 
						||
| 
								 | 
							
									this._isPriv = true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.setPrivateKey = DiffieHellman.prototype.setKey;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.computeSecret = function (otherpk) {
							 | 
						||
| 
								 | 
							
									this._keyCheck(otherpk, true);
							 | 
						||
| 
								 | 
							
									if (!this._isPriv)
							 | 
						||
| 
								 | 
							
										throw (new Error('DH exchange has not been initialized with ' +
							 | 
						||
| 
								 | 
							
										    'a private key yet'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var pub;
							 | 
						||
| 
								 | 
							
									if (this._algo === 'dsa') {
							 | 
						||
| 
								 | 
							
										return (this._dh.computeSecret(
							 | 
						||
| 
								 | 
							
										    otherpk.part.y.data));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (this._algo === 'ecdsa') {
							 | 
						||
| 
								 | 
							
										if (CRYPTO_HAVE_ECDH) {
							 | 
						||
| 
								 | 
							
											return (this._dh.computeSecret(
							 | 
						||
| 
								 | 
							
											    otherpk.part.Q.data));
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											pub = new ECPublic(
							 | 
						||
| 
								 | 
							
											    this._ecParams, otherpk.part.Q.data);
							 | 
						||
| 
								 | 
							
											return (this._priv.deriveSharedSecret(pub));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (this._algo === 'curve25519') {
							 | 
						||
| 
								 | 
							
										pub = otherpk.part.A.data;
							 | 
						||
| 
								 | 
							
										while (pub[0] === 0x00 && pub.length > 32)
							 | 
						||
| 
								 | 
							
											pub = pub.slice(1);
							 | 
						||
| 
								 | 
							
										var priv = this._priv;
							 | 
						||
| 
								 | 
							
										assert.strictEqual(pub.length, 32);
							 | 
						||
| 
								 | 
							
										assert.strictEqual(priv.length, 32);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var secret = nacl.box.before(new Uint8Array(pub),
							 | 
						||
| 
								 | 
							
										    new Uint8Array(priv));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return (Buffer.from(secret));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									throw (new Error('Invalid algorithm: ' + this._algo));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.generateKey = function () {
							 | 
						||
| 
								 | 
							
									var parts = [];
							 | 
						||
| 
								 | 
							
									var priv, pub;
							 | 
						||
| 
								 | 
							
									if (this._algo === 'dsa') {
							 | 
						||
| 
								 | 
							
										this._dh.generateKeys();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										parts.push({name: 'p', data: this._p.data});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'q', data: this._key.part.q.data});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'g', data: this._g.data});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'y', data: this._dh.getPublicKey()});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'x', data: this._dh.getPrivateKey()});
							 | 
						||
| 
								 | 
							
										this._key = new PrivateKey({
							 | 
						||
| 
								 | 
							
											type: 'dsa',
							 | 
						||
| 
								 | 
							
											parts: parts
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
										this._isPriv = true;
							 | 
						||
| 
								 | 
							
										return (this._key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (this._algo === 'ecdsa') {
							 | 
						||
| 
								 | 
							
										if (CRYPTO_HAVE_ECDH) {
							 | 
						||
| 
								 | 
							
											this._dh.generateKeys();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											parts.push({name: 'curve',
							 | 
						||
| 
								 | 
							
											    data: Buffer.from(this._curve)});
							 | 
						||
| 
								 | 
							
											parts.push({name: 'Q', data: this._dh.getPublicKey()});
							 | 
						||
| 
								 | 
							
											parts.push({name: 'd', data: this._dh.getPrivateKey()});
							 | 
						||
| 
								 | 
							
											this._key = new PrivateKey({
							 | 
						||
| 
								 | 
							
												type: 'ecdsa',
							 | 
						||
| 
								 | 
							
												curve: this._curve,
							 | 
						||
| 
								 | 
							
												parts: parts
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
											this._isPriv = true;
							 | 
						||
| 
								 | 
							
											return (this._key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											var n = this._ecParams.getN();
							 | 
						||
| 
								 | 
							
											var r = new jsbn(crypto.randomBytes(n.bitLength()));
							 | 
						||
| 
								 | 
							
											var n1 = n.subtract(jsbn.ONE);
							 | 
						||
| 
								 | 
							
											priv = r.mod(n1).add(jsbn.ONE);
							 | 
						||
| 
								 | 
							
											pub = this._ecParams.getG().multiply(priv);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											priv = Buffer.from(priv.toByteArray());
							 | 
						||
| 
								 | 
							
											pub = Buffer.from(this._ecParams.getCurve().
							 | 
						||
| 
								 | 
							
											    encodePointHex(pub), 'hex');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this._priv = new ECPrivate(this._ecParams, priv);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											parts.push({name: 'curve',
							 | 
						||
| 
								 | 
							
											    data: Buffer.from(this._curve)});
							 | 
						||
| 
								 | 
							
											parts.push({name: 'Q', data: pub});
							 | 
						||
| 
								 | 
							
											parts.push({name: 'd', data: priv});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this._key = new PrivateKey({
							 | 
						||
| 
								 | 
							
												type: 'ecdsa',
							 | 
						||
| 
								 | 
							
												curve: this._curve,
							 | 
						||
| 
								 | 
							
												parts: parts
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
											this._isPriv = true;
							 | 
						||
| 
								 | 
							
											return (this._key);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if (this._algo === 'curve25519') {
							 | 
						||
| 
								 | 
							
										var pair = nacl.box.keyPair();
							 | 
						||
| 
								 | 
							
										priv = Buffer.from(pair.secretKey);
							 | 
						||
| 
								 | 
							
										pub = Buffer.from(pair.publicKey);
							 | 
						||
| 
								 | 
							
										priv = Buffer.concat([priv, pub]);
							 | 
						||
| 
								 | 
							
										assert.strictEqual(priv.length, 64);
							 | 
						||
| 
								 | 
							
										assert.strictEqual(pub.length, 32);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										parts.push({name: 'A', data: pub});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'k', data: priv});
							 | 
						||
| 
								 | 
							
										this._key = new PrivateKey({
							 | 
						||
| 
								 | 
							
											type: 'curve25519',
							 | 
						||
| 
								 | 
							
											parts: parts
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
										this._isPriv = true;
							 | 
						||
| 
								 | 
							
										return (this._key);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									throw (new Error('Invalid algorithm: ' + this._algo));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								DiffieHellman.prototype.generateKeys = DiffieHellman.prototype.generateKey;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* These are helpers for using ecc-jsbn (for node 0.10 compatibility). */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function X9ECParameters(name) {
							 | 
						||
| 
								 | 
							
									var params = algs.curves[name];
							 | 
						||
| 
								 | 
							
									assert.object(params);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var p = new jsbn(params.p);
							 | 
						||
| 
								 | 
							
									var a = new jsbn(params.a);
							 | 
						||
| 
								 | 
							
									var b = new jsbn(params.b);
							 | 
						||
| 
								 | 
							
									var n = new jsbn(params.n);
							 | 
						||
| 
								 | 
							
									var h = jsbn.ONE;
							 | 
						||
| 
								 | 
							
									var curve = new ec.ECCurveFp(p, a, b);
							 | 
						||
| 
								 | 
							
									var G = curve.decodePointHex(params.G.toString('hex'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									this.curve = curve;
							 | 
						||
| 
								 | 
							
									this.g = G;
							 | 
						||
| 
								 | 
							
									this.n = n;
							 | 
						||
| 
								 | 
							
									this.h = h;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								X9ECParameters.prototype.getCurve = function () { return (this.curve); };
							 | 
						||
| 
								 | 
							
								X9ECParameters.prototype.getG = function () { return (this.g); };
							 | 
						||
| 
								 | 
							
								X9ECParameters.prototype.getN = function () { return (this.n); };
							 | 
						||
| 
								 | 
							
								X9ECParameters.prototype.getH = function () { return (this.h); };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function ECPublic(params, buffer) {
							 | 
						||
| 
								 | 
							
									this._params = params;
							 | 
						||
| 
								 | 
							
									if (buffer[0] === 0x00)
							 | 
						||
| 
								 | 
							
										buffer = buffer.slice(1);
							 | 
						||
| 
								 | 
							
									this._pub = params.getCurve().decodePointHex(buffer.toString('hex'));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function ECPrivate(params, buffer) {
							 | 
						||
| 
								 | 
							
									this._params = params;
							 | 
						||
| 
								 | 
							
									this._priv = new jsbn(utils.mpNormalize(buffer));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								ECPrivate.prototype.deriveSharedSecret = function (pubKey) {
							 | 
						||
| 
								 | 
							
									assert.ok(pubKey instanceof ECPublic);
							 | 
						||
| 
								 | 
							
									var S = pubKey._pub.multiply(this._priv);
							 | 
						||
| 
								 | 
							
									return (Buffer.from(S.getX().toBigInteger().toByteArray()));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function generateED25519() {
							 | 
						||
| 
								 | 
							
									var pair = nacl.sign.keyPair();
							 | 
						||
| 
								 | 
							
									var priv = Buffer.from(pair.secretKey);
							 | 
						||
| 
								 | 
							
									var pub = Buffer.from(pair.publicKey);
							 | 
						||
| 
								 | 
							
									assert.strictEqual(priv.length, 64);
							 | 
						||
| 
								 | 
							
									assert.strictEqual(pub.length, 32);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var parts = [];
							 | 
						||
| 
								 | 
							
									parts.push({name: 'A', data: pub});
							 | 
						||
| 
								 | 
							
									parts.push({name: 'k', data: priv.slice(0, 32)});
							 | 
						||
| 
								 | 
							
									var key = new PrivateKey({
							 | 
						||
| 
								 | 
							
										type: 'ed25519',
							 | 
						||
| 
								 | 
							
										parts: parts
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									return (key);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Generates a new ECDSA private key on a given curve. */
							 | 
						||
| 
								 | 
							
								function generateECDSA(curve) {
							 | 
						||
| 
								 | 
							
									var parts = [];
							 | 
						||
| 
								 | 
							
									var key;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (CRYPTO_HAVE_ECDH) {
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * Node crypto doesn't expose key generation directly, but the
							 | 
						||
| 
								 | 
							
										 * ECDH instances can generate keys. It turns out this just
							 | 
						||
| 
								 | 
							
										 * calls into the OpenSSL generic key generator, and we can
							 | 
						||
| 
								 | 
							
										 * read its output happily without doing an actual DH. So we
							 | 
						||
| 
								 | 
							
										 * use that here.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										var osCurve = {
							 | 
						||
| 
								 | 
							
											'nistp256': 'prime256v1',
							 | 
						||
| 
								 | 
							
											'nistp384': 'secp384r1',
							 | 
						||
| 
								 | 
							
											'nistp521': 'secp521r1'
							 | 
						||
| 
								 | 
							
										}[curve];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var dh = crypto.createECDH(osCurve);
							 | 
						||
| 
								 | 
							
										dh.generateKeys();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										parts.push({name: 'curve',
							 | 
						||
| 
								 | 
							
										    data: Buffer.from(curve)});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'Q', data: dh.getPublicKey()});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'd', data: dh.getPrivateKey()});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										key = new PrivateKey({
							 | 
						||
| 
								 | 
							
											type: 'ecdsa',
							 | 
						||
| 
								 | 
							
											curve: curve,
							 | 
						||
| 
								 | 
							
											parts: parts
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
										return (key);
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var ecParams = new X9ECParameters(curve);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* This algorithm taken from FIPS PUB 186-4 (section B.4.1) */
							 | 
						||
| 
								 | 
							
										var n = ecParams.getN();
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * The crypto.randomBytes() function can only give us whole
							 | 
						||
| 
								 | 
							
										 * bytes, so taking a nod from X9.62, we round up.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										var cByteLen = Math.ceil((n.bitLength() + 64) / 8);
							 | 
						||
| 
								 | 
							
										var c = new jsbn(crypto.randomBytes(cByteLen));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var n1 = n.subtract(jsbn.ONE);
							 | 
						||
| 
								 | 
							
										var priv = c.mod(n1).add(jsbn.ONE);
							 | 
						||
| 
								 | 
							
										var pub = ecParams.getG().multiply(priv);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										priv = Buffer.from(priv.toByteArray());
							 | 
						||
| 
								 | 
							
										pub = Buffer.from(ecParams.getCurve().
							 | 
						||
| 
								 | 
							
										    encodePointHex(pub), 'hex');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										parts.push({name: 'curve', data: Buffer.from(curve)});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'Q', data: pub});
							 | 
						||
| 
								 | 
							
										parts.push({name: 'd', data: priv});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										key = new PrivateKey({
							 | 
						||
| 
								 | 
							
											type: 'ecdsa',
							 | 
						||
| 
								 | 
							
											curve: curve,
							 | 
						||
| 
								 | 
							
											parts: parts
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
										return (key);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |