Skip to content

Commit a226be4

Browse files
mscdexindutny
authored andcommitted
crypto: allow custom generator for DiffieHellman
1 parent 466a9b5 commit a226be4

File tree

8 files changed

+219
-55
lines changed

8 files changed

+219
-55
lines changed

doc/api/crypto.markdown

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,23 +388,39 @@ the data and public key.
388388
Note: `verifier` object can not be used after `verify()` method has been
389389
called.
390390

391-
## crypto.createDiffieHellman(prime_length)
391+
## crypto.createDiffieHellman(prime_length, [generator])
392392

393393
Creates a Diffie-Hellman key exchange object and generates a prime of
394-
the given bit length. The generator used is `2`.
394+
`prime_length` bits and using an optional specific numeric `generator`.
395+
If no `generator` is specified, then `2` is used.
395396

396-
## crypto.createDiffieHellman(prime, [encoding])
397+
## crypto.createDiffieHellman(prime, [prime_encoding], [generator], [generator_encoding])
397398

398-
Creates a Diffie-Hellman key exchange object using the supplied prime.
399-
The generator used is `2`. Encoding can be `'binary'`, `'hex'`, or
400-
`'base64'`. If no encoding is specified, then a buffer is expected.
399+
Creates a Diffie-Hellman key exchange object using the supplied `prime` and an
400+
optional specific `generator`.
401+
`generator` can be a number, string, or Buffer.
402+
If no `generator` is specified, then `2` is used.
403+
`prime_encoding` and `generator_encoding` can be `'binary'`, `'hex'`, or `'base64'`.
404+
If no `prime_encoding` is specified, then a Buffer is expected for `prime`.
405+
If no `generator_encoding` is specified, then a Buffer is expected for `generator`.
401406

402407
## Class: DiffieHellman
403408

404409
The class for creating Diffie-Hellman key exchanges.
405410

406411
Returned by `crypto.createDiffieHellman`.
407412

413+
### diffieHellman.verifyError
414+
415+
A bit field containing any warnings and/or errors as a result of a check performed
416+
during initialization. The following values are valid for this property
417+
(defined in `constants` module):
418+
419+
* `DH_CHECK_P_NOT_SAFE_PRIME`
420+
* `DH_CHECK_P_NOT_PRIME`
421+
* `DH_UNABLE_TO_CHECK_GENERATOR`
422+
* `DH_NOT_SUITABLE_GENERATOR`
423+
408424
### diffieHellman.generateKeys([encoding])
409425

410426
Generates private and public Diffie-Hellman key values, and returns

lib/crypto.js

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ var constants = require('constants');
3939
var stream = require('stream');
4040
var util = require('util');
4141

