/src/keyexchange.cc

http://github.com/OpenRTMFP/ArcusNode · C++ · 222 lines · 133 code · 47 blank · 42 comment · 8 complexity · b9532562b042a0ca1820d0196960af19 MD5 · raw file

  1. /**
  2. * KeyExchange - Diffie-Hellman Key Exchange Module for Node
  3. *
  4. * Copyright 2011 OpenRTMFP
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License received along this program for more
  15. * details (or else see http://www.gnu.org/licenses/).
  16. *
  17. * This file is a part of ArcusNode.
  18. */
  19. #include <v8.h>
  20. #include <node.h>
  21. #include <node_buffer.h>
  22. #include <openssl/evp.h>
  23. #include <openssl/hmac.h>
  24. #include <openssl/dh.h>
  25. #include <string.h>
  26. using namespace v8;
  27. using namespace node;
  28. #define AES_KEY_SIZE 0x20
  29. uint8_t g_dh1024p[] = {
  30. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  31. 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
  32. 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
  33. 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
  34. 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
  35. 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
  36. 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
  37. 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
  38. 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
  39. 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
  40. 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
  41. 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
  42. 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
  43. 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
  44. 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
  45. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
  46. };
  47. class KeyExchange: ObjectWrap
  48. {
  49. private:
  50. public:
  51. static Persistent<FunctionTemplate> s_ct;
  52. DH* dh;
  53. /**
  54. * Node module initialization and method exposure
  55. */
  56. static void init (Handle<Object> target)
  57. {
  58. HandleScope scope;
  59. target->Set(String::New("version"), String::New("0.1"));
  60. Local<FunctionTemplate> t = FunctionTemplate::New(New);
  61. s_ct = Persistent<FunctionTemplate>::New(t);
  62. s_ct->InstanceTemplate()->SetInternalFieldCount(1);
  63. s_ct->SetClassName(String::NewSymbol("KeyExchange"));
  64. NODE_SET_PROTOTYPE_METHOD(s_ct, "computeAsymetricKeys", computeAsymetricKeys);
  65. NODE_SET_PROTOTYPE_METHOD(s_ct, "generateKeyPair", generateKeyPair);
  66. NODE_SET_PROTOTYPE_METHOD(s_ct, "computeSharedSecret", computeSharedSecret);
  67. target->Set(String::NewSymbol("KeyExchange"), s_ct->GetFunction());
  68. }
  69. KeyExchange() : ObjectWrap()
  70. {
  71. dh = NULL;
  72. }
  73. ~KeyExchange(){
  74. if (dh) DH_free(dh);
  75. }
  76. /**
  77. * Creates a new KeyExchange instance as a JavaScript Object
  78. */
  79. static Handle<Value> New(const Arguments& args)
  80. {
  81. HandleScope scope;
  82. KeyExchange* hw = new KeyExchange();
  83. hw->Wrap(args.This());
  84. return args.This();
  85. }
  86. /**
  87. * Generates a private/public keypair for dh key exchange
  88. *
  89. * @return {Array} [privateKey, publicKey]
  90. */
  91. static Handle<Value> generateKeyPair(const Arguments& args) {
  92. KeyExchange *ke = ObjectWrap::Unwrap<KeyExchange>(args.This());
  93. HandleScope scope;
  94. char private_key[128];
  95. char public_key[128];
  96. // Create DH keypair
  97. ke->dh = DH_new();
  98. ke->dh->p = BN_new();
  99. ke->dh->g = BN_new();
  100. BN_set_word(ke->dh->g, 2);
  101. BN_bin2bn(g_dh1024p, 128, ke->dh->p);
  102. DH_generate_key(ke->dh);
  103. //Fill the servers public key
  104. BN_bn2bin(ke->dh->pub_key, (uint8_t*)public_key);
  105. BN_bn2bin(ke->dh->priv_key, (uint8_t*)private_key);
  106. Local<Array> keys = Array::New();
  107. keys->Set(uint32_t(0), Buffer::New(private_key, 128)->handle_);
  108. keys->Set(uint32_t(1), Buffer::New(public_key, 128)->handle_);
  109. return scope.Close(keys);
  110. }
  111. /**
  112. * Computes the shared secret from a public key
  113. */
  114. static Handle<Value> computeSharedSecret(const Arguments& args) {
  115. KeyExchange *ke = ObjectWrap::Unwrap<KeyExchange>(args.This());
  116. HandleScope scope;
  117. Local<Object> far_key_obj = args[0]->ToObject();
  118. if (args.Length() < 1 || !Buffer::HasInstance(far_key_obj)) {
  119. return ThrowException(Exception::TypeError(String::New("Bad argument")));
  120. }
  121. if(DH_size(ke->dh) <= 0){
  122. return ThrowException(Exception::TypeError(String::New("DH empty. Generate Keypair first.")));
  123. }
  124. char *far_key = Buffer::Data(far_key_obj);
  125. size_t far_key_size = Buffer::Length(far_key_obj);
  126. char shared_secret[128];
  127. BIGNUM *bn_far_key = BN_bin2bn((const uint8_t*)far_key, far_key_size, NULL);
  128. DH_compute_key((unsigned char*)shared_secret, bn_far_key, ke->dh);
  129. BN_free(bn_far_key);
  130. return scope.Close(Buffer::New(shared_secret, 128)->handle_);
  131. }
  132. /**
  133. * Computes the asymetric keys in RTMFP handshake for further communication.
  134. * Returns an array with three values: [decryptKey, encryptKey]
  135. */
  136. static Handle<Value> computeAsymetricKeys(const Arguments& args) {
  137. HandleScope scope;
  138. Local<Object> shared_secret_obj = args[0]->ToObject();
  139. Local<Object> initiator_nonce_obj = args[1]->ToObject();
  140. Local<Object> responder_nonce_obj = args[2]->ToObject();
  141. if (args.Length() < 3 || !Buffer::HasInstance(shared_secret_obj) || !Buffer::HasInstance(initiator_nonce_obj) || !Buffer::HasInstance(responder_nonce_obj)) {
  142. return ThrowException(Exception::TypeError(String::New("Bad argument")));
  143. }
  144. char *shared_secret = Buffer::Data(shared_secret_obj);
  145. size_t shared_secret_size = Buffer::Length(shared_secret_obj);
  146. char *initiator_nonce = Buffer::Data(initiator_nonce_obj);
  147. size_t initiator_nonce_size = Buffer::Length(initiator_nonce_obj);
  148. char *responder_nonce = Buffer::Data(responder_nonce_obj);
  149. size_t responder_nonce_size = Buffer::Length(responder_nonce_obj);
  150. uint8_t md1[AES_KEY_SIZE];
  151. uint8_t md2[AES_KEY_SIZE];
  152. // doing HMAC-SHA256 of one side
  153. HMAC(EVP_sha256(), responder_nonce, responder_nonce_size, (const uint8_t*)initiator_nonce, initiator_nonce_size, md1, NULL);
  154. // doing HMAC-SHA256 of the other side
  155. HMAC(EVP_sha256(), initiator_nonce, initiator_nonce_size, (const uint8_t*)responder_nonce, responder_nonce_size, md2, NULL);
  156. char decrypt_key[128];
  157. char encrypt_key[128];
  158. // now doing HMAC-sha256 of both result with the shared secret DH key
  159. HMAC(EVP_sha256(), shared_secret, shared_secret_size, md1, AES_KEY_SIZE, (uint8_t*)decrypt_key, NULL);
  160. HMAC(EVP_sha256(), shared_secret, shared_secret_size, md2, AES_KEY_SIZE, (uint8_t*)encrypt_key, NULL);
  161. Local<Array> keys = Array::New();
  162. keys->Set(uint32_t(0), Buffer::New(decrypt_key, 128)->handle_);
  163. keys->Set(uint32_t(1), Buffer::New(encrypt_key, 128)->handle_);
  164. return scope.Close(keys);
  165. }
  166. };
  167. Persistent<FunctionTemplate> KeyExchange::s_ct;
  168. //Node module exposure
  169. extern "C" {
  170. static void init (Handle<Object> target)
  171. {
  172. KeyExchange::init(target);
  173. }
  174. NODE_MODULE(keyexchange, init);
  175. }