Merge remote-tracking branch ry/v0.10 into master
authorisaacs <i@izs.me>
Mon, 20 May 2013 21:43:14 +0000 (14:43 -0700)
committerisaacs <i@izs.me>
Mon, 20 May 2013 21:43:14 +0000 (14:43 -0700)
Conflicts:
AUTHORS
ChangeLog
src/node_crypto.cc
src/node_version.h

1  2 
AUTHORS
ChangeLog
doc/api/vm.markdown
src/node_crypto.cc
src/string_bytes.cc
test/simple/test-buffer.js

diff --cc AUTHORS
+++ b/AUTHORS
@@@ -452,4 -447,5 +452,6 @@@ Kevin Locke <kevin@kevinlocke.name
  Daniel Moore <polaris@northhorizon.net>
  Robert Kowalski <rok@kowalski.gd>
  Benoit Vallée <github@benoitvallee.net>
+ Ryuichi Okumura <okuryu@okuryu.com>
+ Brandon Frohs <bfrohs@gmail.com>
 +Nick Sullivan <nick@sullivanflock.com>
diff --cc ChangeLog
+++ b/ChangeLog
@@@ -1,65 -1,16 +1,78 @@@
 -2013.05.17, Version 0.10.7 (Stable)
 +2013.05.13, Version 0.11.2 (Unstable)
 +
 +* uv: Upgrade to 0.11.2
 +
 +* V8: Upgrade to 3.19.0
 +
 +* npm: Upgrade to 1.2.21
 +
 +* build: Makefile should respect configure --prefix (Timothy J Fontaine)
 +
 +* cluster: use round-robin load balancing (Ben Noordhuis)
 +
 +* debugger, cluster: each worker has new debug port (Miroslav Bajtoš)
 +
 +* debugger: `restart` with custom debug port (Miroslav Bajtoš)
 +
 +* debugger: breakpoints in scripts not loaded yet (Miroslav Bajtoš)
 +
 +* event: EventEmitter#setMaxListeners() returns this (Sam Roberts)
 +
 +* events: add EventEmitter.defaultMaxListeners (Ben Noordhuis)
 +
 +* install: Support $(PREFIX) install target directory prefix (Olof Johansson)
 +
 +* os: Include netmask in os.networkInterfaces() (Ben Kelly)
 +
 +* path: add path.isAbsolute(path) (Ryan Doenges)
 +
 +* stream: Guarantee ordering of 'finish' event (isaacs)
 +
 +* streams: introduce .cork/.uncork/._writev (Fedor Indutny)
 +
 +* vm: add support for timeout argument (Andrew Paprocki)
 +
 +
 +2013.04.19, Version 0.11.1 (Unstable), 4babd2b46ebf9fbea2c9946af5cfae25a33b2b22
 +
 +* V8: upgrade to 3.18.0
 +
 +* uv: Upgrade to v0.11.1
 +
 +* http: split into multiple separate modules (Timothy J Fontaine)
 +
 +* http: escape unsafe characters in request path (Ben Noordhuis)
 +
 +* url: Escape all unwise characters (isaacs)
 +
 +* build: depend on v8 postmortem-metadata if enabled (Paddy Byers)
 +
 +* etw: update prototypes to match dtrace provider (Timothy J Fontaine)
 +
 +* buffer: change output of Buffer.prototype.toJSON() (David Braun)
 +
 +* dtrace: actually use the _handle.fd value (Timothy J Fontaine)
 +
 +* dtrace: pass more arguments to probes (Dave Pacheco)
 +
 +* build: allow building with dtrace on osx (Dave Pacheco)
 +
 +* zlib: allow passing options to convenience methods (Kyle Robinson Young)
 +
 +
++2013.05.17, Version 0.10.7 (Stable), d2fdae197ac542f686ee06835d1153dd43b862e5
+ * uv: upgrade to v0.10.7
+ * npm: Upgrade to 1.2.21
+ * crypto: Don't ignore verify encoding argument (isaacs)
+ * buffer, crypto: fix default encoding regression (Ben Noordhuis)
+ * timers: fix setInterval() assert (Ben Noordhuis)
  2013.05.14, Version 0.10.6 (Stable), 5deb1672f2b5794f8be19498a425ea4dc0b0711f
  
  * module: Deprecate require.extensions (isaacs)
