Socket
Socket
Sign inDemoInstall

sshpk

Package Overview
Dependencies
4
Maintainers
1
Versions
50
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.2.1 to 1.3.0

lib/formats/pkcs1.js

14

lib/algs.js

@@ -18,2 +18,14 @@ // Copyright 2015 Joyent, Inc.

var algPrivInfo = {
'dsa': {
parts: ['p', 'q', 'g', 'y', 'x']
},
'rsa': {
parts: ['n', 'e', 'd', 'iqmp', 'p', 'q']
},
'ecdsa': {
parts: ['curve', 'Q', 'd']
}
};
var hashAlgs = {

@@ -91,2 +103,3 @@ 'md5': true,

size: 521,
pkcs8oid: '1.3.132.0.35',
p: new Buffer((

@@ -128,4 +141,5 @@ '01ffffff ffffffff ffffffff ffffffff' +

info: algInfo,
privInfo: algPrivInfo,
hashAlgs: hashAlgs,
curves: curves
};

6

lib/fingerprint.js
// Copyright 2015 Joyent, Inc.
module.exports = Fingerprint;
var assert = require('assert-plus');

@@ -7,3 +9,3 @@ var algs = require('./algs');

var errs = require('./errors');
var Key;
var Key = require('./key');

@@ -122,3 +124,1 @@ var FingerprintFormatError = errs.FingerprintFormatError;

}
module.exports = Fingerprint;
// Copyright 2015 Joyent, Inc.
module.exports = {
read: read,
write: write
};
var assert = require('assert-plus');

@@ -7,4 +12,8 @@ var asn1 = require('asn1');

var utils = require('../utils');
var Key;
var Key = require('../key');
var PrivateKey = require('../private-key');
var pkcs1 = require('./pkcs1');
var pkcs8 = require('./pkcs8');
/*

@@ -14,3 +23,3 @@ * For reading we support both PKCS#1 and PKCS#8. If we find a private key,

*/
function read(buf) {
function read(buf, forceType) {
var input = buf;

@@ -24,13 +33,9 @@ if (typeof (buf) !== 'string') {

/* Defer until runtime due to circular deps */
if (Key === undefined)
Key = require('../key');
var m = lines[0].match(/*JSSTYLED*/
/BEGIN ([A-Z]+ )?(PUBLIC|PRIVATE) KEY/);
assert.ok(m);
assert.ok(m, 'invalid PEM header');
var m2 = lines[lines.length - 2].match(/*JSSTYLED*/
/END ([A-Z]+ )?(PUBLIC|PRIVATE) KEY/);
assert.ok(m2);
assert.ok(m2, 'invalid PEM footer');

@@ -44,3 +49,3 @@ /* Begin and end banners must match key type */

/* They also must match algorithms, if given */
assert.equal(m[1], m2[1]);
assert.equal(m[1], m2[1], 'PEM header and footer mismatch');
alg = m[1].trim();

@@ -81,342 +86,53 @@ }

/* PKCS#1 type keys name an algorithm in the banner explicitly */
if (alg)
return (readPkcs1(alg, type, der));
else
return (readPkcs8(alg, type, der));
}
/* Helper to read in a single mpint */
function readMPInt(der, nm) {
assert.strictEqual(der.peek(), asn1.Ber.Integer,
nm + ' is not an Integer');
return (der.readString(asn1.Ber.Integer, true));
}
function readPkcs1(alg, type, der) {
switch (alg) {
case 'RSA':
if (type === 'public')
return (readPkcs1RSAPublic(der));
else if (type === 'private')
return (readPkcs1RSAPrivate(der));
throw (new Error('Unknown key type: ' + type));
case 'DSA':
if (type === 'private')
return (readPkcs1DSAPrivate(der));
throw (new Error('DSA public keys cannot be PKCS#1'));
case 'EC':
if (type === 'private')
return (readPkcs1ECDSAPrivate(der));
throw (new Error('ECDSA public keys cannot be PKCS#1'));
default:
throw (new Error('Unknown key algo: ' + alg));
if (alg) {
if (forceType)
assert.strictEqual(forceType, 'pkcs1');
return (pkcs1.readPkcs1(alg, type, der));
} else {
if (forceType)
assert.strictEqual(forceType, 'pkcs8');
return (pkcs8.readPkcs8(alg, type, der));
}
}
function readPkcs1RSAPublic(der) {
// modulus and exponent
var n = readMPInt(der, 'modulus');
var e = readMPInt(der, 'exponent');
function write(key, type) {
assert.object(key);
// now, make the key
var key = {
type: 'rsa',
source: der.originalInput,
parts: [
{ name: 'e', data: e },
{ name: 'n', data: n }
]
};
var alg = {'ecdsa': 'EC', 'rsa': 'RSA', 'dsa': 'DSA'}[key.type];
var header;
return (new Key(key));
}
var der = new asn1.BerWriter();
function readPkcs1RSAPrivate(der) {
var version = readMPInt(der, 'version');
assert.strictEqual(version.readUInt8(0), 0);
// modulus then public exponent
var n = readMPInt(der, 'modulus');
var e = readMPInt(der, 'public exponent');
// now, make the key
var key = {
type: 'rsa',
source: der.originalInput,
parts: [
{ name: 'e', data: e },
{ name: 'n', data: n }
]
};
return (new Key(key));
}
function readPkcs1DSAPrivate(der) {
var version = readMPInt(der, 'version');
assert.strictEqual(version.readUInt8(0), 0);
var p = readMPInt(der, 'p');
var q = readMPInt(der, 'q');
var g = readMPInt(der, 'g');
var y = readMPInt(der, 'y');
// now, make the key
var key = {
type: 'dsa',
source: der.originalInput,
parts: [
{ name: 'p', data: p },
{ name: 'q', data: q },
{ name: 'g', data: g },
{ name: 'y', data: y }
]
};
return (new Key(key));
}
function readPkcs1ECDSAPrivate(der) {
var version = readMPInt(der, 'version');
assert.strictEqual(version.readUInt8(0), 1);
// private key
der.readString(asn1.Ber.OctetString, true);
der.readSequence(0xa0);
var curveOid = der.readOID();
var curve;
switch (curveOid) {
case '1.2.840.10045.3.1.7':
curve = 'nistp256';
break;
case '1.3.132.0.34':
curve = 'nistp384';
break;
case '1.3.132.0.35':
curve = 'nistp521';
break;
default:
throw (new Error('Unknown ECDSA curve oid: ' + curveOid));
}
der.readSequence(0xa1);
var Q = der.readString(asn1.Ber.BitString, true);
if (Q[0] === 0x0)
Q = Q.slice(1);
var key = {
type: 'ecdsa',
source: der.originalInput,
parts: [
{ name: 'curve', data: new Buffer(curve) },
{ name: 'Q', data: Q }
]
};
return (new Key(key));
}
function readPkcs8(alg, type, der) {
if (type !== 'public')
throw (new Error('PKCS#8 only supports public keys'));
der.readSequence();
var oid = der.readOID();
switch (oid) {
case '1.2.840.113549.1.1.1':
return (readPkcs8RSA(der));
case '1.2.840.10040.4.1':
return (readPkcs8DSA(der));
case '1.2.840.10045.2.1':
return (readPkcs8ECDSA(der));
default:
throw (new Error('Unknown key type OID ' + oid));
}
}
function readPkcs8RSA(der) {
// Null -- XXX this probably isn't good practice
der.readByte();
der.readByte();
// bit string sequence
der.readSequence(0x03);
der.readByte();
der.readSequence();
// modulus
var n = readMPInt(der, 'modulus');
var e = readMPInt(der, 'exponent');
// now, make the key
var key = {
type: 'rsa',
source: der.originalInput,
parts: [
{ name: 'e', data: e },
{ name: 'n', data: n }
]
};
return (new Key(key));
}
function readPkcs8DSA(der) {
der.readSequence();
var p = readMPInt(der, 'p');
var q = readMPInt(der, 'q');
var g = readMPInt(der, 'g');
// bit string sequence
der.readSequence(0x03);
der.readByte();
var y = readMPInt(der, 'y');
// now, make the key
var key = {
type: 'dsa',
source: der.originalInput,
parts: [
{ name: 'p', data: p },
{ name: 'q', data: q },
{ name: 'g', data: g },
{ name: 'y', data: y }
]
};
return (new Key(key));
}
/* Count leading zero bits on a buffer */
function countZeros(buf) {
var o = 0, obit = 8;
while (o < buf.length) {
var mask = (1 << obit);
if ((buf[o] & mask) === mask)
break;
obit--;
if (obit < 0) {
o++;
obit = 8;
if (key instanceof PrivateKey) {
if (type && type === 'pkcs8') {
header = 'PRIVATE KEY';
pkcs8.writePkcs8(der, key);
} else {
if (type)
assert.strictEqual(type, 'pkcs1');
header = alg + ' PRIVATE KEY';
pkcs1.writePkcs1(der, key);
}
}
return (o*8 + (8 - obit) - 1);
}
function readPkcs8ECDSA(der) {
// ECParameters sequence
der.readSequence();
var version = der.readString(asn1.Ber.Integer, true);
assert.strictEqual(version[0], 1, 'ECDSA key not version 1');
var curve = {};
// FieldID sequence
der.readSequence();
var fieldTypeOid = der.readOID();
assert.strictEqual(fieldTypeOid, '1.2.840.10045.1.1',
'ECDSA key is not from a prime-field');
var p = curve.p = der.readString(asn1.Ber.Integer, true);
/*
* p always starts with a 1 bit, so count the zeros to get its
* real size.
*/
curve.size = p.length * 8 - countZeros(p);
// Curve sequence
der.readSequence();
curve.a = der.readString(asn1.Ber.OctetString, true);
curve.b = der.readString(asn1.Ber.OctetString, true);
if (der.peek() === asn1.Ber.BitString)
curve.s = der.readString(asn1.Ber.BitString, true);
// Combined Gx and Gy
curve.G = der.readString(asn1.Ber.OctetString, true);
assert.strictEqual(curve.G[0], 0x4, 'uncompressed G is required');
curve.n = der.readString(asn1.Ber.Integer, true);
curve.h = der.readString(asn1.Ber.Integer, true);
assert.strictEqual(curve.h[0], 0x1, 'a cofactor=1 curve is required');
var curveName;
var curveNames = Object.keys(algs.curves);
for (var j = 0; j < curveNames.length; ++j) {
var c = curveNames[j];
var cd = algs.curves[c];
var ks = Object.keys(cd);
var equal = true;
for (var i = 0; i < ks.length; ++i) {
var k = ks[i];
if (typeof (cd[k]) === 'object') {
if (!cd[k].equals(curve[k])) {
equal = false;
break;
}
} else {
if (cd[k] !== curve[k]) {
equal = false;
break;
}
}
} else if (key instanceof Key) {
if (type && type === 'pkcs1') {
header = alg + ' PUBLIC KEY';
pkcs1.writePkcs1(der, key);
} else {
if (type)
assert.strictEqual(type, 'pkcs8');
header = 'PUBLIC KEY';
pkcs8.writePkcs8(der, key);
}
if (equal) {
curveName = c;
break;
}
}
assert.string(curveName, 'a known elliptic curve');
var Q = der.readString(asn1.Ber.BitString, true);
if (Q[0] === 0x0)
Q = Q.slice(1);
var key = {
type: 'ecdsa',
source: der.originalInput,
parts: [
{ name: 'curve', data: new Buffer(curveName) },
{ name: 'Q', data: Q }
]
};
return (new Key(key));
}
/* For writing, we only support PKCS#8 */
function write(key) {
assert.object(key);
var der = new asn1.BerWriter();
der.startSequence();
der.startSequence();
switch (key.type) {
case 'rsa':
der.writeOID('1.2.840.113549.1.1.1');
der.writeNull();
der.endSequence();
writePkcs8RSA(key, der);
break;
case 'dsa':
der.writeOID('1.2.840.10040.4.1');
writePkcs8DSA(key, der);
break;
case 'ecdsa':
der.writeOID('1.2.840.10045.2.1');
writePkcs8ECDSA(key, der);
break;
default:
throw (new Error('Unsupported key type: ' + key.type));
} else {
throw (new Error('key is not a Key or PrivateKey'));
}
der.endSequence();
var tmp = der.buffer.toString('base64');
var len = tmp.length + (tmp.length / 64) + 28*2 + 10;
var len = tmp.length + (tmp.length / 64) +
18 + 16 + header.length*2 + 10;
var buf = new Buffer(len);
var o = 0;
o += buf.write('-----BEGIN PUBLIC KEY-----\n', o);
o += buf.write('-----BEGIN ' + header + '-----\n', o);
for (var i = 0; i < tmp.length; ) {

@@ -430,89 +146,5 @@ var limit = i + 64;

}
o += buf.write('-----END PUBLIC KEY-----\n', o);
o += buf.write('-----END ' + header + '-----\n', o);
return (buf.slice(0, o));
}
function writePkcs8RSA(key, der) {
der.startSequence(asn1.Ber.BitString);
der.writeByte(0x00);
der.startSequence();
der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
der.endSequence();
der.endSequence();
}
function writePkcs8DSA(key, der) {
der.startSequence();
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
der.endSequence();
der.endSequence();
der.startSequence(asn1.Ber.BitString);
der.writeByte(0x00);
der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
der.endSequence();
}
function writePkcs8ECDSA(key, der) {
var curve = algs.curves[key.curve];
if (curve.pkcs8oid) {
/* This one has a name in pkcs#8, so just write the oid */
der.writeOID(curve.pkcs8oid);
} else {
// ECParameters sequence
der.startSequence();
var version = new Buffer(1);
version.writeUInt8(1, 0);
der.writeBuffer(version, asn1.Ber.Integer);
// FieldID sequence
der.startSequence();
der.writeOID('1.2.840.10045.1.1'); // prime-field
der.writeBuffer(curve.p, asn1.Ber.Integer);
der.endSequence();
// Curve sequence
der.startSequence();
var a = curve.p;
if (a[0] === 0x0)
a = a.slice(1);
der.writeBuffer(a, asn1.Ber.OctetString);
der.writeBuffer(curve.b, asn1.Ber.OctetString);
der.writeBuffer(curve.s, asn1.Ber.BitString);
der.endSequence();
der.writeBuffer(curve.G, asn1.Ber.OctetString);
der.writeBuffer(curve.n, asn1.Ber.Integer);
var h = curve.h;
if (!h) {
h = new Buffer(1);
h[0] = 1;
}
der.writeBuffer(h, asn1.Ber.Integer);
// ECParameters
der.endSequence();
}
der.endSequence();
var Q = key.part.Q.data;
var pre = new Buffer(1);
pre[0] = 0x0;
if (Q[0] === 0x04)
Q = Buffer.concat([pre, Q]);
der.writeBuffer(Q, asn1.Ber.BitString);
}
module.exports = {
read: read,
write: write
};
// Copyright 2015 Joyent, Inc.
module.exports = {
read: read.bind(undefined, false, undefined),
write: write,
/* semi-private api, used by sshpk-agent */
readPartial: read.bind(undefined, true),
/* shared with ssh format */
keyTypeToAlg: keyTypeToAlg,
algToKeyType: algToKeyType
};
var assert = require('assert-plus');
var algInfos = require('../algs').info;
var Key;
var algs = require('../algs');
var Key = require('../key');
var PrivateKey = require('../private-key');

@@ -31,3 +43,11 @@ function algToKeyType(alg) {

function read(buf) {
function readLV(buf, offset, parts) {
var len = buf.readUInt32BE(offset);
offset += 4;
parts.push({data: buf.slice(offset, offset + len)});
offset += len;
return (offset);
}
function read(partial, type, buf) {
if (typeof (buf) === 'string')

@@ -37,20 +57,12 @@ buf = new Buffer(buf);

/* Defer until runtime due to circular deps */
if (Key === undefined)
Key = require('../key');
var key = {};
key._rfc4253Cache = buf;
var parts = key.parts = [];
var offset = 0;
while (offset < buf.length) {
var len = buf.readUInt32BE(offset);
offset += 4;
parts.push({data: buf.slice(offset, offset + len)});
offset += len;
}
offset = readLV(buf, offset, parts);
assert.ok(parts.length > 1);
assert.ok(parts[0].data.length > 0);
assert.ok(parts.length >= 1,
'key must have at least one part');
assert.ok(parts[0].data.length > 0,
'first key part must not be empty');

@@ -63,4 +75,24 @@ var alg = parts[0].data.toString();

var algInfo = algInfos[key.type];
var partCount = algs.info[key.type].parts.length;
if (type && type === 'private')
partCount = algs.privInfo[key.type].parts.length;
while (offset < buf.length && parts.length < partCount)
offset = readLV(buf, offset, parts);
while (!partial && offset < buf.length)
offset = readLV(buf, offset, parts);
assert.ok(parts.length >= 1,
'key must have at least one part');
key._rfc4253Cache = buf.slice(0, offset);
var Constructor = Key;
var algInfo = algs.info[key.type];
if (type === 'private' || algInfo.parts.length !== parts.length) {
algInfo = algs.privInfo[key.type];
Constructor = PrivateKey;
}
assert.strictEqual(algInfo.parts.length, parts.length);
if (key.type === 'ecdsa') {

@@ -72,7 +104,6 @@ var res = /^ecdsa-sha2-(.+)$/.exec(alg);

assert.strictEqual(algInfo.parts.length, parts.length);
for (var i = 0; i < algInfo.parts.length; ++i)
parts[i].name = algInfo.parts[i];
return (new Key(key));
return (new Constructor(key));
}

@@ -86,5 +117,11 @@

var algInfo = algs.info[key.type];
if (key instanceof PrivateKey)
algInfo = algs.privInfo[key.type];
var parts = algInfo.parts;
var size = 0;
for (i = 0; i < key.parts.length; ++i)
size += 4 + key.parts[i].data.length;
for (i = 0; i < parts.length; ++i)
/* +1 in case it's a bignum that needs a leading 0 */
size += 4 + 1 + key.part[parts[i]].data.length;
size += alg.length + 4;

@@ -99,6 +136,14 @@

for (i = 0; i < key.parts.length; ++i) {
buf.writeUInt32BE(key.parts[i].data.length, o);
o += 4;
o += key.parts[i].data.copy(buf, o);
for (i = 0; i < parts.length; ++i) {
var data = key.part[parts[i]].data;
if (parts[i] !== 'curve' && (data[0] & 0x80) == 0x80) {
buf.writeUInt32BE(data.length + 1, o);
o += 4;
buf[o++] = 0;
o += data.copy(buf, o);
} else {
buf.writeUInt32BE(data.length, o);
o += 4;
o += data.copy(buf, o);
}
}

@@ -109,10 +154,1 @@ buf = buf.slice(0, o);

}
module.exports = {
read: read,
write: write,
/* shared with ssh format */
keyTypeToAlg: keyTypeToAlg,
algToKeyType: algToKeyType
};

@@ -6,2 +6,3 @@ // Copyright 2015 Joyent, Inc.

var Signature = require('./signature');
var PrivateKey = require('./private-key');
var errs = require('./errors');

@@ -17,2 +18,4 @@

parseSignature: Signature.parse,
PrivateKey: PrivateKey,
parsePrivateKey: PrivateKey.parse,

@@ -19,0 +22,0 @@ /* errors */

// Copyright 2015 Joyent, Inc.
module.exports = Key;
var assert = require('assert-plus');

@@ -9,2 +11,3 @@ var algs = require('./algs');

var errs = require('./errors');
var PrivateKey = require('./private-key');

@@ -16,2 +19,4 @@ var InvalidAlgorithmError = errs.InvalidAlgorithmError;

formats['pem'] = require('./formats/pem');
formats['pkcs1'] = require('./formats/pkcs1');
formats['pkcs8'] = require('./formats/pkcs8');
formats['rfc4253'] = require('./formats/rfc4253');

@@ -36,34 +41,44 @@ formats['ssh'] = require('./formats/ssh');

Object.defineProperties(this, {
type: { enumerable: true, value: opts.type },
parts: { value: opts.parts },
part: { value: partLookup },
comment: { enumerable: true, writable: true,
value: opts.comment },
source: { value: opts.source },
this.type = opts.type;
this.parts = opts.parts;
this.part = partLookup;
this.comment = undefined;
this.source = opts.source;
/* To make things faster when all you want is the fingerprint */
_rfc4253Cache: { writable: true,
value: opts._rfc4253Cache },
_hashCache: { writable: true, value: {} }
});
/* for speeding up hashing/fingerprint operations */
this._rfc4253Cache = opts._rfc4253Cache;
this._hashCache = {};
var sz;
this.curve = undefined;
if (this.type === 'ecdsa') {
var curve = this.part.curve.data.toString();
Object.defineProperties(this, {
curve: { enumerable: true, value: curve },
size: { enumerable: true,
value: algs.curves[curve].size }
});
this.curve = curve;
sz = algs.curves[curve].size;
} else {
var szPart = this.part[algInfo.sizePart];
var sz = szPart.data.length;
sz = szPart.data.length;
if (szPart.data[0] === 0x0)
sz--;
Object.defineProperties(this, {
size: { enumerable: true, value: sz * 8 }
});
sz = sz * 8;
}
this.size = sz;
}
Key.formats = formats;
Object.defineProperty(Key.prototype, 'type',
{enumerable: true, writable: true});
Object.defineProperty(Key.prototype, 'parts', {writable: true});
Object.defineProperty(Key.prototype, 'part', {writable: true});
Object.defineProperty(Key.prototype, 'comment',
{enumerable: true, writable: true});
Object.defineProperty(Key.prototype, 'source', {writable: true});
Object.defineProperty(Key.prototype, '_rfc4253Cache', {writable: true});
Object.defineProperty(Key.prototype, '_hashCache', {writable: true});
Object.defineProperty(Key.prototype, 'size',
{enumerable: true, writable: true});
Object.defineProperty(Key.prototype, 'curve',
{enumerable: true, writable: true});
Key.prototype.toBuffer = function (format) {

@@ -149,3 +164,3 @@ if (format === undefined)

var oldVerify = v.verify.bind(v);
var key = this.toBuffer('pem');
var key = this.toBuffer('pkcs8');
v.verify = function (signature, fmt) {

@@ -173,2 +188,6 @@ if (typeof (signature) === 'object' &&

var k = formats[format].read(data);
if (k instanceof PrivateKey)
k = k.toPublic();
if (!k.comment)
k.comment = name;
return (k);

@@ -179,3 +198,1 @@ } catch (e) {

};
module.exports = Key;
// Copyright 2015 Joyent, Inc.
module.exports = Signature;
var assert = require('assert-plus');

@@ -220,3 +222,1 @@ var algs = require('./algs');

}
module.exports = Signature;
// Copyright 2015 Joyent, Inc.
module.exports = {
bufferSplit: bufferSplit,
addRSAMissing: addRSAMissing,
calculateDSAPublic: calculateDSAPublic
};
var assert = require('assert-plus');
var PrivateKey = require('./private-key');

@@ -33,4 +40,78 @@ function bufferSplit(buf, chr) {

module.exports = {
bufferSplit: bufferSplit
};
function calculateDSAPublic(g, p, x) {
assert.buffer(g);
assert.buffer(p);
assert.buffer(x);
try {
var bigInt = require('big-integer');
} catch (e) {
throw (new Error('To load a PKCS#8 format DSA private key, ' +
'the node big-integer library is required.'));
}
g = bigInt(g.toString('hex'), 16);
p = bigInt(p.toString('hex'), 16);
x = bigInt(x.toString('hex'), 16);
var y = modexp(g, x, p);
y = new Buffer(y.toString(16), 'hex');
if ((y[0] & 0x80) == 0x80) {
var b = new Buffer(y.length + 1);
b[0] = 0x00;
y.copy(b, 1);
y = b;
}
return (y);
/* Bruce Schneier's modular exponentiation algorithm */
function modexp(base, exp, mod) {
var res = bigInt(1);
base = base.mod(mod);
while (exp.gt(0)) {
if (exp.isOdd())
res = res.times(base).mod(mod);
exp = exp.shiftRight(1);
base = base.square().mod(mod);
}
return (res);
}
}
function addRSAMissing(key) {
assert.object(key);
assert.ok(key instanceof PrivateKey);
try {
var bigInt = require('big-integer');
} catch (e) {
throw (new Error('To write a PEM private key from ' +
'this source, the node big-integer lib is required.'));
}
var d = bigInt(key.part.d.data.toString('hex'), 16);
var b;
if (!key.part.dmodp) {
var p = bigInt(key.part.p.data.toString('hex'), 16);
var dmodp = d.mod(p.minus(1));
dmodp = new Buffer(dmodp.toString(16), 'hex');
if ((dmodp[0] & 0x80) == 0x80) {
b = new Buffer(dmodp.length + 1);
b[0] = 0x00;
dmodp.copy(b, 1);
dmodp = b;
}
key.part.dmodp = {name: 'dmodp', data: dmodp};
key.parts.push(key.part.dmodp);
}
if (!key.part.dmodq) {
var q = bigInt(key.part.q.data.toString('hex'), 16);
var dmodq = d.mod(q.minus(1));
dmodq = new Buffer(dmodq.toString(16), 'hex');
if ((dmodq[0] & 0x80) == 0x80) {
b = new Buffer(dmodq.length + 1);
b[0] = 0x00;
dmodq.copy(b, 1);
dmodq = b;
}
key.part.dmodq = {name: 'dmodq', data: dmodq};
key.parts.push(key.part.dmodq);
}
}
{
"name": "sshpk",
"version": "1.2.1",
"version": "1.3.0",
"description": "A library for finding and using SSH public keys",

@@ -37,5 +37,8 @@ "main": "lib/index.js",

"dependencies": {
"asn1": "0.2.2",
"assert-plus": "0.1.5"
"asn1": ">=0.2.3 <0.3.0",
"assert-plus": ">=0.1.5 <0.2.0"
},
"optionalDependencies": {
"big-integer": ">=1.6.0 <2.0.0"
},
"devDependencies": {

@@ -42,0 +45,0 @@ "tape": ">=3.5.0 <4.0.0",

sshpk
=========
Parse, convert, fingerprint and use SSH public keys in pure node -- no
`ssh-keygen` or other external dependencies.
Parse, convert, fingerprint and use SSH keys (both public and private) in pure
node -- no `ssh-keygen` or other external dependencies.
Supports RSA, DSA and ECDSA (nistp-\*) key types. Can also parse SSH private
keys in PEM format and output their public half.
Supports RSA, DSA and ECDSA (nistp-\*) key types, in PEM (PKCS#1, PKCS#8) and
OpenSSH formats.

@@ -15,3 +15,3 @@ This library has been extracted from

[`node-ssh-fingerprint`](https://github.com/bahamas10/node-ssh-fingerprint)
(work by Dave Eddy), with some additions (including ECDSA support) by
(work by Dave Eddy), with additions (including ECDSA support) by
[Alex Wilson](https://github.com/arekinath).

@@ -61,23 +61,36 @@

```js
/* Read in a PEM public key (PKCS#8) */
/* Read in a PEM public key */
var keyPem = fs.readFileSync('id_rsa.pem');
var key = sshpk.parseKey(keyPem, 'pem');
/* Convert to PEM PKCS#8 public key format */
var pemBuf = key.toBuffer('pkcs8');
/* Read in an OpenSSH/PEM *private* key, will load just the public half */
/* Convert to SSH public key format (and return as a string) */
var sshKey = key.toString('ssh');
```
Signing and verifying:
```js
/* Read in an OpenSSH/PEM *private* key */
var keyPriv = fs.readFileSync('id_ecdsa');
var key = sshpk.parseKey(keyPriv, 'pem');
var key = sshpk.parsePrivateKey(keyPriv, 'pem');
var data = 'some data';
/* Convert to PEM PKCS#8 public key format */
var pemBuf = key.toBuffer('pem');
/* Sign some data with the key */
var s = key.createSign('sha1');
s.update(data);
var signature = s.sign();
/* Convert to SSH public key format (and return as a string) */
var sshKey = key.toString('ssh');
/* Now load the public key (could also use just key.toPublic()) */
var keyPub = fs.readFileSync('id_ecdsa.pub');
key = sshpk.parseKey(keyPub, 'ssh');
/* Make a crypto.Verifier with this key */
var v = key.createVerify('sha1');
v.update('some data here');
v.update(data);
var valid = v.verify(signature);
/* => true! */
```

@@ -101,2 +114,4 @@

## Public keys
### `parseKey(data[, format = 'ssh'[, name]])`

@@ -111,3 +126,4 @@

both PKCS#1 and PKCS#8), `rfc4253` (raw OpenSSH wire format, as
returned by `ssh-agent`, for example), `ssh` (OpenSSH format)
returned by `ssh-agent`, for example), `ssh` (OpenSSH format),
`pkcs1`, `pkcs8`
- `name` -- Optional name for the key being parsed (eg. the filename that

@@ -177,2 +193,79 @@ was opened). Used to generate Error messages

## Private keys
### `parsePrivateKey(data[, format = 'pem'[, name]])`
Parses a private key from a given data format and returns a new
`PrivateKey` object.
Parameters
- `data` -- Either a Buffer or String, containing the key
- `format` -- String name of format to use, valid options are `pem` (supports
both PKCS#1 and PKCS#8), `rfc4253` (raw OpenSSH wire format, as
returned by `ssh-agent`, for example), `pkcs1`, `pkcs8`
- `name` -- Optional name for the key being parsed (eg. the filename that
was opened). Used to generate Error messages
### `PrivateKey#type`
String, the type of key. Valid options are `rsa`, `dsa`, `ecdsa`.
### `PrivateKey#size`
Integer, "size" of the key in bits. For RSA/DSA this is the size of the modulus;
for ECDSA this is the bit size of the curve in use.
### `PrivateKey#curve`
Only present if `this.type === 'ecdsa'`, string containing the name of the
named curve used with this key. Possible values include `nistp256`, `nistp384`
and `nistp521`.
### `PrivateKey#toBuffer([format = 'pkcs1'])`
Convert the key into a given data format and return the serialized key as
a Buffer.
Parameters
- `format` -- String name of format to use, valid options are `pkcs8`, `pkcs1`,
`rfc4253`, `pem` (same as `pkcs1`)
### `PrivateKey#toString([format = 'pkcs1'])`
Same as `this.toBuffer(format).toString()`.
### `PrivateKey#toPublic()`
Extract just the public part of this private key, and return it as a `Key`
object.
### `PrivateKey#fingerprint([algorithm = 'sha256'])`
Same as `this.toPublic().fingerprint()`.
### `PrivateKey#createVerify([hashAlgorithm])`
Same as `this.toPublic().createVerify()`.
### `PrivateKey#createSign([hashAlgorithm])`
Creates a `crypto.Sign` specialized to use this PrivateKey (and the correct
key algorithm to match it). The returned Signer has the same API as a regular
one, except that the `sign()` function takes no arguments, and returns a
`Signature` object.
Parameters
- `hashAlgorithm` -- optional String name of hash algorithm to use, any
supported by OpenSSL are valid, usually including
`sha1`, `sha256`.
`v.sign()` Parameters
- none
## Fingerprints
### `parseFingerprint(fingerprint[, algorithms])`

@@ -209,11 +302,13 @@

## Signatures
### `parseSignature(signature, algorithm, format)`
Parses a signature in a given format, createing a `Signature` object. Useful
for converting between the SSH and ASN.1 (PKCS/OpenSSL) signature formats for
DSA and ECDSA.
Parses a signature in a given format, creating a `Signature` object. Useful
for converting between the SSH and ASN.1 (PKCS/OpenSSL) signature formats, and
also returned as output from `PrivateKey#createSign().sign()`.
A Signature object can also be passed to a verifier produced by
`Key#createVerify()` and it will automatically be converted into the correct
format for verification.
`Key#createVerify()` and it will automatically be converted internally into the
correct format for verification.

@@ -225,3 +320,3 @@ Parameters

- `algorithm` -- a String, name of the algorithm to be used, possible values
are `rsa`, `dsa` and `ecdsa`
are `rsa`, `dsa`, `ecdsa`
- `format` -- a String, either `asn1` or `ssh`

@@ -276,1 +371,7 @@

- `innerErr` -- the inner Error thrown by the format parser
Friends of sshpk
----------------
* [`sshpk-agent`](https://github.com/arekinath/node-sshpk-agent) is a library
for speaking the `ssh-agent` protocol from node.js, which uses `sshpk`

@@ -5,10 +5,73 @@ var fs = require('fs');

var keyPem = fs.readFileSync('foo.pem');
var key = sk.Key.parse(keyPem, 'pem');
var sshf = require('ssh-fingerprint');
var httpsig = require('http-signature');
console.log('a %d bit %s key', key.size, key.type);
console.log(key.toString('ssh'));
console.log(key.fingerprint('sha256').toString());
var keyPem = fs.readFileSync('foo');
var keyPubPem = fs.readFileSync('foo.pem');
var keySsh = fs.readFileSync('foo.pub');
var Benchmark = require('benchmark');
var key = sk.Key.parse(keyPem, 'pem', './foo.pem');
console.log('-> using a %d bit %s key', key.size, key.type);
console.log('-> fingerprint: %s', key.fingerprint('sha256').toString());
var fp = sk.Fingerprint.parse('MD5:0a:b6:37:a4:5f:e7:94:d3:31:e4:72:91:fc:0c:bb:2f');
console.log(fp.matches(key));
var keySshString = keySsh.toString();
var keyPemString = keyPem.toString();
var suite = new Benchmark.Suite();
suite.add('PrivateKey.parse(pem)', function() {
sk.PrivateKey.parse(keyPem, 'pem');
});
suite.add('PrivateKey.parse(pkcs1)', function() {
sk.PrivateKey.parse(keyPem, 'pkcs1');
});
suite.add('Key.parse(pem)', function() {
sk.Key.parse(keyPubPem, 'pem');
});
suite.add('Key.parse(ssh)', function() {
sk.Key.parse(keySsh, 'ssh');
});
suite.add('Key#fingerprint(md5).toString', function() {
key.fingerprint('md5').toString();
});
suite.add('Key.parse(ssh)#fingerprint(md5).toString', function() {
var k = sk.Key.parse(keySsh, 'ssh');
k.fingerprint('md5').toString();
});
suite.add('ufdsgen', function() {
var k = sk.Key.parse(keySsh, 'ssh');
k.fingerprint('md5').toString('hex');
k.fingerprint('sha1').toString('base64');
k.fingerprint('sha256').toString('base64');
});
suite.add('Fingerprint.parse', function() {
sk.Fingerprint.parse('MD5:0a:b6:37:a4:5f:e7:94:d3:31:e4:72:91:fc:0c:bb:2f');
});
suite.add('Fingerprint#matches(Key)', function() {
fp.matches(key);
});
suite.add('Key#toBuffer(pem)', function() {
key.toBuffer('pem');
});
suite.add('Key#toBuffer(ssh)', function() {
key.toBuffer('ssh');
});
suite.add('ssh-fingerprint(md5)', function() {
sshf.calculate(keySshString, {algorithm: 'md5'});
});
suite.add('node-http-sig.pemToRsaSSHKey', function() {
httpsig.pemToRsaSSHKey(keyPemString, 'foo@foo.com');
});
suite.add('node-http-sig.sshKeyFingerprint', function() {
httpsig.sshKeyFingerprint(keySshString);
});
suite.on('cycle', function(evt) {
console.log(String(evt.target));
});
suite.run({async: true});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc