};
+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;
+};
Connection::Initialize(target);
Cipher::Initialize(target);
Decipher::Initialize(target);
+ DiffieHellman::Initialize(target);
Hmac::Initialize(target);
Hash::Initialize(target);
Sign::Initialize(target);