Simple merge
@@@ -2055,1285 -2032,1718 +2056,1288 @@@ Handle<Value> Connection::SetSNICallbac
  #endif
  
  
 -class Cipher : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
 -
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +void CipherBase::Initialize(Handle<Object> target) {
 +  HandleScope scope(node_isolate);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", CipherInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "initiv", CipherInitIv);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", CipherUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
 -    NODE_SET_PROTOTYPE_METHOD(t, "final", CipherFinal);
 -
 -    target->Set(String::NewSymbol("Cipher"), t->GetFunction());
 -  }
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", Init);
 +  NODE_SET_PROTOTYPE_METHOD(t, "initiv", InitIv);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", Update);
 +  NODE_SET_PROTOTYPE_METHOD(t, "final", Final);
 +  NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
  
 -  bool CipherInit(char* cipherType, char* key_buf, int key_buf_len) {
 -    cipher = EVP_get_cipherbyname(cipherType);
 -    if(!cipher) {
 -      fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
 -      return false;
 -    }
 +  target->Set(String::NewSymbol("CipherBase"), t->GetFunction());
 +}
  
 -    unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
 -    int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL,
 -      (unsigned char*) key_buf, key_buf_len, 1, key, iv);
  
 -    EVP_CIPHER_CTX_init(&ctx);
 -    EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
 -    if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
 -      fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -      return false;
 -    }
 -    EVP_CipherInit_ex(&ctx, NULL, NULL,
 -      (unsigned char*)key,
 -      (unsigned char*)iv, true);
 -    initialised_ = true;
 -    return true;
 -  }
 -
 -
 -  bool CipherInitIv(char* cipherType,
 -                    char* key,
 -                    int key_len,
 -                    char* iv,
 -                    int iv_len) {
 -    cipher = EVP_get_cipherbyname(cipherType);
 -    if(!cipher) {
 -      fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
 -      return false;
 -    }
 -    /* OpenSSL versions up to 0.9.8l failed to return the correct
 -       iv_length (0) for ECB ciphers */
 -    if (EVP_CIPHER_iv_length(cipher) != iv_len &&
 -      !(EVP_CIPHER_mode(cipher) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
 -      fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len);
 -      return false;
 -    }
 -    EVP_CIPHER_CTX_init(&ctx);
 -    EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
 -    if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
 -      fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -      return false;
 -    }
 -    EVP_CipherInit_ex(&ctx, NULL, NULL,
 -      (unsigned char*)key,
 -      (unsigned char*)iv, true);
 -    initialised_ = true;
 -    return true;
 -  }
 +Handle<Value> CipherBase::New(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  int CipherUpdate(char* data, int len, unsigned char** out, int* out_len) {
 -    if (!initialised_) return 0;
 -    *out_len = len+EVP_CIPHER_CTX_block_size(&ctx);
 -    *out = new unsigned char[*out_len];
 -    return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len);
 -  }
 +  CipherBase* cipher = new CipherBase(args[0]->IsTrue() ? kCipher : kDecipher);
 +  cipher->Wrap(args.This());
 +  return args.This();
 +}
  
 -  int SetAutoPadding(bool auto_padding) {
 -    if (!initialised_) return 0;
 -    return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
 -  }
 +Handle<Value> CipherBase::Init(char* cipher_type,
 +                               char* key_buf,
 +                               int key_buf_len) {
 +  HandleScope scope(node_isolate);
  
 -  int CipherFinal(unsigned char** out, int *out_len) {
 -    if (!initialised_) return 0;
 -    *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
 -    int r = EVP_CipherFinal_ex(&ctx,*out, out_len);
 -    EVP_CIPHER_CTX_cleanup(&ctx);
 -    initialised_ = false;
 -    return r;
 +  assert(cipher_ == NULL);
 +  cipher_ = EVP_get_cipherbyname(cipher_type);
 +  if (cipher_ == NULL) {
 +    return ThrowError("Unknown cipher");
    }
  
 +  unsigned char key[EVP_MAX_KEY_LENGTH];
 +  unsigned char iv[EVP_MAX_IV_LENGTH];
  
 - protected:
 -
 -  static Handle<Value> New(const Arguments& args) {
 -    HandleScope scope;
 +  int key_len = EVP_BytesToKey(cipher_,
 +                               EVP_md5(),
 +                               NULL,
 +                               reinterpret_cast<unsigned char*>(key_buf),
 +                               key_buf_len,
 +                               1,
 +                               key,
 +                               iv);
  
 -    Cipher *cipher = new Cipher();
 -    cipher->Wrap(args.This());
 -    return args.This();
 +  EVP_CIPHER_CTX_init(&ctx_);
 +  EVP_CipherInit_ex(&ctx_, cipher_, NULL, NULL, NULL, kind_ == kCipher);
 +  if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) {
 +    EVP_CIPHER_CTX_cleanup(&ctx_);
 +    return ThrowError("Invalid key length");
    }
  
 -  static Handle<Value> CipherInit(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 -
 -    if (args.Length() <= 1
 -        || !args[0]->IsString()
 -        || !(args[1]->IsString() || Buffer::HasInstance(args[1])))
 -    {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give cipher-type, key")));
 -    }
 +  EVP_CipherInit_ex(&ctx_,
 +                    NULL,
 +                    NULL,
 +                    reinterpret_cast<unsigned char*>(key),
 +                    reinterpret_cast<unsigned char*>(iv),
 +                    kind_ == kCipher);
 +  initialised_ = true;
 +  return Null(node_isolate);
 +}
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_buf_len = Buffer::Length(args[1]);
  
 -    if (key_buf_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +Handle<Value> CipherBase::Init(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    char* key_buf = new char[key_buf_len];
 -    ssize_t key_written = DecodeWrite(key_buf, key_buf_len, args[1], BINARY);
 -    assert(key_written == key_buf_len);
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    String::Utf8Value cipherType(args[0]);
 -
 -    bool r = cipher->CipherInit(*cipherType, key_buf, key_buf_len);
 +  if (args.Length() < 2 ||
 +      !(args[0]->IsString() && Buffer::HasInstance(args[1]))) {
 +    return ThrowError("Must give cipher-type, key");
 +  }
  
 -    delete [] key_buf;
 +  String::Utf8Value cipher_type(args[0]);
 +  char* key_buf = Buffer::Data(args[1]);
 +  ssize_t key_buf_len = Buffer::Length(args[1]);
  
 -    if (!r) return ThrowCryptoError(ERR_get_error());
 +  Handle<Value> ret = cipher->Init(*cipher_type, key_buf, key_buf_len);
  
 +  if (ret->IsNull()) {
      return args.This();
 +  } else {
 +    // Exception
 +    return scope.Close(ret);
    }
 +}
  
  
 -  static Handle<Value> CipherInitIv(const Arguments& args) {
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 -
 -    HandleScope scope;
 -
 +Handle<Value> CipherBase::InitIv(char* cipher_type,
 +                                 char* key,
 +                                 int key_len,
 +                                 char* iv,
 +                                 int iv_len) {
 +  HandleScope scope(node_isolate);
  
 -    if (args.Length() <= 2
 -        || !args[0]->IsString()
 -        || !(args[1]->IsString() || Buffer::HasInstance(args[1]))
 -        || !(args[2]->IsString() || Buffer::HasInstance(args[2])))
 -    {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give cipher-type, key, and iv as argument")));
 -    }
 +  cipher_ = EVP_get_cipherbyname(cipher_type);
 +  if (cipher_ == NULL) {
 +    return ThrowError("Unknown cipher");
 +  }
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_len = Buffer::Length(args[1]);
 +  /* OpenSSL versions up to 0.9.8l failed to return the correct
 +     iv_length (0) for ECB ciphers */
 +  if (EVP_CIPHER_iv_length(cipher_) != iv_len &&
 +      !(EVP_CIPHER_mode(cipher_) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
 +    return ThrowError("Invalid IV length");
 +  }
 +  EVP_CIPHER_CTX_init(&ctx_);
 +  EVP_CipherInit_ex(&ctx_, cipher_, NULL, NULL, NULL, kind_ == kCipher);
 +  if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) {
 +    EVP_CIPHER_CTX_cleanup(&ctx_);
 +    return ThrowError("Invalid key length");
 +  }
  
 -    if (key_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  EVP_CipherInit_ex(&ctx_,
 +                    NULL,
 +                    NULL,
 +                    reinterpret_cast<unsigned char*>(key),
 +                    reinterpret_cast<unsigned char*>(iv),
 +                    kind_ == kCipher);
 +  initialised_ = true;
 +  return Null(node_isolate);
 +}
  
 -    ASSERT_IS_BUFFER(args[2]);
 -    ssize_t iv_len = Buffer::Length(args[2]);
  
 -    if (iv_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +Handle<Value> CipherBase::InitIv(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    char* key_buf = new char[key_len];
 -    ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
 -    assert(key_written == key_len);
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    char* iv_buf = new char[iv_len];
 -    ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY);
 -    assert(iv_written == iv_len);
 -
 -    String::Utf8Value cipherType(args[0]);
 +  if (args.Length() < 3 || !args[0]->IsString()) {
 +    return ThrowError("Must give cipher-type, key, and iv as argument");
 +  }
  
 -    bool r = cipher->CipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
 +  ASSERT_IS_BUFFER(args[1]);
 +  ASSERT_IS_BUFFER(args[2]);
  
 -    delete [] key_buf;
 -    delete [] iv_buf;
 +  String::Utf8Value cipher_type(args[0]);
 +  ssize_t key_len = Buffer::Length(args[1]);
 +  char* key_buf = Buffer::Data(args[1]);
 +  ssize_t iv_len = Buffer::Length(args[2]);
 +  char* iv_buf = Buffer::Data(args[2]);
  
 -    if (!r) return ThrowCryptoError(ERR_get_error());
 +  Handle<Value> ret = cipher->InitIv(*cipher_type,
 +                                     key_buf,
 +                                     key_len,
 +                                     iv_buf,
 +                                     iv_len);
  
 +  if (ret->IsNull()) {
      return args.This();
 +  } else {
 +    // Exception
 +    return scope.Close(ret);
    }
 +}
  
 -  static Handle<Value> CipherUpdate(const Arguments& args) {
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
  
 -    HandleScope scope;
 +bool CipherBase::Update(char* data,
 +                        int len,
 +                        unsigned char** out,
 +                        int* out_len) {
 +  if (!initialised_) return 0;
 +  *out_len = len + EVP_CIPHER_CTX_block_size(&ctx_);
 +  *out = new unsigned char[*out_len];
 +  return EVP_CipherUpdate(&ctx_,
 +                          *out,
 +                          out_len,
 +                          reinterpret_cast<unsigned char*>(data),
 +                          len);
 +}
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    // Only copy the data if we have to, because it's a string
 -    unsigned char* out = 0;
 -    int out_len = 0, r;
 -    if (args[0]->IsString()) {
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      size_t buflen = StringBytes::StorageSize(args[0], encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 -      r = cipher->CipherUpdate(buf, written, &out, &out_len);
 -      delete[] buf;
 -    } else {
 -      char* buf = Buffer::Data(args[0]);
 -      size_t buflen = Buffer::Length(args[0]);
 -      r = cipher->CipherUpdate(buf, buflen, &out, &out_len);
 -    }
 +Handle<Value> CipherBase::Update(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (r == 0) {
 -      delete[] out;
 -      return ThrowCryptoTypeError(ERR_get_error());
 -    }
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    Local<Value> outString;
 -    outString = Encode(out, out_len, BUFFER);
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    if (out) delete[] out;
 +  unsigned char* out = NULL;
 +  bool r;
 +  int out_len = 0;
  
 -    return scope.Close(outString);
 +  // Only copy the data if we have to, because it's a string
 +  if (args[0]->IsString()) {
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
 +    size_t buflen = StringBytes::StorageSize(args[0], encoding);
 +    char* buf = new char[buflen];
 +    size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 +    r = cipher->Update(buf, written, &out, &out_len);
 +    delete[] buf;
 +  } else {
 +    char* buf = Buffer::Data(args[0]);
 +    size_t buflen = Buffer::Length(args[0]);
 +    r = cipher->Update(buf, buflen, &out, &out_len);
    }
  
 -  static Handle<Value> SetAutoPadding(const Arguments& args) {
 -    HandleScope scope;
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 -
 -    cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
 -
 -    return Undefined();
 +  if (!r) {
 +    delete[] out;
 +    return ThrowCryptoTypeError(ERR_get_error());
    }
  
 -  static Handle<Value> CipherFinal(const Arguments& args) {
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 -
 -    HandleScope scope;
 +  Buffer* buf = Buffer::New(reinterpret_cast<char*>(out), out_len);
  
 -    unsigned char* out_value = NULL;
 -    int out_len = -1;
 -    Local<Value> outString ;
 +  if (out) delete[] out;
  
 -    int r = cipher->CipherFinal(&out_value, &out_len);
 +  return scope.Close(buf->handle_);
 +}
  
 -    if (out_len <= 0 || r == 0) {
 -      delete[] out_value;
 -      out_value = NULL;
 -      if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
 -    }
  
 -    outString = Encode(out_value, out_len, BUFFER);
 +bool CipherBase::SetAutoPadding(bool auto_padding) {
 +  if (!initialised_) return false;
 +  return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding);
 +}
  
 -    delete [] out_value;
 -    return scope.Close(outString);
 -  }
  
 -  Cipher () : ObjectWrap ()
 -  {
 -    initialised_ = false;
 -  }
 +Handle<Value> CipherBase::SetAutoPadding(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  ~Cipher () {
 -    if (initialised_) {
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -    }
 -  }
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 - private:
 -
 -  EVP_CIPHER_CTX ctx; /* coverity[member_decl] */
 -  const EVP_CIPHER *cipher; /* coverity[member_decl] */
 -  bool initialised_;
 -};
 +  cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
  
 +  return Undefined(node_isolate);
 +}
  
  
 -class Decipher : public ObjectWrap {
 - public:
 -  static void
 -  Initialize (v8::Handle<v8::Object> target)
 -  {
 -    HandleScope scope;
 +bool CipherBase::Final(unsigned char** out, int *out_len) {
 +  if (!initialised_) return false;
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +  *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx_)];
 +  bool r = EVP_CipherFinal_ex(&ctx_, *out, out_len);
 +  EVP_CIPHER_CTX_cleanup(&ctx_);
 +  initialised_ = false;
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 -
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", DecipherInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "initiv", DecipherInitIv);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", DecipherUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "final", DecipherFinal);
 -    NODE_SET_PROTOTYPE_METHOD(t, "finaltol", DecipherFinal); // remove someday
 -    NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
 +  return r;
 +}
  
 -    target->Set(String::NewSymbol("Decipher"), t->GetFunction());
 -  }
  
 -  bool DecipherInit(char* cipherType, char* key_buf, int key_buf_len) {
 -    cipher_ = EVP_get_cipherbyname(cipherType);
 +Handle<Value> CipherBase::Final(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    if(!cipher_) {
 -      fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
 -      return false;
 -    }
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
 -    int key_len = EVP_BytesToKey(cipher_,
 -                                 EVP_md5(),
 -                                 NULL,
 -                                 (unsigned char*)(key_buf),
 -                                 key_buf_len,
 -                                 1,
 -                                 key,
 -                                 iv);
 -
 -    EVP_CIPHER_CTX_init(&ctx);
 -    EVP_CipherInit_ex(&ctx, cipher_, NULL, NULL, NULL, false);
 -    if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
 -      fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -      return false;
 -    }
 -    EVP_CipherInit_ex(&ctx, NULL, NULL,
 -      (unsigned char*)key,
 -      (unsigned char*)iv, false);
 -    initialised_ = true;
 -    return true;
 -  }
 -
 -
 -  bool DecipherInitIv(char* cipherType,
 -                      char* key,
 -                      int key_len,
 -                      char* iv,
 -                      int iv_len) {
 -    cipher_ = EVP_get_cipherbyname(cipherType);
 -    if(!cipher_) {
 -      fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
 -      return false;
 -    }
 -    /* OpenSSL versions up to 0.9.8l failed to return the correct
 -      iv_length (0) for ECB ciphers */
 -    if (EVP_CIPHER_iv_length(cipher_) != iv_len &&
 -      !(EVP_CIPHER_mode(cipher_) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
 -      fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len);
 -      return false;
 -    }
 -    EVP_CIPHER_CTX_init(&ctx);
 -    EVP_CipherInit_ex(&ctx, cipher_, NULL, NULL, NULL, false);
 -    if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
 -      fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -      return false;
 -    }
 -    EVP_CipherInit_ex(&ctx, NULL, NULL,
 -      (unsigned char*)key,
 -      (unsigned char*)iv, false);
 -    initialised_ = true;
 -    return true;
 -  }
 -
 -  int DecipherUpdate(char* data, int len, unsigned char** out, int* out_len) {
 -    if (!initialised_) {
 -      *out_len = 0;
 -      *out = NULL;
 -      return 0;
 -    }
 +  unsigned char* out_value = NULL;
 +  int out_len = -1;
 +  Local<Value> outString;
  
 -    *out_len = len+EVP_CIPHER_CTX_block_size(&ctx);
 -    *out = new unsigned char[*out_len];
 +  bool r = cipher->Final(&out_value, &out_len);
  
 -    return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len);
 +  if (out_len <= 0 || !r) {
 +    delete[] out_value;
 +    out_value = NULL;
 +    out_len = 0;
 +    if (!r) return ThrowCryptoTypeError(ERR_get_error());
    }
  
 -  int SetAutoPadding(bool auto_padding) {
 -    if (!initialised_) return 0;
 -    return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
 -  }
 +  Buffer* buf = Buffer::New(reinterpret_cast<char*>(out_value), out_len);
  
 -  // coverity[alloc_arg]
 -  int DecipherFinal(unsigned char** out, int *out_len) {
 -    int r;
 +  return scope.Close(buf->handle_);
 +}
  
 -    if (!initialised_) {
 -      *out_len = 0;
 -      *out = NULL;
 -      return 0;
 -    }
  
 -    *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
 -    r = EVP_CipherFinal_ex(&ctx,*out,out_len);
 -    EVP_CIPHER_CTX_cleanup(&ctx);
 -    initialised_ = false;
 -    return r;
 -  }
 +void Hmac::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 - protected:
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest);
  
 -    Decipher *cipher = new Decipher();
 -    cipher->Wrap(args.This());
 -    return args.This();
 -  }
 +  target->Set(String::NewSymbol("Hmac"), t->GetFunction());
 +}
  
 -  static Handle<Value> DecipherInit(const Arguments& args) {
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
  
 -    HandleScope scope;
 +Handle<Value> Hmac::New(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (args.Length() <= 1
 -        || !args[0]->IsString()
 -        || !(args[1]->IsString() || Buffer::HasInstance(args[1])))
 -    {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give cipher-type, key as argument")));
 -    }
 +  Hmac* hmac = new Hmac();
 +  hmac->Wrap(args.This());
 +  return args.This();
 +}
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_len = Buffer::Length(args[1]);
  
 -    if (key_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +Handle<Value> Hmac::HmacInit(char* hashType, char* key, int key_len) {
 +  HandleScope scope(node_isolate);
  
 -    char* key_buf = new char[key_len];
 -    ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
 -    assert(key_written == key_len);
 +  assert(md_ == NULL);
 +  md_ = EVP_get_digestbyname(hashType);
 +  if (md_ == NULL) {
 +    return ThrowError("Unknown message digest");
 +  }
 +  HMAC_CTX_init(&ctx_);
 +  if (key_len == 0) {
 +    HMAC_Init(&ctx_, "", 0, md_);
 +  } else {
 +    HMAC_Init(&ctx_, key, key_len, md_);
 +  }
 +  initialised_ = true;
  
 -    String::Utf8Value cipherType(args[0]);
 +  return Null(node_isolate);
 +}
  
 -    bool r = cipher->DecipherInit(*cipherType, key_buf,key_len);
  
 -    delete [] key_buf;
 +Handle<Value> Hmac::HmacInit(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("DecipherInit error")));
 -    }
 +  Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    return args.This();
 +  if (args.Length() < 2 || !args[0]->IsString()) {
 +    return ThrowError("Must give hashtype string, key as arguments");
    }
  
 -  static Handle<Value> DecipherInitIv(const Arguments& args) {
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
  
 -    HandleScope scope;
 +  ASSERT_IS_BUFFER(args[1]);
  
 -    if (args.Length() <= 2
 -        || !args[0]->IsString()
 -        || !(args[1]->IsString() || Buffer::HasInstance(args[1]))
 -        || !(args[2]->IsString() || Buffer::HasInstance(args[2])))
 -    {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give cipher-type, key, and iv as argument")));
 -    }
 +  String::Utf8Value hashType(args[0]);
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_len = Buffer::Length(args[1]);
 +  char* buffer_data = Buffer::Data(args[1]);
 +  size_t buffer_length = Buffer::Length(args[1]);
  
 -    if (key_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  Handle<Value> ret = hmac->HmacInit(*hashType, buffer_data, buffer_length);
  
 -    ASSERT_IS_BUFFER(args[2]);
 -    ssize_t iv_len = Buffer::Length(args[2]);
 +  if (ret->IsNull()) {
 +    return args.This();
 +  } else {
 +    // Exception
 +    return ret;
 +  }
 +}
  
 -    if (iv_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
  
 -    char* key_buf = new char[key_len];
 -    ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
 -    assert(key_written == key_len);
 +bool Hmac::HmacUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  HMAC_Update(&ctx_, reinterpret_cast<unsigned char*>(data), len);
 +  return true;
 +}
  
 -    char* iv_buf = new char[iv_len];
 -    ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY);
 -    assert(iv_written == iv_len);
  
 -    String::Utf8Value cipherType(args[0]);
 +Handle<Value> Hmac::HmacUpdate(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    bool r = cipher->DecipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
 +  Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    delete [] key_buf;
 -    delete [] iv_buf;
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("DecipherInitIv error")));
 -    }
 +  // Only copy the data if we have to, because it's a string
 +  bool r;
 +  if (args[0]->IsString()) {
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
 +    size_t buflen = StringBytes::StorageSize(args[0], encoding);
 +    char* buf = new char[buflen];
 +    size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 +    r = hmac->HmacUpdate(buf, written);
 +    delete[] buf;
 +  } else {
 +    char* buf = Buffer::Data(args[0]);
 +    size_t buflen = Buffer::Length(args[0]);
 +    r = hmac->HmacUpdate(buf, buflen);
 +  }
  
 -    return args.This();
 +  if (!r) {
 +    return ThrowTypeError("HmacUpdate fail");
    }
  
 -  static Handle<Value> DecipherUpdate(const Arguments& args) {
 -    HandleScope scope;
 +  return args.This();
 +}
  
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +bool Hmac::HmacDigest(unsigned char** md_value, unsigned int* md_len) {
 +  if (!initialised_) return false;
 +  *md_value = new unsigned char[EVP_MAX_MD_SIZE];
 +  HMAC_Final(&ctx_, *md_value, md_len);
 +  HMAC_CTX_cleanup(&ctx_);
 +  initialised_ = false;
 +  return true;
 +}
  
 -    // Only copy the data if we have to, because it's a string
 -    unsigned char* out = 0;
 -    int out_len = 0, r;
 -    if (args[0]->IsString()) {
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      size_t buflen = StringBytes::StorageSize(args[0], encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 -      r = cipher->DecipherUpdate(buf, written, &out, &out_len);
 -      delete[] buf;
 -    } else {
 -      char* buf = Buffer::Data(args[0]);
 -      size_t buflen = Buffer::Length(args[0]);
 -      r = cipher->DecipherUpdate(buf, buflen, &out, &out_len);
 -    }
  
 -    if (r == 0) {
 -      delete[] out;
 -      return ThrowCryptoTypeError(ERR_get_error());
 -    }
 +Handle<Value> Hmac::HmacDigest(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    Local<Value> outString;
 -    outString = Encode(out, out_len, BUFFER);
 +  Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    if (out) delete [] out;
 +  enum encoding encoding = BUFFER;
 +  if (args.Length() >= 1) {
 +    encoding = ParseEncoding(args[0]->ToString(), BUFFER);
 +  }
 +
 +  unsigned char* md_value = NULL;
 +  unsigned int md_len = 0;
 +  Local<Value> outString;
  
 -    return scope.Close(outString);
 +  bool r = hmac->HmacDigest(&md_value, &md_len);
 +  if (!r) {
 +    md_value = NULL;
 +    md_len = 0;
    }
  
 -  static Handle<Value> SetAutoPadding(const Arguments& args) {
 -    HandleScope scope;
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
 +  outString = StringBytes::Encode(
 +        reinterpret_cast<const char*>(md_value), md_len, encoding);
  
 -    cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
 +  delete[] md_value;
 +  return scope.Close(outString);
 +}
  
 -    return Undefined();
 -  }
  
 -  static Handle<Value> DecipherFinal(const Arguments& args) {
 -    HandleScope scope;
 +void Hash::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    unsigned char* out_value = NULL;
 -    int out_len = -1;
 -    Local<Value> outString;
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    int r = cipher->DecipherFinal(&out_value, &out_len);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest);
  
 -    if (out_len <= 0 || r == 0) {
 -      delete [] out_value; // allocated even if out_len == 0
 -      out_value = NULL;
 -      if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
 -    }
 +  target->Set(String::NewSymbol("Hash"), t->GetFunction());
 +}
  
 -    outString = Encode(out_value, out_len, BUFFER);
 -    delete [] out_value;
 -    return scope.Close(outString);
 -  }
  
 -  Decipher () : ObjectWrap () {
 -    initialised_ = false;
 -  }
 +Handle<Value> Hash::New(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  ~Decipher () {
 -    if (initialised_) {
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -    }
 +  if (args.Length() == 0 || !args[0]->IsString()) {
 +    return ThrowError("Must give hashtype string as argument");
    }
  
 - private:
 +  String::Utf8Value hashType(args[0]);
  
 -  EVP_CIPHER_CTX ctx;
 -  const EVP_CIPHER *cipher_;
 -  bool initialised_;
 -};
 +  Hash* hash = new Hash();
 +  if (!hash->HashInit(*hashType)) {
 +    delete hash;
 +    return ThrowError("Digest method not supported");
 +  }
  
 +  hash->Wrap(args.This());
 +  return args.This();
 +}
  
  
 +bool Hash::HashInit(const char* hashType) {
 +  assert(md_ == NULL);
 +  md_ = EVP_get_digestbyname(hashType);
 +  if (md_ == NULL) return false;
 +  EVP_MD_CTX_init(&mdctx_);
 +  EVP_DigestInit_ex(&mdctx_, md_, NULL);
 +  initialised_ = true;
 +  return true;
 +}
  
 -class Hmac : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +bool Hash::HashUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  EVP_DigestUpdate(&mdctx_, data, len);
 +  return true;
 +}
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest);
 +Handle<Value> Hash::HashUpdate(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    target->Set(String::NewSymbol("Hmac"), t->GetFunction());
 -  }
 +  Hash* hash = ObjectWrap::Unwrap<Hash>(args.This());
  
 -  bool HmacInit(char* hashType, char* key, int key_len) {
 -    md = EVP_get_digestbyname(hashType);
 -    if(!md) {
 -      fprintf(stderr, "node-crypto : Unknown message digest %s\n", hashType);
 -      return false;
 -    }
 -    HMAC_CTX_init(&ctx);
 -    if (key_len == 0) {
 -      HMAC_Init(&ctx, "", 0, md);
 -    } else {
 -      HMAC_Init(&ctx, key, key_len, md);
 -    }
 -    initialised_ = true;
 -    return true;
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 +  // Only copy the data if we have to, because it's a string
 +  bool r;
 +  if (args[0]->IsString()) {
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
 +    size_t buflen = StringBytes::StorageSize(args[0], encoding);
 +    char* buf = new char[buflen];
 +    size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 +    r = hash->HashUpdate(buf, written);
 +    delete[] buf;
 +  } else {
 +    char* buf = Buffer::Data(args[0]);
 +    size_t buflen = Buffer::Length(args[0]);
 +    r = hash->HashUpdate(buf, buflen);
    }
  
 -  int HmacUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    HMAC_Update(&ctx, (unsigned char*)data, len);
 -    return 1;
 +  if (!r) {
 +    return ThrowTypeError("HashUpdate fail");
    }
  
 -  int HmacDigest(unsigned char** md_value, unsigned int *md_len) {
 -    if (!initialised_) return 0;
 -    *md_value = new unsigned char[EVP_MAX_MD_SIZE];
 -    HMAC_Final(&ctx, *md_value, md_len);
 -    HMAC_CTX_cleanup(&ctx);
 -    initialised_ = false;
 -    return 1;
 -  }
 +  return args.This();
 +}
  
  
 - protected:
 +Handle<Value> Hash::HashDigest(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 +  Hash* hash = ObjectWrap::Unwrap<Hash>(args.This());
  
 -    Hmac *hmac = new Hmac();
 -    hmac->Wrap(args.This());
 -    return args.This();
 +  if (!hash->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  static Handle<Value> HmacInit(const Arguments& args) {
 -    Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
 -
 -    HandleScope scope;
 -
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give hashtype string as argument")));
 -    }
 +  enum encoding encoding = BUFFER;
 +  if (args.Length() >= 1) {
 +    encoding = ParseEncoding(args[0]->ToString(), BUFFER);
 +  }
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t len = Buffer::Length(args[1]);
 +  unsigned char md_value[EVP_MAX_MD_SIZE];
 +  unsigned int md_len;
  
 -    if (len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len);
 +  EVP_MD_CTX_cleanup(&hash->mdctx_);
 +  hash->initialised_ = false;
  
 -    String::Utf8Value hashType(args[0]);
 -
 -    bool r;
 +  return scope.Close(StringBytes::Encode(
 +        reinterpret_cast<const char*>(md_value), md_len, encoding));
 +}
  
 -    if( Buffer::HasInstance(args[1])) {
 -      char* buffer_data = Buffer::Data(args[1]);
 -      size_t buffer_length = Buffer::Length(args[1]);
  
 -      r = hmac->HmacInit(*hashType, buffer_data, buffer_length);
 -    } else {
 -      char* buf = new char[len];
 -      ssize_t written = DecodeWrite(buf, len, args[1], BINARY);
 -      assert(written == len);
 +void Sign::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -      r = hmac->HmacInit(*hashType, buf, len);
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -      delete [] buf;
 -    }
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("hmac error")));
 -    }
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal);
  
 -    return args.This();
 -  }
 +  target->Set(String::NewSymbol("Sign"), t->GetFunction());
 +}
  
 -  static Handle<Value> HmacUpdate(const Arguments& args) {
 -    Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    HandleScope scope;
 +Handle<Value> Sign::New(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +  Sign* sign = new Sign();
 +  sign->Wrap(args.This());
  
 -    // Only copy the data if we have to, because it's a string
 -    int r;
 -    if (args[0]->IsString()) {
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      size_t buflen = StringBytes::StorageSize(args[0], encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 -      r = hmac->HmacUpdate(buf, written);
 -      delete[] buf;
 -    } else {
 -      char* buf = Buffer::Data(args[0]);
 -      size_t buflen = Buffer::Length(args[0]);
 -      r = hmac->HmacUpdate(buf, buflen);
 -    }
 +  return args.This();
 +}
  
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("HmacUpdate fail"));
 -      return ThrowException(exception);
 -    }
 +Handle<Value> Sign::SignInit(const char* sign_type) {
 +  HandleScope scope(node_isolate);
  
 -    return args.This();
 +  assert(md_ == NULL);
 +  md_ = EVP_get_digestbyname(sign_type);
 +  if (!md_) {
 +    return ThrowError("Uknown message digest");
    }
 +  EVP_MD_CTX_init(&mdctx_);
 +  EVP_SignInit_ex(&mdctx_, md_, NULL);
 +  initialised_ = true;
 +  return Null(node_isolate);
 +}
  
 -  static Handle<Value> HmacDigest(const Arguments& args) {
 -    Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
 -
 -    HandleScope scope;
 -
 -    enum encoding encoding = BUFFER;
 -    if (args.Length() >= 1) {
 -      encoding = ParseEncoding(args[0]->ToString(), BUFFER);
 -    }
  
 -    unsigned char* md_value = NULL;
 -    unsigned int md_len = 0;
 -    Local<Value> outString;
 +Handle<Value> Sign::SignInit(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    int r = hmac->HmacDigest(&md_value, &md_len);
 -    if (r == 0) {
 -      md_value = NULL;
 -      md_len = 0;
 -    }
 +  Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    outString = StringBytes::Encode(
 -          reinterpret_cast<const char*>(md_value), md_len, encoding);
 -
 -    delete[] md_value;
 -    return scope.Close(outString);
 +  if (args.Length() == 0 || !args[0]->IsString()) {
 +    return ThrowError("Must give signtype string as argument");
    }
  
 -  Hmac () : ObjectWrap () {
 -    initialised_ = false;
 -  }
 +  String::Utf8Value sign_type(args[0]);
  
 -  ~Hmac () {
 -    if (initialised_) {
 -      HMAC_CTX_cleanup(&ctx);
 -    }
 -  }
 +  Handle<Value> ret = sign->SignInit(*sign_type);
  
 - private:
 +  if (ret->IsNull()) {
 +    return args.This();
 +  } else {
 +    // Exception
 +    return scope.Close(ret);
 +  }
 +}
  
 -  HMAC_CTX ctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 -};
  
 +bool Sign::SignUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  EVP_SignUpdate(&mdctx_, data, len);
 +  return true;
 +}
  
 -class Hash : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +Handle<Value> Sign::SignUpdate(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest);
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    target->Set(String::NewSymbol("Hash"), t->GetFunction());
 +  // Only copy the data if we have to, because it's a string
 +  int r;
 +  if (args[0]->IsString()) {
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
 +    size_t buflen = StringBytes::StorageSize(args[0], encoding);
 +    char* buf = new char[buflen];
 +    size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 +    r = sign->SignUpdate(buf, written);
 +    delete[] buf;
 +  } else {
 +    char* buf = Buffer::Data(args[0]);
 +    size_t buflen = Buffer::Length(args[0]);
 +    r = sign->SignUpdate(buf, buflen);
    }
  
 -  bool HashInit (const char* hashType) {
 -    md = EVP_get_digestbyname(hashType);
 -    if(!md) return false;
 -    EVP_MD_CTX_init(&mdctx);
 -    EVP_DigestInit_ex(&mdctx, md, NULL);
 -    initialised_ = true;
 -    return true;
 +  if (!r) {
 +    return ThrowTypeError("SignUpdate fail");
    }
  
 -  int HashUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    EVP_DigestUpdate(&mdctx, data, len);
 -    return 1;
 -  }
 +  return args.This();
 +}
  
  
 - protected:
 +bool Sign::SignFinal(unsigned char** md_value,
 +                     unsigned int *md_len,
 +                     char* key_pem,
 +                     int key_pem_len) {
 +  if (!initialised_) return false;
  
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 +  BIO* bp = NULL;
 +  EVP_PKEY* pkey = NULL;
 +  bp = BIO_new(BIO_s_mem());
 +  if (!BIO_write(bp, key_pem, key_pem_len)) return false;
  
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give hashtype string as argument")));
 -    }
 +  pkey = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
 +  if (pkey == NULL) return 0;
  
 -    String::Utf8Value hashType(args[0]);
 +  EVP_SignFinal(&mdctx_, *md_value, md_len, pkey);
 +  EVP_MD_CTX_cleanup(&mdctx_);
 +  initialised_ = false;
 +  EVP_PKEY_free(pkey);
 +  BIO_free_all(bp);
 +  return true;
 +}
  
 -    Hash *hash = new Hash();
 -    if (!hash->HashInit(*hashType)) {
 -      delete hash;
 -      return ThrowException(Exception::Error(String::New(
 -        "Digest method not supported")));
 -    }
  
 -    hash->Wrap(args.This());
 -    return args.This();
 -  }
 +Handle<Value> Sign::SignFinal(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> HashUpdate(const Arguments& args) {
 -    HandleScope scope;
 +  Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    Hash *hash = ObjectWrap::Unwrap<Hash>(args.This());
 +  unsigned char* md_value;
 +  unsigned int md_len;
 +  Local<Value> outString;
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +  enum encoding encoding = BUFFER;
 +  if (args.Length() >= 2) {
 +    encoding = ParseEncoding(args[1]->ToString(), BUFFER);
 +  }
  
 -    // Only copy the data if we have to, because it's a string
 -    int r;
 -    if (args[0]->IsString()) {
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      size_t buflen = StringBytes::StorageSize(args[0], encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 -      r = hash->HashUpdate(buf, written);
 -      delete[] buf;
 -    } else {
 -      char* buf = Buffer::Data(args[0]);
 -      size_t buflen = Buffer::Length(args[0]);
 -      r = hash->HashUpdate(buf, buflen);
 -    }
 +  ASSERT_IS_BUFFER(args[0]);
 +  ssize_t len = Buffer::Length(args[0]);
 +  char* buf = Buffer::Data(args[0]);
  
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("HashUpdate fail"));
 -      return ThrowException(exception);
 -    }
 +  md_len = 8192; // Maximum key size is 8192 bits
 +  md_value = new unsigned char[md_len];
  
 -    return args.This();
 +  bool r = sign->SignFinal(&md_value, &md_len, buf, len);
 +  if (!r) {
 +    delete[] md_value;
 +    md_value = NULL;
 +    md_len = 0;
    }
  
 -  static Handle<Value> HashDigest(const Arguments& args) {
 -    HandleScope scope;
 +  outString = StringBytes::Encode(
 +      reinterpret_cast<const char*>(md_value), md_len, encoding);
  
 -    Hash *hash = ObjectWrap::Unwrap<Hash>(args.This());
 -
 -    if (!hash->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 +  delete[] md_value;
 +  return scope.Close(outString);
 +}
  
 -    enum encoding encoding = BUFFER;
 -    if (args.Length() >= 1) {
 -      encoding = ParseEncoding(args[0]->ToString(), BUFFER);
 -    }
  
 -    unsigned char md_value[EVP_MAX_MD_SIZE];
 -    unsigned int md_len;
 +void Verify::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -    EVP_DigestFinal_ex(&hash->mdctx, md_value, &md_len);
 -    EVP_MD_CTX_cleanup(&hash->mdctx);
 -    hash->initialised_ = false;
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    return scope.Close(StringBytes::Encode(
 -          reinterpret_cast<const char*>(md_value), md_len, encoding));
 -  }
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -  Hash () : ObjectWrap () {
 -    initialised_ = false;
 -  }
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal);
  
 -  ~Hash () {
 -    if (initialised_) {
 -      EVP_MD_CTX_cleanup(&mdctx);
 -    }
 -  }
 +  target->Set(String::NewSymbol("Verify"), t->GetFunction());
 +}
  
 - private:
  
 -  EVP_MD_CTX mdctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 -};
 +Handle<Value> Verify::New(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -class Sign : public ObjectWrap {
 - public:
 -  static void
 -  Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
 +  Verify* verify = new Verify();
 +  verify->Wrap(args.This());
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +  return args.This();
 +}
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal);
 +Handle<Value> Verify::VerifyInit(const char* verify_type) {
 +  HandleScope scope(node_isolate);
  
 -    target->Set(String::NewSymbol("Sign"), t->GetFunction());
 +  assert(md_ == NULL);
 +  md_ = EVP_get_digestbyname(verify_type);
 +  if (md_ == NULL) {
 +    return ThrowError("Unknown message digest");
    }
  
 -  bool SignInit (const char* signType) {
 -    md = EVP_get_digestbyname(signType);
 -    if(!md) {
 -      printf("Unknown message digest %s\n", signType);
 -      return false;
 -    }
 -    EVP_MD_CTX_init(&mdctx);
 -    EVP_SignInit_ex(&mdctx, md, NULL);
 -    initialised_ = true;
 -    return true;
 +  EVP_MD_CTX_init(&mdctx_);
 +  EVP_VerifyInit_ex(&mdctx_, md_, NULL);
 +  initialised_ = true;
  
 -  }
 -
 -  int SignUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    EVP_SignUpdate(&mdctx, data, len);
 -    return 1;
 -  }
 +  return Null(node_isolate);
 +}
  
 -  int SignFinal(unsigned char** md_value,
 -                unsigned int *md_len,
 -                char* key_pem,
 -                int key_pemLen) {
 -    if (!initialised_) return 0;
  
 -    BIO *bp = NULL;
 -    EVP_PKEY* pkey;
 -    bp = BIO_new(BIO_s_mem());
 -    if(!BIO_write(bp, key_pem, key_pemLen)) return 0;
 +Handle<Value> Verify::VerifyInit(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    pkey = PEM_read_bio_PrivateKey( bp, NULL, NULL, NULL );
 -    if (pkey == NULL) return 0;
 +  Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
  
 -    EVP_SignFinal(&mdctx, *md_value, md_len, pkey);
 -    EVP_MD_CTX_cleanup(&mdctx);
 -    initialised_ = false;
 -    EVP_PKEY_free(pkey);
 -    BIO_free(bp);
 -    return 1;
 +  if (args.Length() == 0 || !args[0]->IsString()) {
 +    return ThrowError("Must give verifytype string as argument");
    }
  
 +  String::Utf8Value verify_type(args[0]);
  
 - protected:
 -
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 -
 -    Sign *sign = new Sign();
 -    sign->Wrap(args.This());
 +  Handle<Value> ret = verify->VerifyInit(*verify_type);
  
 +  if (ret->IsNull()) {
      return args.This();
 +  } else {
 +    // Exception
 +    return scope.Close(ret);
    }
 +}
  
 -  static Handle<Value> SignInit(const Arguments& args) {
 -    HandleScope scope;
  
 -    Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
 +bool Verify::VerifyUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  EVP_VerifyUpdate(&mdctx_, data, len);
 +  return true;
 +}
  
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give signtype string as argument")));
 -    }
  
 -    String::Utf8Value signType(args[0]);
 +Handle<Value> Verify::VerifyUpdate(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    bool r = sign->SignInit(*signType);
 +  Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("SignInit error")));
 -    }
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    return args.This();
 +  // Only copy the data if we have to, because it's a string
 +  bool r;
 +  if (args[0]->IsString()) {
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
 +    size_t buflen = StringBytes::StorageSize(args[0], encoding);
 +    char* buf = new char[buflen];
 +    size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 +    r = verify->VerifyUpdate(buf, written);
 +    delete[] buf;
 +  } else {
 +    char* buf = Buffer::Data(args[0]);
 +    size_t buflen = Buffer::Length(args[0]);
 +    r = verify->VerifyUpdate(buf, buflen);
    }
  
 -  static Handle<Value> SignUpdate(const Arguments& args) {
 -    Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
 -
 -    HandleScope scope;
 -
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 -
 -    // Only copy the data if we have to, because it's a string
 -    int r;
 -    if (args[0]->IsString()) {
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      size_t buflen = StringBytes::StorageSize(args[0], encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 -      r = sign->SignUpdate(buf, written);
 -      delete[] buf;
 -    } else {
 -      char* buf = Buffer::Data(args[0]);
 -      size_t buflen = Buffer::Length(args[0]);
 -      r = sign->SignUpdate(buf, buflen);
 -    }
 -
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("SignUpdate fail"));
 -      return ThrowException(exception);
 -    }
 -
 -    return args.This();
 +  if (!r) {
 +    return ThrowTypeError("VerifyUpdate fail");
    }
  
 -  static Handle<Value> SignFinal(const Arguments& args) {
 -    Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
 -
 -    HandleScope scope;
 -
 -    unsigned char* md_value;
 -    unsigned int md_len;
 -    Local<Value> outString;
 +  return args.This();
 +}
  
 -    ASSERT_IS_BUFFER(args[0]);
 -    ssize_t len = Buffer::Length(args[0]);
  
 -    enum encoding encoding = BUFFER;
 -    if (args.Length() >= 2) {
 -      encoding = ParseEncoding(args[1]->ToString(), BUFFER);
 -    }
 +Handle<Value> Verify::VerifyFinal(char* key_pem,
 +                                  int key_pem_len,
 +                                  unsigned char* sig,
 +                                  int siglen) {
 +  HandleScope scope(node_isolate);
  
 -    char* buf = new char[len];
 -    ssize_t written = DecodeWrite(buf, len, args[0], BUFFER);
 -    assert(written == len);
 +  if (!initialised_) {
 +    return ThrowError("Verify not initalised");
 +  }
  
 -    md_len = 8192; // Maximum key size is 8192 bits
 -    md_value = new unsigned char[md_len];
 +  EVP_PKEY* pkey = NULL;
 +  BIO* bp = NULL;
 +  X509* x509 = NULL;
 +  bool fatal = true;
 +  int r;
  
 -    int r = sign->SignFinal(&md_value, &md_len, buf, len);
 -    if (r == 0) {
 -      md_value = NULL;
 -      md_len = r;
 +  bp = BIO_new(BIO_s_mem());
 +  if (bp == NULL)
 +    goto exit;
 +
 +  if (!BIO_write(bp, key_pem, key_pem_len))
 +    goto exit;
 +
 +  // Check if this is a PKCS#8 or RSA public key before trying as X.509.
 +  // Split this out into a separate function once we have more than one
 +  // consumer of public keys.
 +  if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
 +    pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
 +    if (pkey == NULL)
 +      goto exit;
 +  } else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
 +    RSA* rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
 +    if (rsa) {
 +      pkey = EVP_PKEY_new();
 +      if (pkey) EVP_PKEY_set1_RSA(pkey, rsa);
 +      RSA_free(rsa);
      }
 +    if (pkey == NULL)
 +      goto exit;
 +  } else {
 +    // X.509 fallback
 +    x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL);
 +    if (x509 == NULL)
 +      goto exit;
  
 -    delete [] buf;
 +    pkey = X509_get_pubkey(x509);
 +    if (pkey == NULL)
 +      goto exit;
 +  }
  
 -    outString = StringBytes::Encode(
 -        reinterpret_cast<const char*>(md_value), md_len, encoding);
 +  fatal = false;
 +  r = EVP_VerifyFinal(&mdctx_, sig, siglen, pkey);
  
 -    delete [] md_value;
 -    return scope.Close(outString);
 -  }
 +exit:
 +  if (pkey != NULL)
 +    EVP_PKEY_free(pkey);
 +  if (bp != NULL)
 +    BIO_free_all(bp);
 +  if (x509 != NULL)
 +    X509_free(x509);
  
 -  Sign () : ObjectWrap () {
 -    initialised_ = false;
 -  }
 +  EVP_MD_CTX_cleanup(&mdctx_);
 +  initialised_ = false;
  
 -  ~Sign () {
 -    if (initialised_) {
 -      EVP_MD_CTX_cleanup(&mdctx);
 -    }
 +  if (fatal) {
 +    unsigned long err = ERR_get_error();
 +    return ThrowCryptoError(err);
    }
  
 - private:
 -
 -  EVP_MD_CTX mdctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 -};
 +  return scope.Close(r ? True(node_isolate) : False(node_isolate));
 +}
  
 -class Verify : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +Handle<Value> Verify::VerifyFinal(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal);
 +  ASSERT_IS_BUFFER(args[0]);
 +  char* kbuf = Buffer::Data(args[0]);
 +  ssize_t klen = Buffer::Length(args[0]);
  
 -    target->Set(String::NewSymbol("Verify"), t->GetFunction());
 +  ASSERT_IS_STRING_OR_BUFFER(args[1]);
 +  // BINARY works for both buffers and binary strings.
 +  enum encoding encoding = BINARY;
 +  if (args.Length() >= 3) {
 +    encoding = ParseEncoding(args[2]->ToString(), BINARY);
    }
  
 -
 -  bool VerifyInit (const char* verifyType) {
 -    md = EVP_get_digestbyname(verifyType);
 -    if(!md) {
 -      fprintf(stderr, "node-crypto : Unknown message digest %s\n", verifyType);
 -      return false;
 -    }
 -    EVP_MD_CTX_init(&mdctx);
 -    EVP_VerifyInit_ex(&mdctx, md, NULL);
 -    initialised_ = true;
 -    return true;
 -  }
 +  ssize_t hlen = StringBytes::Size(args[1], encoding);
  
 -  int VerifyUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    EVP_VerifyUpdate(&mdctx, data, len);
 -    return 1;
 +  // only copy if we need to, because it's a string.
 +  unsigned char* hbuf;
 +  if (args[1]->IsString()) {
 +    hbuf = new unsigned char[hlen];
 +    ssize_t hwritten = StringBytes::Write(
 +        reinterpret_cast<char*>(hbuf), hlen, args[1], encoding);
 +    assert(hwritten == hlen);
 +  } else {
 +    hbuf = reinterpret_cast<unsigned char*>(Buffer::Data(args[1]));
    }
  
 +  Local<Value> retval = Local<Value>::New(verify->VerifyFinal(kbuf, klen, hbuf, hlen));
 +  if (args[1]->IsString()) {
 +    delete[] hbuf;
 +  }
 +  return scope.Close(retval);
 +}
  
 -  int VerifyFinal(char* key_pem, int key_pemLen, unsigned char* sig, int siglen) {
 -    if (!initialised_) return 0;
 -
 -    EVP_PKEY* pkey = NULL;
 -    BIO *bp = NULL;
 -    X509 *x509 = NULL;
 -    int r = 0;
  
 -    bp = BIO_new(BIO_s_mem());
 -    if (bp == NULL) {
 -      ERR_print_errors_fp(stderr);
 -      return 0;
 -    }
 -    if(!BIO_write(bp, key_pem, key_pemLen)) {
 -      ERR_print_errors_fp(stderr);
 -      return 0;
 -    }
 -
 -    // Check if this is a PKCS#8 or RSA public key before trying as X.509.
 -    // Split this out into a separate function once we have more than one
 -    // consumer of public keys.
 -    if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
 -      pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
 -      if (pkey == NULL) {
 -        ERR_print_errors_fp(stderr);
 -        return 0;
 -      }
 -    } else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
 -      RSA* rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
 -      if (rsa) {
 -        pkey = EVP_PKEY_new();
 -        if (pkey) EVP_PKEY_set1_RSA(pkey, rsa);
 -        RSA_free(rsa);
 -      }
 -      if (pkey == NULL) {
 -        ERR_print_errors_fp(stderr);
 -        return 0;
 -      }
 -    } else {
 -      // X.509 fallback
 -      x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL);
 -      if (x509 == NULL) {
 -        ERR_print_errors_fp(stderr);
 -        return 0;
 -      }
 +void DiffieHellman::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -      pkey = X509_get_pubkey(x509);
 -      if (pkey == NULL) {
 -        ERR_print_errors_fp(stderr);
 -        return 0;
 -      }
 -    }
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    r = EVP_VerifyFinal(&mdctx, sig, siglen, pkey);
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    if(pkey != NULL)
 -      EVP_PKEY_free (pkey);
 -    if (x509 != NULL)
 -      X509_free(x509);
 -    if (bp != NULL)
 -      BIO_free(bp);
 -    EVP_MD_CTX_cleanup(&mdctx);
 -    initialised_ = false;
 +  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);
  
 -    return r;
 -  }
 +  target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction());
  
 +  Local<FunctionTemplate> t2 = FunctionTemplate::New(DiffieHellmanGroup);
 +  t2->InstanceTemplate()->SetInternalFieldCount(1);
  
 - protected:
 +  NODE_SET_PROTOTYPE_METHOD(t2, "generateKeys", GenerateKeys);
 +  NODE_SET_PROTOTYPE_METHOD(t2, "computeSecret", ComputeSecret);
 +  NODE_SET_PROTOTYPE_METHOD(t2, "getPrime", GetPrime);
 +  NODE_SET_PROTOTYPE_METHOD(t2, "getGenerator", GetGenerator);
 +  NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey);
 +  NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey);
  
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 +  target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction());
 +}
  
 -    Verify *verify = new Verify();
 -    verify->Wrap(args.This());
  
 -    return args.This();
 -  }
 +bool DiffieHellman::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;
 +}
  
  
 -  static Handle<Value> VerifyInit(const Arguments& args) {
 -    Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
 +bool DiffieHellman::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;
 +}
  
 -    HandleScope scope;
  
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give verifytype string as argument")));
 -    }
 +bool DiffieHellman::Init(unsigned char* p,
 +                         int p_len,
 +                         unsigned char* g,
 +                         int g_len) {
 +  dh = DH_new();
 +  dh->p = BN_bin2bn(p, p_len, 0);
 +  dh->g = BN_bin2bn(g, g_len, 0);
 +  initialised_ = true;
 +  return true;
 +}
  
 -    String::Utf8Value verifyType(args[0]);
  
 -    bool r = verify->VerifyInit(*verifyType);
 +Handle<Value> DiffieHellman::DiffieHellmanGroup(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("VerifyInit error")));
 -    }
 +  DiffieHellman* diffieHellman = new DiffieHellman();
  
 -    return args.This();
 +  if (args.Length() != 1 || !args[0]->IsString()) {
 +    return ThrowError("No group name given");
    }
  
 +  String::Utf8Value group_name(args[0]);
  
 -  static Handle<Value> VerifyUpdate(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
 -
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +  modp_group* it = modp_groups;
  
 -    // Only copy the data if we have to, because it's a string
 -    int r;
 -    if (args[0]->IsString()) {
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      size_t buflen = StringBytes::StorageSize(args[0], encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
 -      r = verify->VerifyUpdate(buf, written);
 -      delete[] buf;
 -    } else {
 -      char* buf = Buffer::Data(args[0]);
 -      size_t buflen = Buffer::Length(args[0]);
 -      r = verify->VerifyUpdate(buf, buflen);
 -    }
 -
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("VerifyUpdate fail"));
 -      return ThrowException(exception);
 -    }
 -
 -    return args.This();
 +  while(it->name != NULL) {
 +    if (!strcasecmp(*group_name, it->name))
 +      break;
 +    it++;
    }
  
 +  if (it->name != NULL) {
 +    diffieHellman->Init(it->prime,
 +                        it->prime_size,
 +                        it->gen,
 +                        it->gen_size);
 +  } else {
 +    return ThrowError("Unknown group");
 +  }
  
 -  static Handle<Value> VerifyFinal(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
 +  diffieHellman->Wrap(args.This());
  
 -    ASSERT_IS_BUFFER(args[0]);
 -    ssize_t klen = Buffer::Length(args[0]);
 +  return args.This();
 +}
  
 -    if (klen < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
  
 -    char* kbuf = new char[klen];
 -    ssize_t kwritten = DecodeWrite(kbuf, klen, args[0], BINARY);
 -    assert(kwritten == klen);
 +Handle<Value> DiffieHellman::New(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[1]);
 +  DiffieHellman* diffieHellman = new DiffieHellman();
 +  bool initialized = false;
  
 -    // BINARY works for both buffers and binary strings.
 -    enum encoding encoding = BINARY;
 -    if (args.Length() >= 3) {
 -      encoding = ParseEncoding(args[2]->ToString(), BINARY);
 +  if (args.Length() > 0) {
 +    if (args[0]->IsInt32()) {
 +      initialized = diffieHellman->Init(args[0]->Int32Value());
 +    } else {
 +      initialized = diffieHellman->Init(
 +              reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
 +              Buffer::Length(args[0]));
      }
 +  }
  
 -    ssize_t hlen = StringBytes::Size(args[1], encoding);
 +  if (!initialized) {
 +    return ThrowError("Initialization failed");
 +  }
  
 -    if (hlen < 0) {
 -      delete[] kbuf;
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  diffieHellman->Wrap(args.This());
  
 -    unsigned char* hbuf = new unsigned char[hlen];
 -    ssize_t hwritten = StringBytes::Write(
 -        reinterpret_cast<char*>(hbuf), hlen, args[1], encoding);
 -    assert(hwritten == hlen);
 +  return args.This();
 +}
  
 -    int r;
 -    r = verify->VerifyFinal(kbuf, klen, hbuf, hlen);
  
 -    delete[] kbuf;
 -    delete[] hbuf;
 +Handle<Value> DiffieHellman::GenerateKeys(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    return Boolean::New(r && r != -1);
 -  }
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -  Verify () : ObjectWrap () {
 -    initialised_ = false;
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  ~Verify () {
 -    if (initialised_) {
 -      EVP_MD_CTX_cleanup(&mdctx);
 -    }
 +  if (!DH_generate_key(diffieHellman->dh)) {
 +    return ThrowError("Key generation failed");
    }
  
 - private:
 +  Local<Value> outString;
  
 -  EVP_MD_CTX mdctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 +  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));
  
 -};
 -
 -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);
 +  outString = Encode(data, dataSize, BUFFER);
 +  delete[] data;
  
 -    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);
 +  return scope.Close(outString);
 +}
  
 -    target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction());
  
 -    Local<FunctionTemplate> t2 = FunctionTemplate::New(DiffieHellmanGroup);
 -    t2->InstanceTemplate()->SetInternalFieldCount(1);
 +Handle<Value> DiffieHellman::GetPrime(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    NODE_SET_PROTOTYPE_METHOD(t2, "generateKeys", GenerateKeys);
 -    NODE_SET_PROTOTYPE_METHOD(t2, "computeSecret", ComputeSecret);
 -    NODE_SET_PROTOTYPE_METHOD(t2, "getPrime", GetPrime);
 -    NODE_SET_PROTOTYPE_METHOD(t2, "getGenerator", GetGenerator);
 -    NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey);
 -    NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey);
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction());
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  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;
 -  }
 +  int dataSize = BN_num_bytes(diffieHellman->dh->p);
 +  char* data = new char[dataSize];
 +  BN_bn2bin(diffieHellman->dh->p, reinterpret_cast<unsigned char*>(data));
  
 -  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;
 -  }
 +  Local<Value> outString;
  
 -  bool Init(unsigned char* p, int p_len, unsigned char* g, int g_len) {
 -    dh = DH_new();
 -    dh->p = BN_bin2bn(p, p_len, 0);
 -    dh->g = BN_bin2bn(g, g_len, 0);
 -    initialised_ = true;
 -    return true;
 -  }
 +  outString = Encode(data, dataSize, BUFFER);
  
 - protected:
 -  static Handle<Value> DiffieHellmanGroup(const Arguments& args) {
 -    HandleScope scope;
 +  delete[] data;
  
 -    DiffieHellman* diffieHellman = new DiffieHellman();
 +  return scope.Close(outString);
 +}
  
 -    if (args.Length() != 1 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(
 -          String::New("No group name given")));
 -    }
  
 -    String::Utf8Value group_name(args[0]);
 +Handle<Value> DiffieHellman::GetGenerator(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    modp_group* it = modp_groups;
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    while(it->name != NULL) {
 -      if (!strcasecmp(*group_name, it->name))
 -          break;
 -      it++;
 -    }
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
 +  }
  
 -    if (it->name != NULL) {
 -      diffieHellman->Init(it->prime, it->prime_size,
 -              it->gen, it->gen_size);
 -    } else {
 -      return ThrowException(Exception::Error(
 -          String::New("Unknown group")));
 -    }
 +  int dataSize = BN_num_bytes(diffieHellman->dh->g);
 +  char* data = new char[dataSize];
 +  BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data));
  
 -    diffieHellman->Wrap(args.This());
 +  Local<Value> outString;
  
 -    return args.This();
 -  }
 +  outString = Encode(data, dataSize, BUFFER);
  
 -  static Handle<Value> New(const Arguments& args) {
 -    HandleScope scope;
 +  delete[] data;
  
 -    DiffieHellman* diffieHellman = new DiffieHellman();
 -    bool initialized = false;
 +  return scope.Close(outString);
 +}
  
 -    if (args.Length() > 0) {
 -      if (args[0]->IsInt32()) {
 -        initialized = diffieHellman->Init(args[0]->Int32Value());
 -      } else {
 -        initialized = diffieHellman->Init(
 -                reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
 -                Buffer::Length(args[0]));
 -      }
 -    }
  
 -    if (!initialized) {
 -      return ThrowException(Exception::Error(
 -            String::New("Initialization failed")));
 -    }
 +Handle<Value> DiffieHellman::GetPublicKey(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    diffieHellman->Wrap(args.This());
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    return args.This();
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  static Handle<Value> GenerateKeys(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 +  if (diffieHellman->dh->pub_key == NULL) {
 +    return ThrowError("No public key - did you forget to generate one?");
 +  }
  
 -    HandleScope scope;
 +  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 (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(
 -            String::New("Not initialized")));
 -    }
 +  Local<Value> outString;
  
 -    if (!DH_generate_key(diffieHellman->dh)) {
 -      return ThrowException(Exception::Error(
 -            String::New("Key generation failed")));
 -    }
 +  outString = Encode(data, dataSize, BUFFER);
  
 -    Local<Value> outString;
 +  delete[] data;
  
 -    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));
 +  return scope.Close(outString);
 +}
  
 -    outString = Encode(data, dataSize, BUFFER);
 -    delete[] data;
  
 -    return scope.Close(outString);
 -  }
 +Handle<Value> DiffieHellman::GetPrivateKey(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> GetPrime(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 +  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;
 -
 -    outString = Encode(data, dataSize, BUFFER);
 -
 -    delete[] data;
 -
 -    return scope.Close(outString);
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  static Handle<Value> GetGenerator(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 +  if (diffieHellman->dh->priv_key == NULL) {
 +    return ThrowError("No private key - did you forget to generate one?");
 +  }
  
 -    HandleScope scope;
 +  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));
  
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 +  Local<Value> outString;
  
 -    int dataSize = BN_num_bytes(diffieHellman->dh->g);
 -    char* data = new char[dataSize];
 -    BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data));
 +  outString = Encode(data, dataSize, BUFFER);
  
 -    Local<Value> outString;
 +  delete[] data;
  
 -    outString = Encode(data, dataSize, BUFFER);
 +  return scope.Close(outString);
 +}
  
 -    delete[] data;
  
 -    return scope.Close(outString);
 -  }
 +Handle<Value> DiffieHellman::ComputeSecret(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> GetPublicKey(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 +  DiffieHellman* diffieHellman =
        ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    HandleScope scope;
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
 +  }
  
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
++  ClearErrorOnReturn clear_error_on_return;
++  (void) &clear_error_on_return;  // Silence compiler warning.
 +  BIGNUM* key = NULL;
  
 -    if (diffieHellman->dh->pub_key == NULL) {
 -      return ThrowException(Exception::Error(
 -            String::New("No public key - did you forget to generate one?")));
 -    }
 +  if (args.Length() == 0) {
 +    return ThrowError("First argument must be other party's public key");
 +  } else {
 +    ASSERT_IS_BUFFER(args[0]);
 +    key = BN_bin2bn(
 +        reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
 +        Buffer::Length(args[0]),
 +        0);
 +  }
  
 -    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));
 +  int dataSize = DH_size(diffieHellman->dh);
 +  char* data = new char[dataSize];
  
 -    Local<Value> outString;
 +  int size = DH_compute_key(reinterpret_cast<unsigned char*>(data),
 +                            key,
 +                            diffieHellman->dh);
  
 -    outString = Encode(data, dataSize, BUFFER);
 +  if (size == -1) {
 +    int checkResult;
 +    int checked;
  
 +    checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult);
 +    BN_free(key);
      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 (!checked) {
 +      return ThrowError("Invalid key");
 +    } else if (checkResult) {
 +      if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) {
 +        return ThrowError("Supplied key is too small");
 +      } else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) {
 +        return ThrowError("Supplied key is too large");
 +      } else {
 +        return ThrowError("Invalid key");
 +      }
 +    } else {
 +      return ThrowError("Invalid key");
      }
 +  }
  
 -    if (diffieHellman->dh->priv_key == NULL) {
 -      return ThrowException(Exception::Error(
 -            String::New("No private key - did you forget to generate one?")));
 -    }
 +  BN_free(key);
 +  assert(size >= 0);
  
 -    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));
 +  // DH_size returns number of bytes in a prime number
 +  // DH_compute_key returns number of bytes in a remainder of exponent, which
 +  // may have less bytes than a prime number. Therefore add 0-padding to the
 +  // allocated buffer.
 +  if (size != dataSize) {
 +    assert(dataSize > size);
 +    memmove(data + dataSize - size, data, size);
 +    memset(data, 0, dataSize - size);
 +  }
  
 -    Local<Value> outString;
 +  Local<Value> outString;
  
 -    outString = Encode(data, dataSize, BUFFER);
 +  outString = Encode(data, dataSize, BUFFER);
  
 -    delete[] data;
 +  delete[] data;
 +  return scope.Close(outString);
 +}
  
 -    return scope.Close(outString);
 -  }
  
 -  static Handle<Value> ComputeSecret(const Arguments& args) {
 -    HandleScope scope;
 +Handle<Value> DiffieHellman::SetPublicKey(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    DiffieHellman* diffieHellman =
 +  DiffieHellman* diffieHellman =
        ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 -
 -    ClearErrorOnReturn clear_error_on_return;
 -    (void) &clear_error_on_return;  // Silence compiler warning.
 -    BIGNUM* key = 0;
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
 +  }
  
 -    if (args.Length() == 0) {
 -      return ThrowException(Exception::Error(
 -            String::New("First argument must be other party's public key")));
 -    } else {
 -      ASSERT_IS_BUFFER(args[0]);
 -      key = BN_bin2bn(
 +  if (args.Length() == 0) {
 +    return ThrowError("First argument must be public key");
 +  } else {
 +    ASSERT_IS_BUFFER(args[0]);
 +    diffieHellman->dh->pub_key = BN_bin2bn(
          reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
          Buffer::Length(args[0]), 0);
 -    }
 -
 -    int dataSize = DH_size(diffieHellman->dh);
 -    char* data = new char[dataSize];
 -
 -    int size = DH_compute_key(reinterpret_cast<unsigned char*>(data),
 -      key, diffieHellman->dh);
 -
 -    if (size == -1) {
 -      int checkResult;
 -      int checked;
 -
 -      checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult);
 -      BN_free(key);
 -      delete[] data;
 -
 -      if (!checked) {
 -        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")));
 -      }
 -    }
 -
 -    BN_free(key);
 -    assert(size >= 0);
 -
 -    // DH_size returns number of bytes in a prime number
 -    // DH_compute_key returns number of bytes in a remainder of exponent, which
 -    // may have less bytes than a prime number. Therefore add 0-padding to the
 -    // allocated buffer.
 -    if (size != dataSize) {
 -      assert(dataSize > size);
 -      memmove(data + dataSize - size, data, size);
 -      memset(data, 0, dataSize - size);
 -    }
 -
 -    Local<Value> outString;
 -
 -    outString = Encode(data, dataSize, BUFFER);
 -
 -    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 {
 -      ASSERT_IS_BUFFER(args[0]);
 -      diffieHellman->dh->pub_key =
 -        BN_bin2bn(
 -          reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
 -          Buffer::Length(args[0]), 0);
 -    }
 +  return args.This();
 +}
  
 -    return args.This();
 -  }
  
 -  static Handle<Value> SetPrivateKey(const Arguments& args) {
 -    HandleScope scope;
 +Handle<Value> DiffieHellman::SetPrivateKey(const Arguments& args) {
 +  HandleScope scope(node_isolate);
  
 -    DiffieHellman* diffieHellman =
 +  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 {
 -      ASSERT_IS_BUFFER(args[0]);
 -      diffieHellman->dh->priv_key =
 -        BN_bin2bn(
 -          reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
 -          Buffer::Length(args[0]), 0);
 -    }
 -
 -    return args.This();
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  DiffieHellman() : ObjectWrap() {
 -    initialised_ = false;
 -    dh = NULL;
 +  if (args.Length() == 0) {
 +    return ThrowError("First argument must be private key");
 +  } else {
 +    ASSERT_IS_BUFFER(args[0]);
 +    diffieHellman->dh->priv_key = BN_bin2bn(
 +        reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
 +        Buffer::Length(args[0]),
 +        0);
    }
  
 -  ~DiffieHellman() {
 -    if (dh != NULL) {
 -      DH_free(dh);
 -    }
 -  }
 +  return args.This();
 +}
  
 - 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;
 -  }
  
 -  bool initialised_;
 -  DH* dh;
 -};
 +bool DiffieHellman::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;
 +}
  
  
  struct pbkdf2_req {
Simple merge
Simple merge