42+
var DH_GENERATOR = 2;
43+
4244
// This is here because many functions accepted binary strings without
4345
// any explicit encoding in older versions of node, and we don't want
4446
// to break them unnecessarily.
@@ -456,17 +458,36 @@ Verify.prototype.verify = function(object, signature, sigEncoding) {
456458

457459
exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
458460

459-
function DiffieHellman(sizeOrKey, encoding) {
461+
function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) {
460462
if (!(this instanceof DiffieHellman))
461-
return new DiffieHellman(sizeOrKey, encoding);
462-
463-
if (!sizeOrKey)
464-
this._binding = new binding.DiffieHellman();
465-
else {
466-
encoding = encoding || exports.DEFAULT_ENCODING;
467-
sizeOrKey = toBuf(sizeOrKey, encoding);
468-
this._binding = new binding.DiffieHellman(sizeOrKey);
463+
return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding);
464+
465+
if (keyEncoding) {
466+
if (typeof keyEncoding !== 'string' ||
467+
(!Buffer.isEncoding(keyEncoding) && keyEncoding !== 'buffer')) {
468+
genEncoding = generator;
469+
generator = keyEncoding;
470+
keyEncoding = false;
471+
}
469472
}
473+
474+
keyEncoding = keyEncoding || exports.DEFAULT_ENCODING;
475+
genEncoding = genEncoding || exports.DEFAULT_ENCODING;
476+
477+
if (typeof sizeOrKey !== 'number')
478+
sizeOrKey = toBuf(sizeOrKey, keyEncoding);
479+
480+
if (!generator)
481+
generator = DH_GENERATOR;
482+
else if (typeof generator !== 'number')
483+
generator = toBuf(generator, genEncoding);
484+
485+
this._binding = new binding.DiffieHellman(sizeOrKey, generator);
486+
Object.defineProperty(this, 'verifyError', {
487+
enumerable: true,
488+
value: this._binding.verifyError,
489+
writable: false
490+
});
470491
}
471492

472493

@@ -478,6 +499,11 @@ function DiffieHellmanGroup(name) {
478499
if (!(this instanceof DiffieHellmanGroup))
479500
return new DiffieHellmanGroup(name);
480501
this._binding = new binding.DiffieHellmanGroup(name);
502+
Object.defineProperty(this, 'verifyError', {
503+
enumerable: true,
504+
value: this._binding.verifyError,
505+
writable: false
506+
});
481507
}
482508

483509

src/env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ namespace node {
167167
V(used_heap_size_string, "used_heap_size") \
168168
V(valid_from_string, "valid_from") \
169169
V(valid_to_string, "valid_to") \
170+
V(verify_error_string, "verifyError") \
170171
V(version_major_string, "versionMajor") \
171172
V(version_minor_string, "versionMinor") \
172173
V(version_string, "version") \

src/node_constants.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,22 @@ void DefineOpenSSLConstants(Handle<Object> target) {
930930

931931
# endif // !OPENSSL_NO_ENGINE
932932

933+
#ifdef DH_CHECK_P_NOT_SAFE_PRIME
934+
NODE_DEFINE_CONSTANT(target, DH_CHECK_P_NOT_SAFE_PRIME);
935+
#endif
936+
937+
#ifdef DH_CHECK_P_NOT_PRIME
938+
NODE_DEFINE_CONSTANT(target, DH_CHECK_P_NOT_PRIME);
939+
#endif
940+
941+
#ifdef DH_UNABLE_TO_CHECK_GENERATOR
942+
NODE_DEFINE_CONSTANT(target, DH_UNABLE_TO_CHECK_GENERATOR);
943+
#endif
944+
945+
#ifdef DH_NOT_SUITABLE_GENERATOR
946+
NODE_DEFINE_CONSTANT(target, DH_NOT_SUITABLE_GENERATOR);
947+
#endif
948+
933949
#ifdef OPENSSL_NPN_NEGOTIATED
934950
#define NPN_ENABLED 1
935951
NODE_DEFINE_CONSTANT(target, NPN_ENABLED);

src/node_crypto.cc

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ using v8::Local;
8888
using v8::Null;
8989
using v8::Object;
9090
using v8::Persistent;
91+
using v8::PropertyAttribute;
92+
using v8::PropertyCallbackInfo;
9193
using v8::String;
9294
using v8::ThrowException;
9395
using v8::V8;
@@ -3158,6 +3160,9 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
31583160
void DiffieHellman::Initialize(Environment* env, Handle<Object> target) {
31593161
Local<FunctionTemplate> t = FunctionTemplate::New(New);
31603162

3163+
static enum PropertyAttribute attributes =
3164+
static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
3165+
31613166
t->InstanceTemplate()->SetInternalFieldCount(1);
31623167

31633168
NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys);
@@ -3169,6 +3174,13 @@ void DiffieHellman::Initialize(Environment* env, Handle<Object> target) {
31693174
NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey);
31703175
NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey);
31713176

3177+
t->InstanceTemplate()->SetAccessor(env->verify_error_string(),
3178+
DiffieHellman::VerifyErrorGetter,
3179+
NULL,
3180+
Handle<Value>(),
3181+
v8::DEFAULT,
3182+
attributes);
3183+
31723184
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"),
31733185
t->GetFunction());
31743186

@@ -3182,14 +3194,21 @@ void DiffieHellman::Initialize(Environment* env, Handle<Object> target) {
31823194
NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey);
31833195
NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey);
31843196

