sshpk
Advanced tools
Comparing version 1.13.1 to 1.13.2
@@ -17,5 +17,4 @@ // Copyright 2015 Joyent, Inc. | ||
'ed25519': { | ||
parts: ['R'], | ||
normalize: false, | ||
sizePart: 'R' | ||
parts: ['A'], | ||
sizePart: 'A' | ||
} | ||
@@ -36,4 +35,3 @@ }; | ||
'ed25519': { | ||
parts: ['R', 'r'], | ||
normalize: false | ||
parts: ['A', 'k'] | ||
} | ||
@@ -40,0 +38,0 @@ }; |
@@ -82,3 +82,4 @@ // Copyright 2017 Joyent, Inc. | ||
if (this._isPriv) { | ||
this._priv = key.part.r.data; | ||
utils.assertCompatible(key, PrivateKey, [1, 5], 'key'); | ||
this._priv = key.part.k.data; | ||
} | ||
@@ -147,3 +148,6 @@ | ||
} else if (pk.type === 'curve25519') { | ||
this._priv = pk.part.r.data; | ||
var k = pk.part.k; | ||
if (!pk.part.k) | ||
k = pk.part.r; | ||
this._priv = k.data; | ||
if (this._priv[0] === 0x00) | ||
@@ -180,10 +184,9 @@ this._priv = this._priv.slice(1); | ||
} else if (this._algo === 'curve25519') { | ||
pub = otherpk.part.R.data; | ||
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(this._priv.length, 64); | ||
assert.strictEqual(priv.length, 32); | ||
var priv = this._priv.slice(0, 32); | ||
var secret = nacl.box.before(new Uint8Array(pub), | ||
@@ -267,4 +270,4 @@ new Uint8Array(priv)); | ||
parts.push({name: 'R', data: pub}); | ||
parts.push({name: 'r', data: priv}); | ||
parts.push({name: 'A', data: pub}); | ||
parts.push({name: 'k', data: priv}); | ||
this._key = new PrivateKey({ | ||
@@ -334,4 +337,4 @@ type: 'curve25519', | ||
var parts = []; | ||
parts.push({name: 'R', data: pub}); | ||
parts.push({name: 'r', data: priv}); | ||
parts.push({name: 'A', data: pub}); | ||
parts.push({name: 'k', data: priv.slice(0, 32)}); | ||
var key = new PrivateKey({ | ||
@@ -377,3 +380,2 @@ type: 'ed25519', | ||
return (key); | ||
} else { | ||
@@ -380,0 +382,0 @@ if (ecdh === undefined) |
@@ -59,3 +59,3 @@ // Copyright 2015 Joyent, Inc. | ||
new Uint8Array(sig), | ||
new Uint8Array(this.key.part.R.data))); | ||
new Uint8Array(this.key.part.A.data))); | ||
}; | ||
@@ -92,3 +92,4 @@ | ||
new Uint8Array(Buffer.concat(this.chunks)), | ||
new Uint8Array(this.key.part.r.data)); | ||
new Uint8Array(Buffer.concat([ | ||
this.key.part.k.data, this.key.part.A.data]))); | ||
var sigBuf = new Buffer(sig); | ||
@@ -95,0 +96,0 @@ var sigObj = Signature.parse(sigBuf, 'ed25519', 'raw'); |
@@ -16,3 +16,6 @@ // Copyright 2015 Joyent, Inc. | ||
var rfc4253 = require('./rfc4253'); | ||
var dnssec = require('./dnssec'); | ||
var DNSSEC_PRIVKEY_HEADER_PREFIX = 'Private-key-format: v1'; | ||
function read(buf, options) { | ||
@@ -26,2 +29,4 @@ if (typeof (buf) === 'string') { | ||
return (ssh.read(buf, options)); | ||
if (findDNSSECHeader(buf)) | ||
return (dnssec.read(buf, options)); | ||
buf = new Buffer(buf, 'binary'); | ||
@@ -34,2 +39,4 @@ } else { | ||
return (ssh.read(buf, options)); | ||
if (findDNSSECHeader(buf)) | ||
return (dnssec.read(buf, options)); | ||
} | ||
@@ -74,4 +81,30 @@ if (buf.readUInt32BE(0) < buf.length) | ||
function findDNSSECHeader(buf) { | ||
// private case first | ||
if (buf.length <= DNSSEC_PRIVKEY_HEADER_PREFIX.length) | ||
return (false); | ||
var headerCheck = buf.slice(0, DNSSEC_PRIVKEY_HEADER_PREFIX.length); | ||
if (headerCheck.toString('ascii') === DNSSEC_PRIVKEY_HEADER_PREFIX) | ||
return (true); | ||
// public-key RFC3110 ? | ||
// 'domain.com. IN KEY ...' or 'domain.com. IN DNSKEY ...' | ||
// skip any comment-lines | ||
if (typeof (buf) !== 'string') { | ||
buf = buf.toString('ascii'); | ||
} | ||
var lines = buf.split('\n'); | ||
var line = 0; | ||
/* JSSTYLED */ | ||
while (lines[line].match(/^\;/)) | ||
line++; | ||
if (lines[line].toString('ascii').match(/\. IN KEY /)) | ||
return (true); | ||
if (lines[line].toString('ascii').match(/\. IN DNSKEY /)) | ||
return (true); | ||
return (false); | ||
} | ||
function write(key, options) { | ||
throw (new Error('"auto" format cannot be used for writing')); | ||
} |
@@ -37,7 +37,7 @@ // Copyright 2015 Joyent, Inc. | ||
var m = lines[0].match(/*JSSTYLED*/ | ||
/[-]+[ ]*BEGIN ([A-Z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/); | ||
/[-]+[ ]*BEGIN ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/); | ||
assert.ok(m, 'invalid PEM header'); | ||
var m2 = lines[lines.length - 1].match(/*JSSTYLED*/ | ||
/[-]+[ ]*END ([A-Z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/); | ||
/[-]+[ ]*END ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/); | ||
assert.ok(m2, 'invalid PEM footer'); | ||
@@ -139,3 +139,8 @@ | ||
var alg = {'ecdsa': 'EC', 'rsa': 'RSA', 'dsa': 'DSA'}[key.type]; | ||
var alg = { | ||
'ecdsa': 'EC', | ||
'rsa': 'RSA', | ||
'dsa': 'DSA', | ||
'ed25519': 'EdDSA' | ||
}[key.type]; | ||
var header; | ||
@@ -142,0 +147,0 @@ |
@@ -58,2 +58,7 @@ // Copyright 2015 Joyent, Inc. | ||
throw (new Error('Unknown key type: ' + type)); | ||
case 'EDDSA': | ||
case 'EdDSA': | ||
if (type === 'private') | ||
return (readPkcs1EdDSAPrivate(der)); | ||
throw (new Error(type + ' keys not supported with EdDSA')); | ||
default: | ||
@@ -138,2 +143,27 @@ throw (new Error('Unknown key algo: ' + alg)); | ||
function readPkcs1EdDSAPrivate(der) { | ||
var version = readMPInt(der, 'version'); | ||
assert.strictEqual(version.readUInt8(0), 1); | ||
// private key | ||
var k = der.readString(asn1.Ber.OctetString, true); | ||
der.readSequence(0xa0); | ||
var oid = der.readOID(); | ||
assert.strictEqual(oid, '1.3.101.112', 'the ed25519 curve identifier'); | ||
der.readSequence(0xa1); | ||
var A = utils.readBitString(der); | ||
var key = { | ||
type: 'ed25519', | ||
parts: [ | ||
{ name: 'A', data: utils.zeroPadToLength(A, 32) }, | ||
{ name: 'k', data: k } | ||
] | ||
}; | ||
return (new PrivateKey(key)); | ||
} | ||
function readPkcs1DSAPublic(der) { | ||
@@ -241,2 +271,8 @@ var y = readMPInt(der, 'y'); | ||
break; | ||
case 'ed25519': | ||
if (PrivateKey.isPrivateKey(key)) | ||
writePkcs1EdDSAPrivate(der, key); | ||
else | ||
writePkcs1EdDSAPublic(der, key); | ||
break; | ||
default: | ||
@@ -324,1 +360,21 @@ throw (new Error('Unknown key algo: ' + key.type)); | ||
} | ||
function writePkcs1EdDSAPrivate(der, key) { | ||
var ver = new Buffer(1); | ||
ver[0] = 1; | ||
der.writeBuffer(ver, asn1.Ber.Integer); | ||
der.writeBuffer(key.part.k.data, asn1.Ber.OctetString); | ||
der.startSequence(0xa0); | ||
der.writeOID('1.3.101.112'); | ||
der.endSequence(); | ||
der.startSequence(0xa1); | ||
utils.writeBitString(der, key.part.A.data); | ||
der.endSequence(); | ||
} | ||
function writePkcs1EdDSAPublic(der, key) { | ||
throw (new Error('Public keys are not supported for EdDSA PKCS#1')); | ||
} |
@@ -65,2 +65,14 @@ // Copyright 2015 Joyent, Inc. | ||
return (readPkcs8ECDSAPrivate(der)); | ||
case '1.3.101.112': | ||
if (type === 'public') { | ||
return (readPkcs8EdDSAPublic(der)); | ||
} else { | ||
return (readPkcs8EdDSAPrivate(der)); | ||
} | ||
case '1.3.101.110': | ||
if (type === 'public') { | ||
return (readPkcs8X25519Public(der)); | ||
} else { | ||
return (readPkcs8X25519Private(der)); | ||
} | ||
default: | ||
@@ -326,2 +338,79 @@ throw (new Error('Unknown key type OID ' + oid)); | ||
function readPkcs8EdDSAPublic(der) { | ||
if (der.peek() === 0x00) | ||
der.readByte(); | ||
var A = utils.readBitString(der); | ||
var key = { | ||
type: 'ed25519', | ||
parts: [ | ||
{ name: 'A', data: utils.zeroPadToLength(A, 32) } | ||
] | ||
}; | ||
return (new Key(key)); | ||
} | ||
function readPkcs8X25519Public(der) { | ||
var A = utils.readBitString(der); | ||
var key = { | ||
type: 'curve25519', | ||
parts: [ | ||
{ name: 'A', data: utils.zeroPadToLength(A, 32) } | ||
] | ||
}; | ||
return (new Key(key)); | ||
} | ||
function readPkcs8EdDSAPrivate(der) { | ||
if (der.peek() === 0x00) | ||
der.readByte(); | ||
der.readSequence(asn1.Ber.OctetString); | ||
var k = der.readString(asn1.Ber.OctetString, true); | ||
k = utils.zeroPadToLength(k, 32); | ||
var A; | ||
if (der.peek() === asn1.Ber.BitString) { | ||
A = utils.readBitString(der); | ||
A = utils.zeroPadToLength(A, 32); | ||
} else { | ||
A = utils.calculateED25519Public(k); | ||
} | ||
var key = { | ||
type: 'ed25519', | ||
parts: [ | ||
{ name: 'A', data: utils.zeroPadToLength(A, 32) }, | ||
{ name: 'k', data: utils.zeroPadToLength(k, 32) } | ||
] | ||
}; | ||
return (new PrivateKey(key)); | ||
} | ||
function readPkcs8X25519Private(der) { | ||
if (der.peek() === 0x00) | ||
der.readByte(); | ||
der.readSequence(asn1.Ber.OctetString); | ||
var k = der.readString(asn1.Ber.OctetString, true); | ||
k = utils.zeroPadToLength(k, 32); | ||
var A = utils.calculateX25519Public(k); | ||
var key = { | ||
type: 'curve25519', | ||
parts: [ | ||
{ name: 'A', data: utils.zeroPadToLength(A, 32) }, | ||
{ name: 'k', data: utils.zeroPadToLength(k, 32) } | ||
] | ||
}; | ||
return (new PrivateKey(key)); | ||
} | ||
function writePkcs8(der, key) { | ||
@@ -359,2 +448,9 @@ der.startSequence(); | ||
break; | ||
case 'ed25519': | ||
der.writeOID('1.3.101.112'); | ||
if (PrivateKey.isPrivateKey(key)) | ||
throw (new Error('Ed25519 private keys in pkcs8 ' + | ||
'format are not supported')); | ||
writePkcs8EdDSAPublic(key, der); | ||
break; | ||
default: | ||
@@ -509,1 +605,16 @@ throw (new Error('Unsupported key type: ' + key.type)); | ||
} | ||
function writePkcs8EdDSAPublic(key, der) { | ||
der.endSequence(); | ||
utils.writeBitString(der, key.part.A.data); | ||
} | ||
function writePkcs8EdDSAPrivate(key, der) { | ||
der.endSequence(); | ||
var k = utils.mpNormalize(key.part.k.data, true); | ||
der.startSequence(asn1.Ber.OctetString); | ||
der.writeBuffer(k, asn1.Ber.OctetString); | ||
der.endSequence(); | ||
} |
@@ -100,8 +100,21 @@ // Copyright 2015 Joyent, Inc. | ||
for (var i = 0; i < algInfo.parts.length; ++i) { | ||
parts[i].name = algInfo.parts[i]; | ||
if (parts[i].name !== 'curve' && | ||
algInfo.normalize !== false) { | ||
var p = parts[i]; | ||
var nd = utils.mpNormalize(p.data); | ||
if (nd !== p.data) { | ||
var p = parts[i]; | ||
p.name = algInfo.parts[i]; | ||
/* | ||
* OpenSSH stores ed25519 "private" keys as seed + public key | ||
* concat'd together (k followed by A). We want to keep them | ||
* separate for other formats that don't do this. | ||
*/ | ||
if (key.type === 'ed25519' && p.name === 'k') | ||
p.data = p.data.slice(0, 32); | ||
if (p.name !== 'curve' && algInfo.normalize !== false) { | ||
var nd; | ||
if (key.type === 'ed25519') { | ||
nd = utils.zeroPadToLength(p.data, 32); | ||
} else { | ||
nd = utils.mpNormalize(p.data); | ||
} | ||
if (nd.toString('binary') !== | ||
p.data.toString('binary')) { | ||
p.data = nd; | ||
@@ -141,4 +154,10 @@ normalized = false; | ||
var data = key.part[parts[i]].data; | ||
if (algInfo.normalize !== false) | ||
data = utils.mpNormalize(data); | ||
if (algInfo.normalize !== false) { | ||
if (key.type === 'ed25519') | ||
data = utils.zeroPadToLength(data, 32); | ||
else | ||
data = utils.mpNormalize(data); | ||
} | ||
if (key.type === 'ed25519' && parts[i] === 'k') | ||
data = Buffer.concat([data, key.part.A.data]); | ||
buf.writeBuffer(data); | ||
@@ -145,0 +164,0 @@ } |
@@ -17,5 +17,5 @@ // Copyright 2015 Joyent, Inc. | ||
/*JSSTYLED*/ | ||
var SSHKEY_RE = /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/]+[=]*)([\n \t]+([^\n]+))?$/; | ||
var SSHKEY_RE = /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/]+[=]*)([ \t]+([^ \t][^\n]*[\n]*)?)?$/; | ||
/*JSSTYLED*/ | ||
var SSHKEY_RE2 = /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/ \t\n]+[=]*)(.*)$/; | ||
var SSHKEY_RE2 = /^([a-z0-9-]+)[ \t\n]+([a-zA-Z0-9+\/][a-zA-Z0-9+\/ \t\n=]*)([^a-zA-Z0-9+\/ \t\n=].*)?$/; | ||
@@ -75,3 +75,3 @@ function read(buf, options) { | ||
*/ | ||
var data = m[2] + m[3]; | ||
var data = m[2] + (m[3] ? m[3] : ''); | ||
var realOffset = Math.ceil(ret.consumed / 3) * 4; | ||
@@ -78,0 +78,0 @@ data = data.slice(0, realOffset - 2). /*JSSTYLED*/ |
@@ -73,3 +73,4 @@ // Copyright 2017 Joyent, Inc. | ||
'ecdsa-sha384': '1.2.840.10045.4.3.3', | ||
'ecdsa-sha512': '1.2.840.10045.4.3.4' | ||
'ecdsa-sha512': '1.2.840.10045.4.3.4', | ||
'ed25519-sha512': '1.3.101.112' | ||
}; | ||
@@ -526,2 +527,4 @@ Object.keys(SIGN_ALGS).forEach(function (k) { | ||
der.writeOID(SIGN_ALGS[sig.algo]); | ||
if (sig.algo.match(/^rsa-/)) | ||
der.writeNull(); | ||
der.endSequence(); | ||
@@ -528,0 +531,0 @@ |
@@ -139,10 +139,21 @@ // Copyright 2017 Joyent, Inc. | ||
* IA5String or UTF8String. | ||
* | ||
* If this identity was parsed from a DN, use the ASN.1 types | ||
* from the original representation (otherwise this might not | ||
* be a full match for the original in some validators). | ||
*/ | ||
if (c.value.match(NOT_IA5)) { | ||
if (c.asn1type === asn1.Ber.Utf8String || | ||
c.value.match(NOT_IA5)) { | ||
var v = new Buffer(c.value, 'utf8'); | ||
der.writeBuffer(v, asn1.Ber.Utf8String); | ||
} else if (c.value.match(NOT_PRINTABLE)) { | ||
} else if (c.asn1type === asn1.Ber.IA5String || | ||
c.value.match(NOT_PRINTABLE)) { | ||
der.writeString(c.value, asn1.Ber.IA5String); | ||
} else { | ||
der.writeString(c.value, asn1.Ber.PrintableString); | ||
var type = asn1.Ber.PrintableString; | ||
if (c.asn1type !== undefined) | ||
type = c.asn1type; | ||
der.writeString(c.value, type); | ||
} | ||
@@ -257,3 +268,3 @@ der.endSequence(); | ||
} | ||
components.push({ oid: oid, value: value }); | ||
components.push({ oid: oid, asn1type: type, value: value }); | ||
der._offset = after; | ||
@@ -260,0 +271,0 @@ } |
@@ -34,2 +34,3 @@ // Copyright 2017 Joyent, Inc. | ||
formats['openssh'] = formats['ssh-private']; | ||
formats['dnssec'] = require('./formats/dnssec'); | ||
@@ -109,3 +110,2 @@ function Key(opts) { | ||
return (this._hashCache[algo]); | ||
var hash = crypto.createHash(algo). | ||
@@ -261,4 +261,5 @@ update(this.toBuffer('rfc4253')).digest(); | ||
* [1,5] -- first explicitly tagged version | ||
* [1,6] -- changed ed25519 part names | ||
*/ | ||
Key.prototype._sshpkApiVersion = [1, 5]; | ||
Key.prototype._sshpkApiVersion = [1, 6]; | ||
@@ -265,0 +266,0 @@ Key._oldVersionDetect = function (obj) { |
@@ -40,2 +40,3 @@ // Copyright 2017 Joyent, Inc. | ||
formats['ssh'] = formats['ssh-private']; | ||
formats['dnssec'] = require('./formats/dnssec'); | ||
@@ -95,10 +96,8 @@ function PrivateKey(opts) { | ||
priv = this.part.r.data; | ||
priv = this.part.k.data; | ||
if (priv[0] === 0x00) | ||
priv = priv.slice(1); | ||
priv = priv.slice(0, 32); | ||
pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); | ||
pub = new Buffer(pair.publicKey); | ||
priv = Buffer.concat([priv, pub]); | ||
@@ -108,4 +107,4 @@ return (new PrivateKey({ | ||
parts: [ | ||
{ name: 'R', data: utils.mpNormalize(pub) }, | ||
{ name: 'r', data: priv } | ||
{ name: 'A', data: utils.mpNormalize(pub) }, | ||
{ name: 'k', data: utils.mpNormalize(priv) } | ||
] | ||
@@ -117,10 +116,8 @@ })); | ||
priv = this.part.r.data; | ||
priv = this.part.k.data; | ||
if (priv[0] === 0x00) | ||
priv = priv.slice(1); | ||
priv = priv.slice(0, 32); | ||
pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); | ||
pub = new Buffer(pair.publicKey); | ||
priv = Buffer.concat([priv, pub]); | ||
@@ -130,4 +127,4 @@ return (new PrivateKey({ | ||
parts: [ | ||
{ name: 'R', data: utils.mpNormalize(pub) }, | ||
{ name: 'r', data: priv } | ||
{ name: 'A', data: utils.mpNormalize(pub) }, | ||
{ name: 'k', data: utils.mpNormalize(priv) } | ||
] | ||
@@ -246,4 +243,5 @@ })); | ||
* [1,4] -- first tagged version | ||
* [1,5] -- changed ed25519 part names and format | ||
*/ | ||
PrivateKey.prototype._sshpkApiVersion = [1, 4]; | ||
PrivateKey.prototype._sshpkApiVersion = [1, 5]; | ||
@@ -250,0 +248,0 @@ PrivateKey._oldVersionDetect = function (obj) { |
102
lib/utils.js
@@ -7,3 +7,6 @@ // Copyright 2015 Joyent, Inc. | ||
calculateDSAPublic: calculateDSAPublic, | ||
calculateED25519Public: calculateED25519Public, | ||
calculateX25519Public: calculateX25519Public, | ||
mpNormalize: mpNormalize, | ||
mpDenormalize: mpDenormalize, | ||
ecNormalize: ecNormalize, | ||
@@ -14,3 +17,7 @@ countZeros: countZeros, | ||
opensslKeyDeriv: opensslKeyDeriv, | ||
opensshCipherInfo: opensshCipherInfo | ||
opensshCipherInfo: opensshCipherInfo, | ||
publicFromPrivateECDSA: publicFromPrivateECDSA, | ||
zeroPadToLength: zeroPadToLength, | ||
writeBitString: writeBitString, | ||
readBitString: readBitString | ||
}; | ||
@@ -20,4 +27,10 @@ | ||
var PrivateKey = require('./private-key'); | ||
var Key = require('./key'); | ||
var crypto = require('crypto'); | ||
var algs = require('./algs'); | ||
var asn1 = require('asn1'); | ||
var ec, jsbn; | ||
var nacl; | ||
var MAX_CLASS_DEPTH = 3; | ||
@@ -184,2 +197,20 @@ | ||
function readBitString(der, tag) { | ||
if (tag === undefined) | ||
tag = asn1.Ber.BitString; | ||
var buf = der.readString(tag, true); | ||
assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + | ||
'not supported (0x' + buf[0].toString(16) + ')'); | ||
return (buf.slice(1)); | ||
} | ||
function writeBitString(der, buf, tag) { | ||
if (tag === undefined) | ||
tag = asn1.Ber.BitString; | ||
var b = new Buffer(buf.length + 1); | ||
b[0] = 0x00; | ||
buf.copy(b, 1); | ||
der.writeBuffer(b, tag); | ||
} | ||
function mpNormalize(buf) { | ||
@@ -198,2 +229,25 @@ assert.buffer(buf); | ||
function mpDenormalize(buf) { | ||
assert.buffer(buf); | ||
while (buf.length > 1 && buf[0] === 0x00) | ||
buf = buf.slice(1); | ||
return (buf); | ||
} | ||
function zeroPadToLength(buf, len) { | ||
assert.buffer(buf); | ||
assert.number(len); | ||
while (buf.length > len) { | ||
assert.equal(buf[0], 0x00); | ||
buf = buf.slice(1); | ||
} | ||
while (buf.length < len) { | ||
var b = new Buffer(buf.length + 1); | ||
b[0] = 0x00; | ||
buf.copy(b, 1); | ||
buf = b; | ||
} | ||
return (buf); | ||
} | ||
function bigintToMpBuf(bigint) { | ||
@@ -223,2 +277,22 @@ var buf = new Buffer(bigint.toByteArray()); | ||
function calculateED25519Public(k) { | ||
assert.buffer(k); | ||
if (nacl === undefined) | ||
nacl = require('tweetnacl'); | ||
var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); | ||
return (new Buffer(kp.publicKey)); | ||
} | ||
function calculateX25519Public(k) { | ||
assert.buffer(k); | ||
if (nacl === undefined) | ||
nacl = require('tweetnacl'); | ||
var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); | ||
return (new Buffer(kp.publicKey)); | ||
} | ||
function addRSAMissing(key) { | ||
@@ -255,2 +329,28 @@ assert.object(key); | ||
function publicFromPrivateECDSA(curveName, priv) { | ||
assert.string(curveName, 'curveName'); | ||
assert.buffer(priv); | ||
if (ec === undefined) | ||
ec = require('ecc-jsbn/lib/ec'); | ||
if (jsbn === undefined) | ||
jsbn = require('jsbn').BigInteger; | ||
var params = algs.curves[curveName]; | ||
var p = new jsbn(params.p); | ||
var a = new jsbn(params.a); | ||
var b = new jsbn(params.b); | ||
var curve = new ec.ECCurveFp(p, a, b); | ||
var G = curve.decodePointHex(params.G.toString('hex')); | ||
var d = new jsbn(mpNormalize(priv)); | ||
var pub = G.multiply(d); | ||
pub = new Buffer(curve.encodePointHex(pub), 'hex'); | ||
var parts = []; | ||
parts.push({name: 'curve', data: new Buffer(curveName)}); | ||
parts.push({name: 'Q', data: pub}); | ||
var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); | ||
return (key); | ||
} | ||
function opensshCipherInfo(cipher) { | ||
@@ -257,0 +357,0 @@ var inf = {}; |
{ | ||
"name": "sshpk", | ||
"version": "1.13.1", | ||
"version": "1.13.2", | ||
"description": "A library for finding and using SSH public keys", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
Sorry, the diff of this file is not supported yet
208057
35
5418