From 6489c900fb79b7b04a7bf0770ec8ace7a02c5d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Stranden?= Date: Wed, 19 Jan 2011 02:00:38 +0100 Subject: [PATCH 1/4] Add Diffie-Hellman support to crypto module --- AUTHORS | 2 +- doc/api/crypto.markdown | 20 +++++ lib/crypto.js | 10 +++ src/node_crypto.cc | 181 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 0cddc38b4a0..94bae6e2115 100644 --- a/AUTHORS +++ b/AUTHORS @@ -152,4 +152,4 @@ Theo Schlossnagle Kai Chen Daniel C <333222@gmail.com> Mihai Călin Bazon - +Håvard Stranden diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index 9e8323541a1..cd4cf4e2fd7 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -128,3 +128,23 @@ 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() + +Creates a Diffie-Hellman key exchange object using the default Diffie-Hellman primes from the OpenID specification. + +### 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(p, g) + +Creates a Diffie-Hellman key exchange object using the supplied prime and generator, which should be Base64-encoded strings. + +### diffieHellman.generateKey() + +Generates private and public Diffie-Hellman key values, and returns the public key in Base64-encoding. This key should be transferred to the other party. + +### diffieHellman.computeSecret(other_public_key) + +Computes the shared secret using `other_public_key` as the other party's public key. The other party's public key should be a Base64-encoded string. diff --git a/lib/crypto.js b/lib/crypto.js index f7f6437533f..6095ed22a90 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,12 @@ exports.Verify = Verify; exports.createVerify = function(algorithm) { return (new Verify).init(algorithm); }; + +exports.DiffieHellman = DiffieHellman; +exports.createDiffieHellman = function(size) { + if(!size) + { + return new DiffieHellman(); + } + return new DiffieHellman(size); +} diff --git a/src/node_crypto.cc b/src/node_crypto.cc index ae9e32d2c83..3fc48584cb1 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -16,6 +16,9 @@ # define OPENSSL_CONST #endif +#define DIFFIE_HELLMAN_DEFAULT_P "ANz5OguIOXLsDhmYmsWizjEOHTdxfo2Vcbt2I3MYZuYe91ouJ4mLBX+YkcLiemOcPym2CBRYHNOyyjmG0mg3BVd9RcLn5S3IHHoXGHblzqdLFEi/368Ygo79JRnxTkXjgmY0rxlJ5bU1zIKaSDuKdiI+XUkKJX8Fvf8W8vsixYOr" +#define DIFFIE_HELLMAN_DEFAULT_G "Ag==" + namespace node { namespace crypto { @@ -2654,7 +2657,184 @@ class Verify : public ObjectWrap { }; +class DiffieHellman : public ObjectWrap { + public: + static void Initialize (v8::Handle target) { + HandleScope scope; + + Local t = FunctionTemplate::New(New); + + t->InstanceTemplate()->SetInternalFieldCount(1); + + NODE_SET_PROTOTYPE_METHOD(t, "generateKey", GenerateKey); + NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret); + + target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction()); + } + + bool Init(int primeLength) { + dh = DH_generate_parameters(primeLength, 2, NULL, NULL); + int codes; + if (!DH_check(dh, &codes)) return false; + initialised_ = true; + return true; + } + + bool Init(unsigned char* p, int p_len, unsigned char* g, int g_len) { + dh = DH_new(); + dh->p = DiffieHellman::StringToBigNum(p, p_len); + dh->g = DiffieHellman::StringToBigNum(g, g_len); + int codes; + if (!DH_check(dh, &codes)) return false; + initialised_ = true; + return true; + } + + protected: + static BIGNUM* StringToBigNum(unsigned char* value, int length) + { + char* binaryKey; int binaryKeyLength; + unbase64(value, length, &binaryKey, &binaryKeyLength); + + BIGNUM* bignum = BN_bin2bn(reinterpret_cast(binaryKey), + binaryKeyLength, NULL); + + return bignum; + } + + static Handle New (const Arguments& args) { + HandleScope scope; + + DiffieHellman* diffieHellman = new DiffieHellman(); + bool initialized = false; + + if (args.Length() > 0) { + if (args[0]->IsInt32()) { + int primeLength = args[0]->Int32Value(); + initialized = diffieHellman->Init(primeLength); + } + else if (args.Length() > 1 && args[0]->IsString() && args[1]->IsString()) { + String::Utf8Value p(args[0]->ToString()); + String::Utf8Value g(args[0]->ToString()); + + initialized = diffieHellman->Init(reinterpret_cast(*p), + strlen(*p), + reinterpret_cast(*g), + strlen(*g)); + } + else { + if (args.Length() == 1) { + ThrowException(Exception::Error(String::New("Invalid argument"))); + } + else { + ThrowException(Exception::Error(String::New("Invalid arguments"))); + } + } + } + else + { + String::Utf8Value p(String::New(DIFFIE_HELLMAN_DEFAULT_P)); + String::Utf8Value g(String::New(DIFFIE_HELLMAN_DEFAULT_G)); + initialized = diffieHellman->Init(reinterpret_cast(*p), + strlen(*p), + reinterpret_cast(*g), + strlen(*g)); + } + if (!initialized) { + ThrowException(Exception::Error(String::New("Initialization failed"))); + } + diffieHellman->Wrap(args.This()); + + return args.This(); + } + static Handle GenerateKey (const Arguments& args) { + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + + HandleScope scope; + + if (!diffieHellman->initialised_) { + ThrowException(Exception::Error(String::New("Not initialized"))); + } + + if (!DH_generate_key(diffieHellman->dh)) { + ThrowException(Exception::Error(String::New("Key generation failed"))); + } + + Local outString; + + int binaryKeySize = BN_num_bytes(diffieHellman->dh->pub_key); + char* binaryKey = new char[binaryKeySize]; + + char* base64data; int base64length; + base64(reinterpret_cast(binaryKey), binaryKeySize, + &base64data, &base64length); + + outString = Encode(base64data, base64length, BINARY); + + return scope.Close(outString); + } + + static Handle ComputeSecret (const Arguments& args) { + HandleScope scope; + + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + + if (!diffieHellman->initialised_) { + ThrowException(Exception::Error(String::New("Not initialized"))); + } + + if (args.Length() == 0) { + ThrowException(Exception::Error(String::New("First argument must be other party's public key"))); + } + ssize_t argLength = DecodeBytes(args[0], BINARY); + char* argBuffer = new char[argLength]; + ssize_t written = DecodeWrite(argBuffer, argLength, args[0], BINARY); + assert(written == argLength); + + BIGNUM* key = DiffieHellman::StringToBigNum( + reinterpret_cast(argBuffer), + argLength); + + int dataSize = DH_size(diffieHellman->dh); + unsigned char* data = new unsigned char[dataSize]; + + int size = DH_compute_key(data, key, diffieHellman->dh); + + BN_free(key); + + if (size == -1) { + delete[] data; + ThrowException(Exception::Error(String::New("Could not compute shared key"))); + } + + Local outString; + + char* base64data; int base64length; + base64(data, dataSize, &base64data, &base64length); + + outString = Encode(base64data, base64length, BINARY); + + delete[] data; + + return scope.Close(outString); + } + + DiffieHellman () : ObjectWrap () { + initialised_ = false; + dh = NULL; + } + + ~DiffieHellman () { + if (dh != NULL) { + DH_free(dh); + } + } + + private: + bool initialised_; + DH* dh; +}; @@ -2671,6 +2851,7 @@ void InitCrypto(Handle target) { Connection::Initialize(target); Cipher::Initialize(target); Decipher::Initialize(target); + DiffieHellman::Initialize(target); Hmac::Initialize(target); Hash::Initialize(target); Sign::Initialize(target); From 4ad172a1742972fe09e6d6947ee067ace42665d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Stranden?= Date: Mon, 7 Feb 2011 01:45:20 +0100 Subject: [PATCH 2/4] Diffie-Hellman: Added test, fixed bugs, added encoding/decoding of parameters similar to other crypto functions --- lib/crypto.js | 11 +- src/node_crypto.cc | 343 ++++++++++++++++++++++++++++--------- test/simple/test-crypto.js | 9 + 3 files changed, 281 insertions(+), 82 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index 6095ed22a90..e5a28dd10d5 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -107,10 +107,13 @@ exports.createVerify = function(algorithm) { }; exports.DiffieHellman = DiffieHellman; -exports.createDiffieHellman = function(size) { - if(!size) - { +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); } - return new DiffieHellman(size); + } diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 3fc48584cb1..f4f9519a157 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2668,40 +2668,34 @@ class DiffieHellman : public ObjectWrap { NODE_SET_PROTOTYPE_METHOD(t, "generateKey", GenerateKey); 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, "getKey", GetKey); target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction()); } bool Init(int primeLength) { - dh = DH_generate_parameters(primeLength, 2, NULL, NULL); - int codes; - if (!DH_check(dh, &codes)) return false; + 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, unsigned char* g, int g_len) { + bool Init(unsigned char* p, int p_len) { dh = DH_new(); - dh->p = DiffieHellman::StringToBigNum(p, p_len); - dh->g = DiffieHellman::StringToBigNum(g, g_len); - int codes; - if (!DH_check(dh, &codes)) return false; + 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 BIGNUM* StringToBigNum(unsigned char* value, int length) - { - char* binaryKey; int binaryKeyLength; - unbase64(value, length, &binaryKey, &binaryKeyLength); - - BIGNUM* bignum = BN_bin2bn(reinterpret_cast(binaryKey), - binaryKeyLength, NULL); - - return bignum; - } - static Handle New (const Arguments& args) { HandleScope scope; @@ -2710,39 +2704,40 @@ class DiffieHellman : public ObjectWrap { if (args.Length() > 0) { if (args[0]->IsInt32()) { - int primeLength = args[0]->Int32Value(); - initialized = diffieHellman->Init(primeLength); - } - else if (args.Length() > 1 && args[0]->IsString() && args[1]->IsString()) { - String::Utf8Value p(args[0]->ToString()); - String::Utf8Value g(args[0]->ToString()); - - initialized = diffieHellman->Init(reinterpret_cast(*p), - strlen(*p), - reinterpret_cast(*g), - strlen(*g)); - } - else { - if (args.Length() == 1) { - ThrowException(Exception::Error(String::New("Invalid argument"))); - } - else { - ThrowException(Exception::Error(String::New("Invalid arguments"))); + 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(buf), len); + delete[] buf; + initialized = true; + } + } else if (Buffer::HasInstance(args[0])) { + Local buffer = args[0]->ToObject(); + diffieHellman->Init( + reinterpret_cast(Buffer::Data(buffer)), + Buffer::Length(buffer)); + initialized = true; } } } - else - { - String::Utf8Value p(String::New(DIFFIE_HELLMAN_DEFAULT_P)); - String::Utf8Value g(String::New(DIFFIE_HELLMAN_DEFAULT_G)); - initialized = diffieHellman->Init(reinterpret_cast(*p), - strlen(*p), - reinterpret_cast(*g), - strlen(*g)); - } + if (!initialized) { - ThrowException(Exception::Error(String::New("Initialization failed"))); + return ThrowException(Exception::Error(String::New("Initialization failed"))); } + diffieHellman->Wrap(args.This()); return args.This(); @@ -2754,72 +2749,187 @@ class DiffieHellman : public ObjectWrap { HandleScope scope; if (!diffieHellman->initialised_) { - ThrowException(Exception::Error(String::New("Not initialized"))); + return ThrowException(Exception::Error(String::New("Not initialized"))); } if (!DH_generate_key(diffieHellman->dh)) { - ThrowException(Exception::Error(String::New("Key generation failed"))); + return ThrowException(Exception::Error(String::New("Key generation failed"))); } Local outString; - int binaryKeySize = BN_num_bytes(diffieHellman->dh->pub_key); - char* binaryKey = new char[binaryKeySize]; + int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast(data)); - char* base64data; int base64length; - base64(reinterpret_cast(binaryKey), binaryKeySize, - &base64data, &base64length); - - outString = Encode(base64data, base64length, BINARY); + 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 ComputeSecret (const Arguments& args) { + static Handle GetPrime (const Arguments& args) { + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(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(data)); + + Local 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 GetGenerator (const Arguments& args) { DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + HandleScope scope; + if (!diffieHellman->initialised_) { - ThrowException(Exception::Error(String::New("Not initialized"))); + return ThrowException(Exception::Error(String::New("Not initialized"))); } - if (args.Length() == 0) { - ThrowException(Exception::Error(String::New("First argument must be other party's public key"))); + int dataSize = BN_num_bytes(diffieHellman->dh->g); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->g, reinterpret_cast(data)); + + Local outString; + + if (args.Length() > 0 && args[0]->IsString()) { + outString = EncodeWithEncoding(args[0], data, dataSize); + } else { + outString = Encode(data, dataSize, BINARY); } - ssize_t argLength = DecodeBytes(args[0], BINARY); - char* argBuffer = new char[argLength]; - ssize_t written = DecodeWrite(argBuffer, argLength, args[0], BINARY); - assert(written == argLength); - BIGNUM* key = DiffieHellman::StringToBigNum( - reinterpret_cast(argBuffer), - argLength); + delete[] data; - int dataSize = DH_size(diffieHellman->dh); - unsigned char* data = new unsigned char[dataSize]; + return scope.Close(outString); + } - int size = DH_compute_key(data, key, diffieHellman->dh); + static Handle GetKey (const Arguments& args) { + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); - BN_free(key); + HandleScope scope; - if (size == -1) { - delete[] data; - ThrowException(Exception::Error(String::New("Could not compute shared key"))); + if (!diffieHellman->initialised_) { + return ThrowException(Exception::Error(String::New("Not initialized"))); } - Local outString; + if (diffieHellman->dh->pub_key == NULL) { + return ThrowException(Exception::Error(String::New("No public key - did you forget to generate one?"))); + } - char* base64data; int base64length; - base64(data, dataSize, &base64data, &base64length); + int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast(data)); - outString = Encode(base64data, base64length, BINARY); + Local 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 ComputeSecret (const Arguments& args) { + HandleScope scope; + + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(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(buf), len, 0); + delete[] buf; + } else if (Buffer::HasInstance(args[0])) { + Local buffer = args[0]->ToObject(); + key = BN_bin2bn( + reinterpret_cast(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(data), + key, diffieHellman->dh); + BN_free(key); + + Local 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[2], data, dataSize); + } else { + outString = Encode(data, dataSize, BINARY); + } + } + + delete[] data; + return scope.Close(outString); + } + DiffieHellman () : ObjectWrap () { initialised_ = false; dh = NULL; @@ -2832,6 +2942,83 @@ class DiffieHellman : public ObjectWrap { } 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 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 str, Handle 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 EncodeWithEncoding(Handle enc, char* buf, int len) { + HandleScope scope; + + Local outString; + String::Utf8Value encoding(enc->ToString()); + char* retbuf; + int retlen; + if (strcasecmp(*encoding, "hex") == 0) { + // Hex encoding + HexEncode(reinterpret_cast(buf), len, &retbuf, &retlen); + outString = Encode(retbuf, retlen, BINARY); + delete [] retbuf; + } else if (strcasecmp(*encoding, "base64") == 0) { + base64(reinterpret_cast(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; }; diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index 6083cac64f7..d6c1039ab3e 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -119,3 +119,12 @@ txt += decipher.final('utf8'); assert.equal(txt, plaintext, 'encryption and decryption with key and iv'); +var dh1 = crypto.createDiffieHellman(256); +var p1 = dh1.getPrime('base64'); +var dh2 = crypto.createDiffieHellman(p1, 'base64'); +var key1 = dh1.generateKey(); +var key2 = dh2.generateKey('hex'); +var secret1 = dh1.computeSecret(key2, 'hex', 'base64'); +var secret2 = dh2.computeSecret(key1, 'binary', 'base64'); + +assert.equal(secret1, secret2); From cd4613ab690aa9e32a3ac3006947df29503dfa50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Stranden?= Date: Mon, 7 Feb 2011 02:46:04 +0100 Subject: [PATCH 3/4] Diffie-Hellman: Added set/get public/private key for API completeness, added tests, updated documentation --- doc/api/crypto.markdown | 41 +++++++++--- src/node_crypto.cc | 128 ++++++++++++++++++++++++++++++++++--- test/simple/test-crypto.js | 22 ++++++- 3 files changed, 171 insertions(+), 20 deletions(-) diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index cd4cf4e2fd7..8345a1576e9 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -129,22 +129,43 @@ signature for the data, in the `signature_format` which can be `'binary'`, `'hex Returns true or false depending on the validity of the signature for the data and public key. -### crypto.createDiffieHellman() - -Creates a Diffie-Hellman key exchange object using the default Diffie-Hellman primes from the OpenID specification. - ### 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(p, g) +### 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'`. -Creates a Diffie-Hellman key exchange object using the supplied prime and generator, which should be Base64-encoded strings. +### diffieHellman.setPublicKey(public_key, encoding='binary') -### diffieHellman.generateKey() +Sets the Diffie-Hellman public key. Key encoding can be `'binary'`, `'hex'`, or `'base64'`. -Generates private and public Diffie-Hellman key values, and returns the public key in Base64-encoding. This key should be transferred to the other party. +### diffieHellman.setPrivateKey(public_key, encoding='binary') -### diffieHellman.computeSecret(other_public_key) +Sets the Diffie-Hellman private key. Key encoding can be `'binary'`, `'hex'`, or `'base64'`. -Computes the shared secret using `other_public_key` as the other party's public key. The other party's public key should be a Base64-encoded string. diff --git a/src/node_crypto.cc b/src/node_crypto.cc index f4f9519a157..bfa02a92c9c 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -16,9 +16,6 @@ # define OPENSSL_CONST #endif -#define DIFFIE_HELLMAN_DEFAULT_P "ANz5OguIOXLsDhmYmsWizjEOHTdxfo2Vcbt2I3MYZuYe91ouJ4mLBX+YkcLiemOcPym2CBRYHNOyyjmG0mg3BVd9RcLn5S3IHHoXGHblzqdLFEi/368Ygo79JRnxTkXjgmY0rxlJ5bU1zIKaSDuKdiI+XUkKJX8Fvf8W8vsixYOr" -#define DIFFIE_HELLMAN_DEFAULT_G "Ag==" - namespace node { namespace crypto { @@ -2666,11 +2663,14 @@ class DiffieHellman : public ObjectWrap { t->InstanceTemplate()->SetInternalFieldCount(1); - NODE_SET_PROTOTYPE_METHOD(t, "generateKey", GenerateKey); + 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, "getKey", GetKey); + 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()); } @@ -2743,7 +2743,7 @@ class DiffieHellman : public ObjectWrap { return args.This(); } - static Handle GenerateKey (const Arguments& args) { + static Handle GenerateKeys (const Arguments& args) { DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); HandleScope scope; @@ -2824,7 +2824,7 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } - static Handle GetKey (const Arguments& args) { + static Handle GetPublicKey (const Arguments& args) { DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); HandleScope scope; @@ -2854,6 +2854,36 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } + static Handle GetPrivateKey (const Arguments& args) { + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(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(data)); + + Local 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 ComputeSecret (const Arguments& args) { HandleScope scope; @@ -2920,7 +2950,7 @@ class DiffieHellman : public ObjectWrap { if (args.Length() > 2 && args[2]->IsString()) { outString = EncodeWithEncoding(args[2], data, dataSize); } else if (args.Length() > 1 && args[1]->IsString()) { - outString = EncodeWithEncoding(args[2], data, dataSize); + outString = EncodeWithEncoding(args[1], data, dataSize); } else { outString = Encode(data, dataSize, BINARY); } @@ -2930,6 +2960,88 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } + static Handle SetPublicKey(const Arguments& args) { + HandleScope scope; + + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(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(buf), len, 0); + delete[] buf; + } else if (Buffer::HasInstance(args[0])) { + Local buffer = args[0]->ToObject(); + diffieHellman->dh->pub_key = + BN_bin2bn( + reinterpret_cast(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 SetPrivateKey(const Arguments& args) { + HandleScope scope; + + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(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(buf), len, 0); + delete[] buf; + } else if (Buffer::HasInstance(args[0])) { + Local buffer = args[0]->ToObject(); + diffieHellman->dh->priv_key = + BN_bin2bn( + reinterpret_cast(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; diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index d6c1039ab3e..c9e77248bd9 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -119,12 +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.generateKey(); -var key2 = dh2.generateKey('hex'); +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); From 5ff9ffa02531038cefb6da84d7fe5055065468eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Stranden?= Date: Tue, 8 Feb 2011 21:04:44 +0100 Subject: [PATCH 4/4] Linted Diffie-Hellman parts of node_crypto.cc --- src/node_crypto.cc | 133 ++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 51 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index bfa02a92c9c..55d4bfb9ff9 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2656,7 +2656,7 @@ class Verify : public ObjectWrap { class DiffieHellman : public ObjectWrap { public: - static void Initialize (v8::Handle target) { + static void Initialize(v8::Handle target) { HandleScope scope; Local t = FunctionTemplate::New(New); @@ -2696,7 +2696,7 @@ class DiffieHellman : public ObjectWrap { } protected: - static Handle New (const Arguments& args) { + static Handle New(const Arguments& args) { HandleScope scope; DiffieHellman* diffieHellman = new DiffieHellman(); @@ -2718,7 +2718,8 @@ class DiffieHellman : public ObjectWrap { if (len == -1) { delete[] buf; - return ThrowException(Exception::Error(String::New("Invalid argument"))); + return ThrowException(Exception::Error( + String::New("Invalid argument"))); } else { diffieHellman->Init(reinterpret_cast(buf), len); delete[] buf; @@ -2727,7 +2728,7 @@ class DiffieHellman : public ObjectWrap { } else if (Buffer::HasInstance(args[0])) { Local buffer = args[0]->ToObject(); diffieHellman->Init( - reinterpret_cast(Buffer::Data(buffer)), + reinterpret_cast(Buffer::Data(buffer)), Buffer::Length(buffer)); initialized = true; } @@ -2735,7 +2736,8 @@ class DiffieHellman : public ObjectWrap { } if (!initialized) { - return ThrowException(Exception::Error(String::New("Initialization failed"))); + return ThrowException(Exception::Error( + String::New("Initialization failed"))); } diffieHellman->Wrap(args.This()); @@ -2743,24 +2745,28 @@ class DiffieHellman : public ObjectWrap { return args.This(); } - static Handle GenerateKeys (const Arguments& args) { - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + static Handle GenerateKeys(const Arguments& args) { + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); HandleScope scope; if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); + return ThrowException(Exception::Error( + String::New("Not initialized"))); } if (!DH_generate_key(diffieHellman->dh)) { - return ThrowException(Exception::Error(String::New("Key generation failed"))); + return ThrowException(Exception::Error( + String::New("Key generation failed"))); } Local outString; int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); char* data = new char[dataSize]; - BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast(data)); + BN_bn2bin(diffieHellman->dh->pub_key, + reinterpret_cast(data)); if (args.Length() > 0 && args[0]->IsString()) { outString = EncodeWithEncoding(args[0], data, dataSize); @@ -2772,8 +2778,9 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } - static Handle GetPrime (const Arguments& args) { - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + static Handle GetPrime(const Arguments& args) { + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); HandleScope scope; @@ -2798,8 +2805,9 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } - static Handle GetGenerator (const Arguments& args) { - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + static Handle GetGenerator(const Arguments& args) { + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); HandleScope scope; @@ -2824,8 +2832,9 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } - static Handle GetPublicKey (const Arguments& args) { - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + static Handle GetPublicKey(const Arguments& args) { + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); HandleScope scope; @@ -2834,12 +2843,14 @@ class DiffieHellman : public ObjectWrap { } if (diffieHellman->dh->pub_key == NULL) { - return ThrowException(Exception::Error(String::New("No public key - did you forget to generate one?"))); + 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(data)); + BN_bn2bin(diffieHellman->dh->pub_key, + reinterpret_cast(data)); Local outString; @@ -2854,8 +2865,9 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } - static Handle GetPrivateKey (const Arguments& args) { - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + static Handle GetPrivateKey(const Arguments& args) { + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); HandleScope scope; @@ -2864,12 +2876,14 @@ class DiffieHellman : public ObjectWrap { } if (diffieHellman->dh->priv_key == NULL) { - return ThrowException(Exception::Error(String::New("No private key - did you forget to generate one?"))); + 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(data)); + BN_bn2bin(diffieHellman->dh->priv_key, + reinterpret_cast(data)); Local outString; @@ -2884,10 +2898,11 @@ class DiffieHellman : public ObjectWrap { return scope.Close(outString); } - static Handle ComputeSecret (const Arguments& args) { + static Handle ComputeSecret(const Arguments& args) { HandleScope scope; - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); if (!diffieHellman->initialised_) { return ThrowException(Exception::Error(String::New("Not initialized"))); @@ -2896,7 +2911,8 @@ class DiffieHellman : public ObjectWrap { BIGNUM* key = 0; if (args.Length() == 0) { - return ThrowException(Exception::Error(String::New("First argument must be other party's public key"))); + return ThrowException(Exception::Error( + String::New("First argument must be other party's public key"))); } else { if (args[0]->IsString()) { char* buf; @@ -2908,24 +2924,26 @@ class DiffieHellman : public ObjectWrap { } if (len == -1) { delete[] buf; - return ThrowException(Exception::Error(String::New("Invalid argument"))); + return ThrowException(Exception::Error( + String::New("Invalid argument"))); } key = BN_bin2bn(reinterpret_cast(buf), len, 0); delete[] buf; } else if (Buffer::HasInstance(args[0])) { Local buffer = args[0]->ToObject(); key = BN_bin2bn( - reinterpret_cast(Buffer::Data(buffer)), + reinterpret_cast(Buffer::Data(buffer)), Buffer::Length(buffer), 0); } else { - return ThrowException(Exception::Error(String::New("First argument must be other party's public key"))); + 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(data), + int size = DH_compute_key(reinterpret_cast(data), key, diffieHellman->dh); BN_free(key); @@ -2937,9 +2955,11 @@ class DiffieHellman : public ObjectWrap { 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"))); + 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"))); + return ThrowException(Exception::Error( + String::New("Supplied key is too large"))); } else { return ThrowException(Exception::Error(String::New("Invalid key"))); } @@ -2963,14 +2983,16 @@ class DiffieHellman : public ObjectWrap { static Handle SetPublicKey(const Arguments& args) { HandleScope scope; - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(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"))); + return ThrowException(Exception::Error( + String::New("First argument must be public key"))); } else { if (args[0]->IsString()) { char* buf; @@ -2982,19 +3004,21 @@ class DiffieHellman : public ObjectWrap { } if (len == -1) { delete[] buf; - return ThrowException(Exception::Error(String::New("Invalid argument"))); + return ThrowException(Exception::Error( + String::New("Invalid argument"))); } - diffieHellman->dh->pub_key = + diffieHellman->dh->pub_key = BN_bin2bn(reinterpret_cast(buf), len, 0); delete[] buf; } else if (Buffer::HasInstance(args[0])) { Local buffer = args[0]->ToObject(); - diffieHellman->dh->pub_key = + diffieHellman->dh->pub_key = BN_bin2bn( - reinterpret_cast(Buffer::Data(buffer)), + reinterpret_cast(Buffer::Data(buffer)), Buffer::Length(buffer), 0); } else { - return ThrowException(Exception::Error(String::New("First argument must be public key"))); + return ThrowException(Exception::Error( + String::New("First argument must be public key"))); } } @@ -3004,14 +3028,17 @@ class DiffieHellman : public ObjectWrap { static Handle SetPrivateKey(const Arguments& args) { HandleScope scope; - DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); + return ThrowException(Exception::Error( + String::New("Not initialized"))); } if (args.Length() == 0) { - return ThrowException(Exception::Error(String::New("First argument must be private key"))); + return ThrowException(Exception::Error( + String::New("First argument must be private key"))); } else { if (args[0]->IsString()) { char* buf; @@ -3023,31 +3050,33 @@ class DiffieHellman : public ObjectWrap { } if (len == -1) { delete[] buf; - return ThrowException(Exception::Error(String::New("Invalid argument"))); + return ThrowException(Exception::Error( + String::New("Invalid argument"))); } - diffieHellman->dh->priv_key = + diffieHellman->dh->priv_key = BN_bin2bn(reinterpret_cast(buf), len, 0); delete[] buf; } else if (Buffer::HasInstance(args[0])) { Local buffer = args[0]->ToObject(); - diffieHellman->dh->priv_key = + diffieHellman->dh->priv_key = BN_bin2bn( - reinterpret_cast(Buffer::Data(buffer)), + reinterpret_cast(Buffer::Data(buffer)), Buffer::Length(buffer), 0); } else { - return ThrowException(Exception::Error(String::New("First argument must be private key"))); + return ThrowException(Exception::Error( + String::New("First argument must be private key"))); } } return args.This(); } - DiffieHellman () : ObjectWrap () { + DiffieHellman() : ObjectWrap() { initialised_ = false; dh = NULL; } - ~DiffieHellman () { + ~DiffieHellman() { if (dh != NULL) { DH_free(dh); } @@ -3068,13 +3097,14 @@ class DiffieHellman : public ObjectWrap { int len = DecodeBytes(str); *buf = new char[len]; int written = DecodeWrite(*buf, len, str, BINARY); - if(written != len) { + if (written != len) { return -1; } return len; } - static int DecodeWithEncoding(Handle str, Handle enc, char** buf) { + static int DecodeWithEncoding(Handle str, Handle enc, + char** buf) { int len = DecodeBinary(str, buf); if (len == -1) { return len; @@ -3105,7 +3135,8 @@ class DiffieHellman : public ObjectWrap { return len; } - static Local EncodeWithEncoding(Handle enc, char* buf, int len) { + static Local EncodeWithEncoding(Handle enc, char* buf, + int len) { HandleScope scope; Local outString;