3197+
t2->InstanceTemplate()->SetAccessor(env->verify_error_string(),
3198+
DiffieHellman::VerifyErrorGetter,
3199+
NULL,
3200+
Handle<Value>(),
3201+
v8::DEFAULT,
3202+
attributes);
3203+
31853204
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
31863205
t2->GetFunction());
31873206
}
31883207

31893208

3190-
bool DiffieHellman::Init(int primeLength) {
3209+
bool DiffieHellman::Init(int primeLength, int g) {
31913210
dh = DH_new();
3192-
DH_generate_parameters_ex(dh, primeLength, DH_GENERATOR_2, 0);
3211+
DH_generate_parameters_ex(dh, primeLength, g, 0);
31933212
bool result = VerifyContext();
31943213
if (!result)
31953214
return false;
@@ -3198,11 +3217,11 @@ bool DiffieHellman::Init(int primeLength) {
31983217
}
31993218

32003219

3201-
bool DiffieHellman::Init(const char* p, int p_len) {
3220+
bool DiffieHellman::Init(const char* p, int p_len, int g) {
32023221
dh = DH_new();
32033222
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
32043223
dh->g = BN_new();
3205-
if (!BN_set_word(dh->g, 2))
3224+
if (!BN_set_word(dh->g, g))
32063225
return false;
32073226
bool result = VerifyContext();
32083227
if (!result)
@@ -3216,6 +3235,9 @@ bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
32163235
dh = DH_new();
32173236
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
32183237
dh->g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
3238+
bool result = VerifyContext();
3239+
if (!result)
3240+
return false;
32193241
initialised_ = true;
32203242
return true;
32213243
}
@@ -3232,17 +3254,21 @@ void DiffieHellman::DiffieHellmanGroup(
32323254
return ThrowError("No group name given");
32333255
}
32343256

3257+
bool initialized = false;
3258+
32353259
const String::Utf8Value group_name(args[0]);
32363260
for (unsigned int i = 0; i < ARRAY_SIZE(modp_groups); ++i) {
32373261
const modp_group* it = modp_groups + i;
32383262

32393263
if (strcasecmp(*group_name, it->name) != 0)
32403264
continue;
32413265

3242-
diffieHellman->Init(it->prime,
3243-
it->prime_size,
3244-
it->gen,
3245-
it->gen_size);
3266+
initialized = diffieHellman->Init(it->prime,
3267+
it->prime_size,
3268+
it->gen,
3269+
it->gen_size);
3270+
if (!initialized)
3271+
ThrowError("Initialization failed");
32463272
return;
32473273
}
32483274

@@ -3258,12 +3284,23 @@ void DiffieHellman::New(const FunctionCallbackInfo<Value>& args) {
32583284
new DiffieHellman(env, args.This());
32593285
bool initialized = false;
32603286

3261-
if (args.Length() > 0) {
3287+
if (args.Length() == 2) {
32623288
if (args[0]->IsInt32()) {
3263-
initialized = diffieHellman->Init(args[0]->Int32Value());
3289+
if (args[1]->IsInt32()) {
3290+
initialized = diffieHellman->Init(args[0]->Int32Value(),
3291+
args[1]->Int32Value());
3292+
}
32643293
} else {
3265-
initialized = diffieHellman->Init(Buffer::Data(args[0]),
3266-
Buffer::Length(args[0]));
3294+
if (args[1]->IsInt32()) {
3295+
initialized = diffieHellman->Init(Buffer::Data(args[0]),
3296+
Buffer::Length(args[0]),
3297+
args[1]->Int32Value());
3298+
} else {
3299+
initialized = diffieHellman->Init(Buffer::Data(args[0]),
3300+
Buffer::Length(args[0]),
3301+
Buffer::Data(args[1]),
3302+
Buffer::Length(args[1]));
3303+
}
32673304
}
32683305
}
32693306

@@ -3490,18 +3527,24 @@ void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
34903527
}
34913528

34923529

3530+
void DiffieHellman::VerifyErrorGetter(Local<String> property,
3531+
const PropertyCallbackInfo<Value>& args) {
3532+
HandleScope scope(args.GetIsolate());
3533+
3534+
DiffieHellman* diffieHellman = Unwrap<DiffieHellman>(args.This());
3535+
3536+
if (!diffieHellman->initialised_)
3537+
return ThrowError("Not initialized");
3538+
3539+
args.GetReturnValue().Set(diffieHellman->verifyError_);
3540+
}
3541+
3542+
34933543
bool DiffieHellman::VerifyContext() {
34943544
int codes;
34953545
if (!DH_check(dh, &codes))
34963546
return false;
3497-
if (codes & DH_CHECK_P_NOT_SAFE_PRIME)
3498-
return false;
3499-
if (codes & DH_CHECK_P_NOT_PRIME)
3500-
return false;
3501-
if (codes & DH_UNABLE_TO_CHECK_GENERATOR)
3502-
return false;
3503-
if (codes & DH_NOT_SUITABLE_GENERATOR)
3504-
return false;
3547+
verifyError_ = codes;
35053548
return true;
35063549
}
35073550

src/node_crypto.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,8 @@ class DiffieHellman : public BaseObject {
541541

542542
static void Initialize(Environment* env, v8::Handle<v8::Object> target);
543543

544-
bool Init(int primeLength);
545-
bool Init(const char* p, int p_len);
544+
bool Init(int primeLength, int g);
545+
bool Init(const char* p, int p_len, int g);
546546
bool Init(const char* p, int p_len, const char* g, int g_len);
547547

548548
protected:
@@ -557,10 +557,14 @@ class DiffieHellman : public BaseObject {
557557
static void ComputeSecret(const v8::FunctionCallbackInfo<v8::Value>& args);
558558
static void SetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
559559
static void SetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
560+
static void VerifyErrorGetter(
561+
v8::Local<v8::String> property,
562+
const v8::PropertyCallbackInfo<v8::Value>& args);
560563

561564
DiffieHellman(Environment* env, v8::Local<v8::Object> wrap)
562565
: BaseObject(env, wrap),
563566
initialised_(false),
567+
verifyError_(0),
564568
dh(NULL) {
565569
MakeWeak<DiffieHellman>(this);
566570
}
@@ -569,6 +573,7 @@ class DiffieHellman : public BaseObject {
569573
bool VerifyContext();
570574

571575
bool initialised_;
576+
int verifyError_;
572577
DH* dh;
573578
};
574579

test/simple/test-crypto-binary-default.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
var common = require('../common');
2727
var assert = require('assert');
28+
var constants = require('constants');
2829

2930
try {
3031
var crypto = require('crypto');
@@ -569,13 +570,12 @@ var secret3 = dh3.computeSecret(key2, 'hex', 'base64');
569570
assert.equal(secret1, secret3);
570571

571572
// https://github.com/joyent/node/issues/2338
572-
assert.throws(function() {
573-
var p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' +
574-
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' +
575-
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
576-
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
577-
crypto.createDiffieHellman(p, 'hex');
578-
});
573+
var p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' +
574+
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' +
575+
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
576+
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
577+
var d = crypto.createDiffieHellman(p, 'hex');
578+
assert.equal(d.verifyError, constants.DH_NOT_SUITABLE_GENERATOR);
579579

580580
// Test RSA key signing/verification
581581
var rsaSign = crypto.createSign('RSA-SHA1');

0 commit comments

Comments
 (0)