trouble-in-terror-town/node_modules/sshpk/lib/private-key.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

247 lines
6.6 KiB
JavaScript

// Copyright 2017 Joyent, Inc.
module.exports = PrivateKey;
var assert = require('assert-plus');
var Buffer = require('safer-buffer').Buffer;
var algs = require('./algs');
var crypto = require('crypto');
var Fingerprint = require('./fingerprint');
var Signature = require('./signature');
var errs = require('./errors');
var util = require('util');
var utils = require('./utils');
var dhe = require('./dhe');
var generateECDSA = dhe.generateECDSA;
var generateED25519 = dhe.generateED25519;
var edCompat = require('./ed-compat');
var nacl = require('tweetnacl');
var Key = require('./key');
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
var KeyParseError = errs.KeyParseError;
var KeyEncryptedError = errs.KeyEncryptedError;
var formats = {};
formats['auto'] = require('./formats/auto');
formats['pem'] = require('./formats/pem');
formats['pkcs1'] = require('./formats/pkcs1');
formats['pkcs8'] = require('./formats/pkcs8');
formats['rfc4253'] = require('./formats/rfc4253');
formats['ssh-private'] = require('./formats/ssh-private');
formats['openssh'] = formats['ssh-private'];
formats['ssh'] = formats['ssh-private'];
formats['dnssec'] = require('./formats/dnssec');
formats['putty'] = require('./formats/putty');
function PrivateKey(opts) {
assert.object(opts, 'options');
Key.call(this, opts);
this._pubCache = undefined;
}
util.inherits(PrivateKey, Key);
PrivateKey.formats = formats;
PrivateKey.prototype.toBuffer = function (format, options) {
if (format === undefined)
format = 'pkcs1';
assert.string(format, 'format');
assert.object(formats[format], 'formats[format]');
assert.optionalObject(options, 'options');
return (formats[format].write(this, options));
};
PrivateKey.prototype.hash = function (algo, type) {
return (this.toPublic().hash(algo, type));
};
PrivateKey.prototype.fingerprint = function (algo, type) {
return (this.toPublic().fingerprint(algo, type));
};
PrivateKey.prototype.toPublic = function () {
if (this._pubCache)
return (this._pubCache);
var algInfo = algs.info[this.type];
var pubParts = [];
for (var i = 0; i < algInfo.parts.length; ++i) {
var p = algInfo.parts[i];
pubParts.push(this.part[p]);
}
this._pubCache = new Key({
type: this.type,
source: this,
parts: pubParts
});
if (this.comment)
this._pubCache.comment = this.comment;
return (this._pubCache);
};
PrivateKey.prototype.derive = function (newType) {
assert.string(newType, 'type');
var priv, pub, pair;
if (this.type === 'ed25519' && newType === 'curve25519') {
priv = this.part.k.data;
if (priv[0] === 0x00)
priv = priv.slice(1);
pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv));
pub = Buffer.from(pair.publicKey);
return (new PrivateKey({
type: 'curve25519',
parts: [
{ name: 'A', data: utils.mpNormalize(pub) },
{ name: 'k', data: utils.mpNormalize(priv) }
]
}));
} else if (this.type === 'curve25519' && newType === 'ed25519') {
priv = this.part.k.data;
if (priv[0] === 0x00)
priv = priv.slice(1);
pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv));
pub = Buffer.from(pair.publicKey);
return (new PrivateKey({
type: 'ed25519',
parts: [
{ name: 'A', data: utils.mpNormalize(pub) },
{ name: 'k', data: utils.mpNormalize(priv) }
]
}));
}
throw (new Error('Key derivation not supported from ' + this.type +
' to ' + newType));
};
PrivateKey.prototype.createVerify = function (hashAlgo) {
return (this.toPublic().createVerify(hashAlgo));
};
PrivateKey.prototype.createSign = function (hashAlgo) {
if (hashAlgo === undefined)
hashAlgo = this.defaultHashAlgorithm();
assert.string(hashAlgo, 'hash algorithm');
/* ED25519 is not supported by OpenSSL, use a javascript impl. */
if (this.type === 'ed25519' && edCompat !== undefined)
return (new edCompat.Signer(this, hashAlgo));
if (this.type === 'curve25519')
throw (new Error('Curve25519 keys are not suitable for ' +
'signing or verification'));
var v, nm, err;
try {
nm = hashAlgo.toUpperCase();
v = crypto.createSign(nm);
} catch (e) {
err = e;
}
if (v === undefined || (err instanceof Error &&
err.message.match(/Unknown message digest/))) {
nm = 'RSA-';
nm += hashAlgo.toUpperCase();
v = crypto.createSign(nm);
}
assert.ok(v, 'failed to create verifier');
var oldSign = v.sign.bind(v);
var key = this.toBuffer('pkcs1');
var type = this.type;
var curve = this.curve;
v.sign = function () {
var sig = oldSign(key);
if (typeof (sig) === 'string')
sig = Buffer.from(sig, 'binary');
sig = Signature.parse(sig, type, 'asn1');
sig.hashAlgorithm = hashAlgo;
sig.curve = curve;
return (sig);
};
return (v);
};
PrivateKey.parse = function (data, format, options) {
if (typeof (data) !== 'string')
assert.buffer(data, 'data');
if (format === undefined)
format = 'auto';
assert.string(format, 'format');
if (typeof (options) === 'string')
options = { filename: options };
assert.optionalObject(options, 'options');
if (options === undefined)
options = {};
assert.optionalString(options.filename, 'options.filename');
if (options.filename === undefined)
options.filename = '(unnamed)';
assert.object(formats[format], 'formats[format]');
try {
var k = formats[format].read(data, options);
assert.ok(k instanceof PrivateKey, 'key is not a private key');
if (!k.comment)
k.comment = options.filename;
return (k);
} catch (e) {
if (e.name === 'KeyEncryptedError')
throw (e);
throw (new KeyParseError(options.filename, format, e));
}
};
PrivateKey.isPrivateKey = function (obj, ver) {
return (utils.isCompatible(obj, PrivateKey, ver));
};
PrivateKey.generate = function (type, options) {
if (options === undefined)
options = {};
assert.object(options, 'options');
switch (type) {
case 'ecdsa':
if (options.curve === undefined)
options.curve = 'nistp256';
assert.string(options.curve, 'options.curve');
return (generateECDSA(options.curve));
case 'ed25519':
return (generateED25519());
default:
throw (new Error('Key generation not supported with key ' +
'type "' + type + '"'));
}
};
/*
* API versions for PrivateKey:
* [1,0] -- initial ver
* [1,1] -- added auto, pkcs[18], openssh/ssh-private formats
* [1,2] -- added defaultHashAlgorithm
* [1,3] -- added derive, ed, createDH
* [1,4] -- first tagged version
* [1,5] -- changed ed25519 part names and format
* [1,6] -- type arguments for hash() and fingerprint()
*/
PrivateKey.prototype._sshpkApiVersion = [1, 6];
PrivateKey._oldVersionDetect = function (obj) {
assert.func(obj.toPublic);
assert.func(obj.createSign);
if (obj.derive)
return ([1, 3]);
if (obj.defaultHashAlgorithm)
return ([1, 2]);
if (obj.formats['auto'])
return ([1, 1]);
return ([1, 0]);
};