Skip to content

Commit

Permalink
#28 remove remaining usage of jodid25519
Browse files Browse the repository at this point in the history
#30 curve25519 keys should always have size 256
Reviewed by: Cody Peter Mello <cody.mello@joyent.com>
  • Loading branch information
Alex Wilson committed Jun 8, 2017
1 parent 78cf827 commit a17ec88
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 33 deletions.
33 changes: 17 additions & 16 deletions lib/dhe.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ var assert = require('assert-plus');
var crypto = require('crypto');
var algs = require('./algs');
var utils = require('./utils');
var ed;
var nacl;

var Key = require('./key');
Expand Down Expand Up @@ -76,14 +75,11 @@ function DiffieHellman(key) {
this._dh.setPublicKey(key.part.Q.data);

} else if (key.type === 'curve25519') {
if (ed === undefined)
ed = require('jodid25519');
if (nacl === undefined)
nacl = require('tweetnacl');

if (this._isPriv) {
this._priv = key.part.r.data;
if (this._priv[0] === 0x00)
this._priv = this._priv.slice(1);
this._priv = this._priv.slice(0, 32);
}

} else {
Expand Down Expand Up @@ -180,14 +176,17 @@ DiffieHellman.prototype.computeSecret = function (otherpk) {

} else if (this._algo === 'curve25519') {
pub = otherpk.part.R.data;
if (pub[0] === 0x00)
while (pub[0] === 0x00 && pub.length > 32)
pub = pub.slice(1);
assert.strictEqual(pub.length, 32);
assert.strictEqual(this._priv.length, 64);

var secret = ed.dh.computeKey(
this._priv.toString('binary'),
pub.toString('binary'));
var priv = this._priv.slice(0, 32);

return (new Buffer(secret, 'binary'));
var secret = nacl.box.before(new Uint8Array(pub),
new Uint8Array(priv));

return (new Buffer(secret));
}

throw (new Error('Invalid algorithm: ' + this._algo));
Expand Down Expand Up @@ -255,13 +254,15 @@ DiffieHellman.prototype.generateKey = function () {
}

} else if (this._algo === 'curve25519') {
priv = ed.dh.generateKey();
pub = ed.dh.publicKey(priv);
this._priv = priv = new Buffer(priv, 'binary');
pub = new Buffer(pub, 'binary');
var pair = nacl.box.keyPair();
priv = new Buffer(pair.secretKey);
pub = new Buffer(pair.publicKey);
priv = Buffer.concat([priv, pub]);
assert.strictEqual(priv.length, 64);
assert.strictEqual(pub.length, 32);

parts.push({name: 'R', data: pub});
parts.push({name: 'r', data: Buffer.concat([priv, pub])});
parts.push({name: 'r', data: priv});
this._key = new PrivateKey({
type: 'curve25519',
parts: parts
Expand Down
2 changes: 1 addition & 1 deletion lib/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function Key(opts) {
var curve = this.part.curve.data.toString();
this.curve = curve;
sz = algs.curves[curve].size;
} else if (this.type === 'ed25519') {
} else if (this.type === 'ed25519' || this.type === 'curve25519') {
sz = 256;
this.curve = 'curve25519';
} else {
Expand Down
27 changes: 13 additions & 14 deletions lib/private-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var dhe = require('./dhe');
var generateECDSA = dhe.generateECDSA;
var generateED25519 = dhe.generateED25519;
var edCompat;
var ed;
var nacl;

try {
edCompat = require('./ed-compat');
Expand Down Expand Up @@ -83,22 +83,22 @@ PrivateKey.prototype.toPublic = function () {
return (this._pubCache);
};

PrivateKey.prototype.derive = function (newType, newSize) {
PrivateKey.prototype.derive = function (newType) {
assert.string(newType, 'type');
assert.optionalNumber(newSize, 'size');
var priv, pub;
var priv, pub, pair;

if (this.type === 'ed25519' && newType === 'curve25519') {
if (ed === undefined)
ed = require('jodid25519');
if (nacl === undefined)
nacl = require('tweetnacl');

priv = this.part.r.data;
if (priv[0] === 0x00)
priv = priv.slice(1);
priv = priv.slice(0, 32);

pub = ed.dh.publicKey(priv);
priv = utils.mpNormalize(Buffer.concat([priv, pub]));
pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv));
pub = new Buffer(pair.publicKey);
priv = Buffer.concat([priv, pub]);

return (new PrivateKey({
type: 'curve25519',
Expand All @@ -108,18 +108,17 @@ PrivateKey.prototype.derive = function (newType, newSize) {
]
}));
} else if (this.type === 'curve25519' && newType === 'ed25519') {
if (ed === undefined)
ed = require('jodid25519');
if (nacl === undefined)
nacl = require('tweetnacl');

priv = this.part.r.data;
if (priv[0] === 0x00)
priv = priv.slice(1);
priv = priv.slice(0, 32);

pub = ed.eddsa.publicKey(priv.toString('binary'));
pub = new Buffer(pub, 'binary');

priv = utils.mpNormalize(Buffer.concat([priv, pub]));
pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv));
pub = new Buffer(pair.publicKey);
priv = Buffer.concat([priv, pub]);

return (new PrivateKey({
type: 'ed25519',
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sshpk",
"version": "1.13.0",
"version": "1.13.1",
"description": "A library for finding and using SSH public keys",
"main": "lib/index.js",
"scripts": {
Expand Down Expand Up @@ -47,7 +47,6 @@
"optionalDependencies": {
"jsbn": "~0.1.0",
"tweetnacl": "~0.14.0",
"jodid25519": "^1.0.0",
"ecc-jsbn": "~0.1.1",
"bcrypt-pbkdf": "^1.0.0"
},
Expand Down
7 changes: 7 additions & 0 deletions test/assets/ed25519-negative
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAvKwD3bKfjHMID69k5Sd/4RQvU1eOG170KVjJK11JCmwAAAIjZfvZs2X72
bAAAAAtzc2gtZWQyNTUxOQAAACAvKwD3bKfjHMID69k5Sd/4RQvU1eOG170KVjJK11JCmw
AAAECwk2CUV9fFK55Q5A8H4vCx07qS3FOSAOFwZ9Yid8gvqC8rAPdsp+McwgPr2TlJ3/hF
C9TV44bXvQpWMkrXUkKbAAAAAAECAwQF
-----END OPENSSH PRIVATE KEY-----
14 changes: 14 additions & 0 deletions test/dhe.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var sinon = require('sinon');

var ED_KEY, ED2_KEY, EC_KEY, EC2_KEY, ECOUT_KEY, DS_KEY, DS2_KEY, DSOUT_KEY;
var C_KEY, C2_KEY;
var NG_KEY;
var C_SSH;

var testDir = path.join(__dirname, 'assets');
Expand All @@ -31,6 +32,8 @@ test('setup', function (t) {
DS2_KEY = sshpk.parsePrivateKey(k);
k = fs.readFileSync(path.join(testDir, 'id_dsa'));
DSOUT_KEY = sshpk.parsePrivateKey(k);
k = fs.readFileSync(path.join(testDir, 'ed25519-negative'));
NG_KEY = sshpk.parsePrivateKey(k);
t.end();
});

Expand All @@ -43,6 +46,17 @@ test('derive ed25519 -> curve25519', function (t) {
t.end();
});

test('derive ed25519 -> curve25519 -> back (negative seed)', function (t) {
var key = NG_KEY.derive('curve25519');
t.strictEqual(key.type, 'curve25519');
t.strictEqual(key.size, 256);
var key2 = key.derive('ed25519');
t.ok(key2.fingerprint().matches(NG_KEY));
t.strictEqual(key2.part.r.toString('base64'),
key.part.r.toString('base64'));
t.end();
});

test('derive curve25519 -> ed25519', function (t) {
var k = sshpk.parsePrivateKey(C_SSH);
t.strictEqual(k.type, 'curve25519');
Expand Down

0 comments on commit a17ec88

Please sign in to comment.