|
1 | | -// Copyright 2015 Joyent, Inc. |
| 1 | +// Copyright 2017 Joyent, Inc. |
2 | 2 |
|
3 | | -module.exports = DiffieHellman; |
| 3 | +module.exports = { |
| 4 | + DiffieHellman: DiffieHellman, |
| 5 | + generateECDSA: generateECDSA, |
| 6 | + generateED25519: generateED25519 |
| 7 | +}; |
4 | 8 |
|
5 | 9 | var assert = require('assert-plus'); |
6 | 10 | var crypto = require('crypto'); |
7 | 11 | var algs = require('./algs'); |
8 | 12 | var utils = require('./utils'); |
9 | 13 | var ed; |
| 14 | +var nacl; |
10 | 15 |
|
11 | 16 | var Key = require('./key'); |
12 | 17 | var PrivateKey = require('./private-key'); |
@@ -309,3 +314,97 @@ ECPrivate.prototype.deriveSharedSecret = function (pubKey) { |
309 | 314 | var S = pubKey._pub.multiply(this._priv); |
310 | 315 | return (new Buffer(S.getX().toBigInteger().toByteArray())); |
311 | 316 | }; |
| 317 | + |
| 318 | +function generateED25519() { |
| 319 | + if (nacl === undefined) |
| 320 | + nacl = require('tweetnacl'); |
| 321 | + |
| 322 | + var pair = nacl.sign.keyPair(); |
| 323 | + var priv = new Buffer(pair.secretKey); |
| 324 | + var pub = new Buffer(pair.publicKey); |
| 325 | + assert.strictEqual(priv.length, 64); |
| 326 | + assert.strictEqual(pub.length, 32); |
| 327 | + |
| 328 | + var parts = []; |
| 329 | + parts.push({name: 'R', data: pub}); |
| 330 | + parts.push({name: 'r', data: priv}); |
| 331 | + var key = new PrivateKey({ |
| 332 | + type: 'ed25519', |
| 333 | + parts: parts |
| 334 | + }); |
| 335 | + return (key); |
| 336 | +} |
| 337 | + |
| 338 | +/* Generates a new ECDSA private key on a given curve. */ |
| 339 | +function generateECDSA(curve) { |
| 340 | + var parts = []; |
| 341 | + var key; |
| 342 | + |
| 343 | + if (CRYPTO_HAVE_ECDH) { |
| 344 | + /* |
| 345 | + * Node crypto doesn't expose key generation directly, but the |
| 346 | + * ECDH instances can generate keys. It turns out this just |
| 347 | + * calls into the OpenSSL generic key generator, and we can |
| 348 | + * read its output happily without doing an actual DH. So we |
| 349 | + * use that here. |
| 350 | + */ |
| 351 | + var osCurve = { |
| 352 | + 'nistp256': 'prime256v1', |
| 353 | + 'nistp384': 'secp384r1', |
| 354 | + 'nistp521': 'secp521r1' |
| 355 | + }[curve]; |
| 356 | + |
| 357 | + var dh = crypto.createECDH(osCurve); |
| 358 | + dh.generateKeys(); |
| 359 | + |
| 360 | + parts.push({name: 'curve', |
| 361 | + data: new Buffer(curve)}); |
| 362 | + parts.push({name: 'Q', data: dh.getPublicKey()}); |
| 363 | + parts.push({name: 'd', data: dh.getPrivateKey()}); |
| 364 | + |
| 365 | + key = new PrivateKey({ |
| 366 | + type: 'ecdsa', |
| 367 | + curve: curve, |
| 368 | + parts: parts |
| 369 | + }); |
| 370 | + return (key); |
| 371 | + |
| 372 | + } else { |
| 373 | + if (ecdh === undefined) |
| 374 | + ecdh = require('ecc-jsbn'); |
| 375 | + if (ec === undefined) |
| 376 | + ec = require('ecc-jsbn/lib/ec'); |
| 377 | + if (jsbn === undefined) |
| 378 | + jsbn = require('jsbn').BigInteger; |
| 379 | + |
| 380 | + var ecParams = new X9ECParameters(curve); |
| 381 | + |
| 382 | + /* This algorithm taken from FIPS PUB 186-4 (section B.4.1) */ |
| 383 | + var n = ecParams.getN(); |
| 384 | + /* |
| 385 | + * The crypto.randomBytes() function can only give us whole |
| 386 | + * bytes, so taking a nod from X9.62, we round up. |
| 387 | + */ |
| 388 | + var cByteLen = Math.ceil((n.bitLength() + 64) / 8); |
| 389 | + var c = new jsbn(crypto.randomBytes(cByteLen)); |
| 390 | + |
| 391 | + var n1 = n.subtract(jsbn.ONE); |
| 392 | + var priv = c.mod(n1).add(jsbn.ONE); |
| 393 | + var pub = ecParams.getG().multiply(priv); |
| 394 | + |
| 395 | + priv = new Buffer(priv.toByteArray()); |
| 396 | + pub = new Buffer(ecParams.getCurve(). |
| 397 | + encodePointHex(pub), 'hex'); |
| 398 | + |
| 399 | + parts.push({name: 'curve', data: new Buffer(curve)}); |
| 400 | + parts.push({name: 'Q', data: pub}); |
| 401 | + parts.push({name: 'd', data: priv}); |
| 402 | + |
| 403 | + key = new PrivateKey({ |
| 404 | + type: 'ecdsa', |
| 405 | + curve: curve, |
| 406 | + parts: parts |
| 407 | + }); |
| 408 | + return (key); |
| 409 | + } |
| 410 | +} |
0 commit comments