trouble-in-terror-town/node_modules/sshpk/lib/dhe.js
Mikolaj 2bbacbea09 did some more work on networking and removed EOS in favor of LRM
did some more work on networking and removed EOS in favor of Light Reflective Mirror
2022-05-31 15:04:31 +02:00

397 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);
}
}