Created
February 7, 2011 21:55
-
-
Save ry/815320 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 1c1ed88320a5137c2aad0c9f01c76e7cc2093dac Mon Sep 17 00:00:00 2001 | |
From: =?UTF-8?q?H=C3=A5vard=20Stranden?= <havard.stranden@gmail.com> | |
Date: Wed, 19 Jan 2011 02:00:38 +0100 | |
Subject: [PATCH] Add bindings for Diffie-Hellman | |
--- | |
doc/api/crypto.markdown | 56 +++++ | |
lib/crypto.js | 13 ++ | |
src/node_crypto.cc | 480 ++++++++++++++++++++++++++++++++++++++++++++ | |
test/simple/test-crypto.js | 27 +++ | |
4 files changed, 576 insertions(+), 0 deletions(-) | |
diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown | |
index 9e83235..0c1a1bf 100644 | |
--- a/doc/api/crypto.markdown | |
+++ b/doc/api/crypto.markdown | |
@@ -128,3 +128,59 @@ the PEM encoded public key, and `signature`, which is the previously calculates | |
signature for the data, in the `signature_format` which can be `'binary'`, `'hex'` or `'base64'`. | |
Returns true or false depending on the validity of the signature for the data and public key. | |
+ | |
+### crypto.createDiffieHellman(prime_length) | |
+ | |
+Creates a Diffie-Hellman key exchange object and generates a prime of the | |
+given bit length. The generator used is `2`. | |
+ | |
+### crypto.createDiffieHellman(prime, encoding='binary') | |
+ | |
+Creates a Diffie-Hellman key exchange object using the supplied prime. The | |
+generator used is `2`. Encoding can be `'binary'`, `'hex'`, or `'base64'`. | |
+ | |
+### diffieHellman.generateKeys(encoding='binary') | |
+ | |
+Generates private and public Diffie-Hellman key values, and returns the | |
+public key in the specified encoding. This key should be transferred to the | |
+other party. Encoding can be `'binary'`, `'hex'`, or `'base64'`. | |
+ | |
+### diffieHellman.computeSecret(other_public_key, input_encoding='binary', output_encoding=input_encoding) | |
+ | |
+Computes the shared secret using `other_public_key` as the other party's | |
+public key and returns the computed shared secret. Supplied key is | |
+interpreted using specified `input_encoding`, and secret is encoded using | |
+specified `output_encoding`. Encodings can be `'binary'`, `'hex'`, or | |
+`'base64'`. If no output encoding is given, the input encoding is used as | |
+output encoding. | |
+ | |
+### diffieHellman.getPrime(encoding='binary') | |
+ | |
+Returns the Diffie-Hellman prime in the specified encoding, which can be | |
+`'binary'`, `'hex'`, or `'base64'`. | |
+ | |
+### diffieHellman.getGenerator(encoding='binary') | |
+ | |
+Returns the Diffie-Hellman prime in the specified encoding, which can be | |
+`'binary'`, `'hex'`, or `'base64'`. | |
+ | |
+### diffieHellman.getPublicKey(encoding='binary') | |
+ | |
+Returns the Diffie-Hellman public key in the specified encoding, which can | |
+be `'binary'`, `'hex'`, or `'base64'`. | |
+ | |
+### diffieHellman.getPrivateKey(encoding='binary') | |
+ | |
+Returns the Diffie-Hellman private key in the specified encoding, which can | |
+be `'binary'`, `'hex'`, or `'base64'`. | |
+ | |
+### diffieHellman.setPublicKey(public_key, encoding='binary') | |
+ | |
+Sets the Diffie-Hellman public key. Key encoding can be `'binary'`, `'hex'`, | |
+or `'base64'`. | |
+ | |
+### diffieHellman.setPrivateKey(public_key, encoding='binary') | |
+ | |
+Sets the Diffie-Hellman private key. Key encoding can be `'binary'`, | |
+`'hex'`, or `'base64'`. | |
+ | |
diff --git a/lib/crypto.js b/lib/crypto.js | |
index 2b6fc0e..c0cada9 100644 | |
--- a/lib/crypto.js | |
+++ b/lib/crypto.js | |
@@ -8,6 +8,7 @@ try { | |
var Decipher = binding.Decipher; | |
var Sign = binding.Sign; | |
var Verify = binding.Verify; | |
+ var DiffieHellman = binding.DiffieHellman; | |
var crypto = true; | |
} catch (e) { | |
@@ -104,3 +105,15 @@ exports.Verify = Verify; | |
exports.createVerify = function(algorithm) { | |
return (new Verify).init(algorithm); | |
}; | |
+ | |
+exports.DiffieHellman = DiffieHellman; | |
+exports.createDiffieHellman = function(size_or_key, enc) { | |
+ if (!size_or_key) { | |
+ return new DiffieHellman(); | |
+ } else if (!enc) { | |
+ return new DiffieHellman(size_or_key); | |
+ } else { | |
+ return new DiffieHellman(size_or_key, enc); | |
+ } | |
+ | |
+} | |
diff --git a/src/node_crypto.cc b/src/node_crypto.cc | |
index 4abdc5d..a94e4d4 100644 | |
--- a/src/node_crypto.cc | |
+++ b/src/node_crypto.cc | |
@@ -2710,7 +2710,486 @@ class Verify : public ObjectWrap { | |
}; | |
+class DiffieHellman : public ObjectWrap { | |
+ public: | |
+ static void Initialize (v8::Handle<v8::Object> target) { | |
+ HandleScope scope; | |
+ | |
+ Local<FunctionTemplate> t = FunctionTemplate::New(New); | |
+ | |
+ t->InstanceTemplate()->SetInternalFieldCount(1); | |
+ | |
+ NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "getPrime", GetPrime); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "getGenerator", GetGenerator); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "getPublicKey", GetPublicKey); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "getPrivateKey", GetPrivateKey); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey); | |
+ NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey); | |
+ | |
+ target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction()); | |
+ } | |
+ | |
+ bool Init(int primeLength) { | |
+ dh = DH_new(); | |
+ DH_generate_parameters_ex(dh, primeLength, DH_GENERATOR_2, 0); | |
+ bool result = VerifyContext(); | |
+ if (!result) return false; | |
+ initialised_ = true; | |
+ return true; | |
+ } | |
+ | |
+ bool Init(unsigned char* p, int p_len) { | |
+ dh = DH_new(); | |
+ dh->p = BN_bin2bn(p, p_len, 0); | |
+ dh->g = BN_new(); | |
+ if (!BN_set_word(dh->g, 2)) return false; | |
+ bool result = VerifyContext(); | |
+ if (!result) return false; | |
+ initialised_ = true; | |
+ return true; | |
+ } | |
+ | |
+ protected: | |
+ static Handle<Value> New (const Arguments& args) { | |
+ HandleScope scope; | |
+ | |
+ DiffieHellman* diffieHellman = new DiffieHellman(); | |
+ bool initialized = false; | |
+ | |
+ if (args.Length() > 0) { | |
+ if (args[0]->IsInt32()) { | |
+ diffieHellman->Init(args[0]->Int32Value()); | |
+ initialized = true; | |
+ } else { | |
+ if (args[0]->IsString()) { | |
+ char* buf; | |
+ int len; | |
+ if (args.Length() > 1 && args[1]->IsString()) { | |
+ len = DecodeWithEncoding(args[0], args[1], &buf); | |
+ } else { | |
+ len = DecodeBinary(args[0], &buf); | |
+ } | |
+ | |
+ if (len == -1) { | |
+ delete[] buf; | |
+ return ThrowException(Exception::Error(String::New("Invalid argument"))); | |
+ } else { | |
+ diffieHellman->Init(reinterpret_cast<unsigned char*>(buf), len); | |
+ delete[] buf; | |
+ initialized = true; | |
+ } | |
+ } else if (Buffer::HasInstance(args[0])) { | |
+ Local<Object> buffer = args[0]->ToObject(); | |
+ diffieHellman->Init( | |
+ reinterpret_cast<unsigned char*>(Buffer::Data(buffer)), | |
+ Buffer::Length(buffer)); | |
+ initialized = true; | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (!initialized) { | |
+ return ThrowException(Exception::Error(String::New("Initialization failed"))); | |
+ } | |
+ | |
+ diffieHellman->Wrap(args.This()); | |
+ | |
+ return args.This(); | |
+ } | |
+ | |
+ static Handle<Value> GenerateKeys (const Arguments& args) { | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ HandleScope scope; | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ if (!DH_generate_key(diffieHellman->dh)) { | |
+ return ThrowException(Exception::Error(String::New("Key generation failed"))); | |
+ } | |
+ | |
+ Local<Value> outString; | |
+ | |
+ int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); | |
+ char* data = new char[dataSize]; | |
+ BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data)); | |
+ | |
+ if (args.Length() > 0 && args[0]->IsString()) { | |
+ outString = EncodeWithEncoding(args[0], data, dataSize); | |
+ } else { | |
+ outString = Encode(data, dataSize, BINARY); | |
+ } | |
+ delete[] data; | |
+ | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ static Handle<Value> GetPrime (const Arguments& args) { | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ HandleScope scope; | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ int dataSize = BN_num_bytes(diffieHellman->dh->p); | |
+ char* data = new char[dataSize]; | |
+ BN_bn2bin(diffieHellman->dh->p, reinterpret_cast<unsigned char*>(data)); | |
+ | |
+ Local<Value> outString; | |
+ | |
+ if (args.Length() > 0 && args[0]->IsString()) { | |
+ outString = EncodeWithEncoding(args[0], data, dataSize); | |
+ } else { | |
+ outString = Encode(data, dataSize, BINARY); | |
+ } | |
+ | |
+ delete[] data; | |
+ | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ static Handle<Value> GetGenerator (const Arguments& args) { | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ HandleScope scope; | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ int dataSize = BN_num_bytes(diffieHellman->dh->g); | |
+ char* data = new char[dataSize]; | |
+ BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data)); | |
+ | |
+ Local<Value> outString; | |
+ | |
+ if (args.Length() > 0 && args[0]->IsString()) { | |
+ outString = EncodeWithEncoding(args[0], data, dataSize); | |
+ } else { | |
+ outString = Encode(data, dataSize, BINARY); | |
+ } | |
+ | |
+ delete[] data; | |
+ | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ static Handle<Value> GetPublicKey (const Arguments& args) { | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ HandleScope scope; | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ if (diffieHellman->dh->pub_key == NULL) { | |
+ return ThrowException(Exception::Error(String::New("No public key - did you forget to generate one?"))); | |
+ } | |
+ | |
+ int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); | |
+ char* data = new char[dataSize]; | |
+ BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data)); | |
+ | |
+ Local<Value> outString; | |
+ | |
+ if (args.Length() > 0 && args[0]->IsString()) { | |
+ outString = EncodeWithEncoding(args[0], data, dataSize); | |
+ } else { | |
+ outString = Encode(data, dataSize, BINARY); | |
+ } | |
+ | |
+ delete[] data; | |
+ | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ static Handle<Value> GetPrivateKey (const Arguments& args) { | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ HandleScope scope; | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ if (diffieHellman->dh->priv_key == NULL) { | |
+ return ThrowException(Exception::Error(String::New("No private key - did you forget to generate one?"))); | |
+ } | |
+ int dataSize = BN_num_bytes(diffieHellman->dh->priv_key); | |
+ char* data = new char[dataSize]; | |
+ BN_bn2bin(diffieHellman->dh->priv_key, reinterpret_cast<unsigned char*>(data)); | |
+ | |
+ Local<Value> outString; | |
+ | |
+ if (args.Length() > 0 && args[0]->IsString()) { | |
+ outString = EncodeWithEncoding(args[0], data, dataSize); | |
+ } else { | |
+ outString = Encode(data, dataSize, BINARY); | |
+ } | |
+ | |
+ delete[] data; | |
+ | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ static Handle<Value> ComputeSecret (const Arguments& args) { | |
+ HandleScope scope; | |
+ | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ BIGNUM* key = 0; | |
+ | |
+ if (args.Length() == 0) { | |
+ return ThrowException(Exception::Error(String::New("First argument must be other party's public key"))); | |
+ } else { | |
+ if (args[0]->IsString()) { | |
+ char* buf; | |
+ int len; | |
+ if (args.Length() > 1) { | |
+ len = DecodeWithEncoding(args[0], args[1], &buf); | |
+ } else { | |
+ len = DecodeBinary(args[0], &buf); | |
+ } | |
+ if (len == -1) { | |
+ delete[] buf; | |
+ return ThrowException(Exception::Error(String::New("Invalid argument"))); | |
+ } | |
+ key = BN_bin2bn(reinterpret_cast<unsigned char*>(buf), len, 0); | |
+ delete[] buf; | |
+ } else if (Buffer::HasInstance(args[0])) { | |
+ Local<Object> buffer = args[0]->ToObject(); | |
+ key = BN_bin2bn( | |
+ reinterpret_cast<unsigned char*>(Buffer::Data(buffer)), | |
+ Buffer::Length(buffer), 0); | |
+ } else { | |
+ return ThrowException(Exception::Error(String::New("First argument must be other party's public key"))); | |
+ } | |
+ } | |
+ | |
+ int dataSize = DH_size(diffieHellman->dh); | |
+ char* data = new char[dataSize]; | |
+ | |
+ int size = DH_compute_key(reinterpret_cast<unsigned char*>(data), | |
+ key, diffieHellman->dh); | |
+ BN_free(key); | |
+ | |
+ Local<Value> outString; | |
+ | |
+ if (size == -1) { | |
+ int checkResult; | |
+ if (!DH_check_pub_key(diffieHellman->dh, key, &checkResult)) { | |
+ return ThrowException(Exception::Error(String::New("Invalid key"))); | |
+ } else if (checkResult) { | |
+ if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) { | |
+ return ThrowException(Exception::Error(String::New("Supplied key is too small"))); | |
+ } else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) { | |
+ return ThrowException(Exception::Error(String::New("Supplied key is too large"))); | |
+ } else { | |
+ return ThrowException(Exception::Error(String::New("Invalid key"))); | |
+ } | |
+ } else { | |
+ return ThrowException(Exception::Error(String::New("Invalid key"))); | |
+ } | |
+ } else { | |
+ if (args.Length() > 2 && args[2]->IsString()) { | |
+ outString = EncodeWithEncoding(args[2], data, dataSize); | |
+ } else if (args.Length() > 1 && args[1]->IsString()) { | |
+ outString = EncodeWithEncoding(args[1], data, dataSize); | |
+ } else { | |
+ outString = Encode(data, dataSize, BINARY); | |
+ } | |
+ } | |
+ | |
+ delete[] data; | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ static Handle<Value> SetPublicKey(const Arguments& args) { | |
+ HandleScope scope; | |
+ | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ if (args.Length() == 0) { | |
+ return ThrowException(Exception::Error(String::New("First argument must be public key"))); | |
+ } else { | |
+ if (args[0]->IsString()) { | |
+ char* buf; | |
+ int len; | |
+ if (args.Length() > 1) { | |
+ len = DecodeWithEncoding(args[0], args[1], &buf); | |
+ } else { | |
+ len = DecodeBinary(args[0], &buf); | |
+ } | |
+ if (len == -1) { | |
+ delete[] buf; | |
+ return ThrowException(Exception::Error(String::New("Invalid argument"))); | |
+ } | |
+ diffieHellman->dh->pub_key = | |
+ BN_bin2bn(reinterpret_cast<unsigned char*>(buf), len, 0); | |
+ delete[] buf; | |
+ } else if (Buffer::HasInstance(args[0])) { | |
+ Local<Object> buffer = args[0]->ToObject(); | |
+ diffieHellman->dh->pub_key = | |
+ BN_bin2bn( | |
+ reinterpret_cast<unsigned char*>(Buffer::Data(buffer)), | |
+ Buffer::Length(buffer), 0); | |
+ } else { | |
+ return ThrowException(Exception::Error(String::New("First argument must be public key"))); | |
+ } | |
+ } | |
+ | |
+ return args.This(); | |
+ } | |
+ | |
+ static Handle<Value> SetPrivateKey(const Arguments& args) { | |
+ HandleScope scope; | |
+ | |
+ DiffieHellman* diffieHellman = ObjectWrap::Unwrap<DiffieHellman>(args.This()); | |
+ | |
+ if (!diffieHellman->initialised_) { | |
+ return ThrowException(Exception::Error(String::New("Not initialized"))); | |
+ } | |
+ | |
+ if (args.Length() == 0) { | |
+ return ThrowException(Exception::Error(String::New("First argument must be private key"))); | |
+ } else { | |
+ if (args[0]->IsString()) { | |
+ char* buf; | |
+ int len; | |
+ if (args.Length() > 1) { | |
+ len = DecodeWithEncoding(args[0], args[1], &buf); | |
+ } else { | |
+ len = DecodeBinary(args[0], &buf); | |
+ } | |
+ if (len == -1) { | |
+ delete[] buf; | |
+ return ThrowException(Exception::Error(String::New("Invalid argument"))); | |
+ } | |
+ diffieHellman->dh->priv_key = | |
+ BN_bin2bn(reinterpret_cast<unsigned char*>(buf), len, 0); | |
+ delete[] buf; | |
+ } else if (Buffer::HasInstance(args[0])) { | |
+ Local<Object> buffer = args[0]->ToObject(); | |
+ diffieHellman->dh->priv_key = | |
+ BN_bin2bn( | |
+ reinterpret_cast<unsigned char*>(Buffer::Data(buffer)), | |
+ Buffer::Length(buffer), 0); | |
+ } else { | |
+ return ThrowException(Exception::Error(String::New("First argument must be private key"))); | |
+ } | |
+ } | |
+ | |
+ return args.This(); | |
+ } | |
+ | |
+ DiffieHellman () : ObjectWrap () { | |
+ initialised_ = false; | |
+ dh = NULL; | |
+ } | |
+ | |
+ ~DiffieHellman () { | |
+ if (dh != NULL) { | |
+ DH_free(dh); | |
+ } | |
+ } | |
+ | |
+ private: | |
+ bool VerifyContext() { | |
+ int codes; | |
+ if (!DH_check(dh, &codes)) return false; | |
+ if (codes & DH_CHECK_P_NOT_SAFE_PRIME) return false; | |
+ if (codes & DH_CHECK_P_NOT_PRIME) return false; | |
+ if (codes & DH_UNABLE_TO_CHECK_GENERATOR) return false; | |
+ if (codes & DH_NOT_SUITABLE_GENERATOR) return false; | |
+ return true; | |
+ } | |
+ | |
+ static int DecodeBinary(Handle<Value> str, char** buf) { | |
+ int len = DecodeBytes(str); | |
+ *buf = new char[len]; | |
+ int written = DecodeWrite(*buf, len, str, BINARY); | |
+ if(written != len) { | |
+ return -1; | |
+ } | |
+ return len; | |
+ } | |
+ | |
+ static int DecodeWithEncoding(Handle<Value> str, Handle<Value> enc, char** buf) { | |
+ int len = DecodeBinary(str, buf); | |
+ if (len == -1) { | |
+ return len; | |
+ } | |
+ String::Utf8Value encoding(enc->ToString()); | |
+ char* retbuf = 0; | |
+ int retlen; | |
+ | |
+ if (strcasecmp(*encoding, "hex") == 0) { | |
+ HexDecode((unsigned char*)*buf, len, &retbuf, &retlen); | |
+ | |
+ } else if (strcasecmp(*encoding, "base64") == 0) { | |
+ unbase64((unsigned char*)*buf, len, &retbuf, &retlen); | |
+ | |
+ } else if (strcasecmp(*encoding, "binary") == 0) { | |
+ // Binary - do nothing | |
+ } else { | |
+ fprintf(stderr, "node-crypto : Diffie-Hellman parameter encoding " | |
+ "can be binary, hex or base64\n"); | |
+ } | |
+ | |
+ if (retbuf != 0) { | |
+ delete [] *buf; | |
+ *buf = retbuf; | |
+ len = retlen; | |
+ } | |
+ | |
+ return len; | |
+ } | |
+ | |
+ static Local<Value> EncodeWithEncoding(Handle<Value> enc, char* buf, int len) { | |
+ HandleScope scope; | |
+ | |
+ Local<Value> outString; | |
+ String::Utf8Value encoding(enc->ToString()); | |
+ char* retbuf; | |
+ int retlen; | |
+ if (strcasecmp(*encoding, "hex") == 0) { | |
+ // Hex encoding | |
+ HexEncode(reinterpret_cast<unsigned char*>(buf), len, &retbuf, &retlen); | |
+ outString = Encode(retbuf, retlen, BINARY); | |
+ delete [] retbuf; | |
+ } else if (strcasecmp(*encoding, "base64") == 0) { | |
+ base64(reinterpret_cast<unsigned char*>(buf), len, &retbuf, &retlen); | |
+ outString = Encode(retbuf, retlen, BINARY); | |
+ delete [] retbuf; | |
+ } else if (strcasecmp(*encoding, "binary") == 0) { | |
+ outString = Encode(buf, len, BINARY); | |
+ } else { | |
+ fprintf(stderr, "node-crypto : Diffie-Hellman parameter encoding " | |
+ "can be binary, hex or base64\n"); | |
+ } | |
+ | |
+ return scope.Close(outString); | |
+ } | |
+ | |
+ bool initialised_; | |
+ DH* dh; | |
+}; | |
@@ -2727,6 +3206,7 @@ void InitCrypto(Handle<Object> target) { | |
Connection::Initialize(target); | |
Cipher::Initialize(target); | |
Decipher::Initialize(target); | |
+ DiffieHellman::Initialize(target); | |
Hmac::Initialize(target); | |
Hash::Initialize(target); | |
Sign::Initialize(target); | |
diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js | |
index 6083cac..c9e7724 100644 | |
--- a/test/simple/test-crypto.js | |
+++ b/test/simple/test-crypto.js | |
@@ -119,3 +119,30 @@ txt += decipher.final('utf8'); | |
assert.equal(txt, plaintext, 'encryption and decryption with key and iv'); | |
+// Test Diffie-Hellman with two parties sharing a secret, | |
+// using various encodings as we go along | |
+var dh1 = crypto.createDiffieHellman(256); | |
+var p1 = dh1.getPrime('base64'); | |
+var dh2 = crypto.createDiffieHellman(p1, 'base64'); | |
+var key1 = dh1.generateKeys(); | |
+var key2 = dh2.generateKeys('hex'); | |
+var secret1 = dh1.computeSecret(key2, 'hex', 'base64'); | |
+var secret2 = dh2.computeSecret(key1, 'binary', 'base64'); | |
+ | |
+assert.equal(secret1, secret2); | |
+ | |
+// Create "another dh1" using generated keys from dh1, | |
+// and compute secret again | |
+var dh3 = crypto.createDiffieHellman(p1, 'base64'); | |
+var privkey1 = dh1.getPrivateKey(); | |
+dh3.setPublicKey(key1); | |
+dh3.setPrivateKey(privkey1); | |
+ | |
+assert.equal(dh1.getPrime(), dh3.getPrime()); | |
+assert.equal(dh1.getGenerator(), dh3.getGenerator()); | |
+assert.equal(dh1.getPublicKey(), dh3.getPublicKey()); | |
+assert.equal(dh1.getPrivateKey(), dh3.getPrivateKey()); | |
+ | |
+var secret3 = dh3.computeSecret(key2, 'hex', 'base64'); | |
+ | |
+assert.equal(secret1, secret3); | |
-- | |
1.7.3.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment