Merge remote-tracking branch 'origin/v0.10'
authorBen Noordhuis <info@bnoordhuis.nl>
Tue, 30 Jul 2013 13:19:48 +0000 (15:19 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Tue, 30 Jul 2013 13:19:48 +0000 (15:19 +0200)
Conflicts:
AUTHORS
ChangeLog
deps/uv/ChangeLog
deps/uv/src/version.c
deps/uv/src/win/fs.c
src/node.cc
src/node_crypto.cc
src/node_os.cc
src/node_version.h

1  2 
AUTHORS
ChangeLog
doc/api/events.markdown
doc/api/fs.markdown
doc/api/tls.markdown
src/node_crypto.cc
src/node_file.cc
src/node_os.cc
src/string_bytes.cc
test/simple/test-crypto.js

diff --cc AUTHORS
+++ b/AUTHORS
@@@ -431,12 -431,8 +431,13 @@@ JeongHoon Byun <outsideris@gmail.com
  Iskren Ivov Chernev <iskren.chernev@gmail.com>
  Alexey Kupershtokh <alexey.kupershtokh@gmail.com>
  Benjamin Ruston <benjy.ruston@gmail.com>
 +Manav Rathi <manav.r@directi.com>
 +Marcin Kostrzewa <marcinkostrzewa@yahoo.com>
 +Suwon Chae <doortts@gmail.com>
 +David Braun <NodeJS-box@snkmail.com>
  Mitar Milutinovic <mitar.git@tnode.com>
  Michael Hart <michael.hart.au@gmail.com>
++Jeff Barczewski <jeff.barczewski@gmail.com>
  Andrew Hart <hartandrewr@gmail.com>
  Rafael Garcia <rgarcia2009@gmail.com>
  Tobias Müllerleile <tobias@muellerleile.net>
@@@ -461,7 -455,5 +462,7 @@@ Daniel G. Taylor <dan@programmer-art.or
  Kiyoshi Nomo <tokyoincidents.g@gmail.com>
  Veres Lajos <vlajos@gmail.com>
  Yuan Chuan <yuanchuan23@gmail.com>
 +Krzysztof Chrapka <chrapka.k@gmail.com>
 +Linus Mårtensson <linus.martensson@sonymobile.com>
  Peter Rust <peter@cornerstonenw.com>
Jeff Barczewski <jeff.barczewski@gmail.com>
Shuan Wang <shuanwang@gmail.com>
diff --cc ChangeLog
+++ b/ChangeLog
+ 2013.07.25, Version 0.10.15 (Stable)
+ * src: fix process.getuid() return value (Ben Noordhuis)
+ 2013.07.25, Version 0.10.14 (Stable), fdf57f811f9683a4ec49a74dc7226517e32e6c9d
+ * uv: Upgrade to v0.10.13
+ * npm: Upgrade to v1.3.5
+ * os: Don't report negative times in cpu info (Ben Noordhuis)
+ * fs: Handle large UID and GID (Ben Noordhuis)
+ * url: Fix edge-case when protocol is non-lowercase (Shuan Wang)
+ * doc: Streams API Doc Rewrite (isaacs)
+ * node: call MakeDomainCallback in all domain cases (Trevor Norris)
+ * crypto: fix memory leak in LoadPKCS12 (Fedor Indutny)
 +2013.07.12, Version 0.11.4 (Unstable)
 +
 +* npm: Upgrade to 1.3.4
 +
 +* v8: Upgrade to v3.20.2
 +
 +* c-ares: Upgrade to piscisaureus/cares@805d153
 +
 +* timers: setImmediate process full queue each turn (Ben Noordhuis)
 +
 +* http: Add agent.get/request methods (isaacs)
 +
 +* http: Proper KeepAlive behavior (isaacs)
 +
 +* configure: fix the --without-ssl option (Nathan Rajlich)
 +
 +* buffer: propagate originating parent (Trevor Norris)
 +
 +* tls_wrap: return Error not throw for missing cert (Timothy J Fontaine)
 +
 +* src: enable native v8 typed arrays (Ben Noordhuis)
 +
 +* stream: objectMode transform should allow falsey values (Jeff Barczewski)
 +
 +* slab_allocator: remove SlabAllocator (Trevor Norris)
 +
 +* crypto: fix memory leak in LoadPKCS12 (Fedor Indutny)
 +
 +* tls: export TLSSocket (Fedor Indutny)
 +
 +* zlib: allow changing of level and strategy (Brian White)
 +
 +* zlib: allow custom flush type for flush() (Brian White)
 +
 +
 +2013.06.26, Version 0.11.3 (Unstable), 38c0c47bbe280ddc42054418091571e532d82a1e
 +
 +* uv: Upgrade to v0.11.5
 +
 +* c-ares: upgrade to 1.10.0
 +
 +* v8: upgrade to v3.19.13
 +
 +* punycode: update to v1.2.3 (Mathias Bynens)
 +
 +* debugger: break on uncaught exception (Miroslav Bajtos)
 +
 +* child_process: emit 'disconnect' asynchronously (Ben Noordhuis)
 +
 +* dtrace: enable uv's probes if enabled (Timothy J Fontaine)
 +
 +* dtrace: unify dtrace and systemtap interfaces (Timothy J Fontaine)
 +
 +* buffer: New API for backing data store (Trevor Norris)
 +
 +* buffer: return `this` in fill() for chainability (Brian White)
 +
 +* build: fix include order for building on windows (Timothy J Fontaine)
 +
 +* build: add android support (Linus Mårtensson)
 +
 +* readline: strip ctrl chars for prompt width calc (Krzysztof Chrapka)
 +
 +* tls: introduce TLSSocket based on tls_wrap binding (Fedor Indutny)
 +
 +* tls: add localAddress and localPort properties (Ben Noordhuis)
 +
 +* crypto: free excessive memory in NodeBIO (Fedor Indutny)
 +
 +* process: remove maxTickDepth (Trevor Norris)
 +
 +* timers: use uv_now instead of Date.now (Timothy J Fontaine)
 +
 +* util: Add debuglog, deprecate console lookalikes (isaacs)
 +
 +* module: use path.sep instead of a custom solution (Robert Kowalski)
 +
 +* http: don't escape request path, reject bad chars (Ben Noordhuis)
 +
 +* net: emit dns 'lookup' event before connect (Ben Noordhuis)
 +
 +* dns: add getServers and setServers (Timothy J Fontaine)
 +
 +
 +2013.05.13, Version 0.11.2 (Unstable), 5d3dc0e4c3369dfb00b7b13e08936c2e652fa696
 +
 +* 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.03.28, Version 0.11.0 (Unstable), bce38b3d74e64fcb7d04a2dd551151da6168cdc5
 +
 +* V8: update to 3.17.13
 +
 +* os: use %SystemRoot% or %windir% in os.tmpdir() (Suwon Chae)
 +
 +* util: fix util.inspect() line width calculation (Marcin Kostrzewa)
 +
 +* buffer: remove _charsWritten (Trevor Norris)
 +
 +* fs: uv_[fl]stat now reports subsecond resolution (Timothy J Fontaine)
 +
 +* fs: Throw if error raised and missing callback (bnoordhuis)
 +
 +* tls: expose SSL_CTX_set_timeout via tls.createServer (Manav Rathi)
 +
 +* tls: remove harmful unnecessary bounds checking (Marcel Laverdet)
 +
 +* buffer: write ascii strings using WriteOneByte (Trevor Norris)
 +
 +* dtrace: fix generation of v8 constants on freebsd (Fedor Indutny)
 +
 +* dtrace: x64 ustack helper (Fedor Indutny)
 +
 +* readline: handle wide characters properly (Nao Iizuka)
 +
 +* repl: Use a domain to catch async errors safely (isaacs)
 +
 +* repl: emit 'reset' event when context is reset (Sami Samhuri)
 +
 +* util: custom `inspect()` method may return an Object (Nathan Rajlich)
 +
 +* console: `console.dir()` bypasses inspect() methods (Nathan Rajlich)
 +
 +
  2013.07.09, Version 0.10.13 (Stable), e32660a984427d46af6a144983cf7b8045b7299c
  
  * uv: Upgrade to v0.10.12
Simple merge
Simple merge
Simple merge
@@@ -2065,1175 -2058,1736 +2065,1190 @@@ void Connection::SetSNICallback(const F
  #endif
  
  
 -class Cipher : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
 +void CipherBase::Initialize(Handle<Object> target) {
 +  HandleScope scope(node_isolate);
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    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);
 +  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);
  
 -    target->Set(String::NewSymbol("Cipher"), t->GetFunction());
 -  }
 +  target->Set(String::NewSymbol("CipherBase"), t->GetFunction());
 +}
  
  
 -  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;
 -    }
 +void CipherBase::New(const FunctionCallbackInfo<Value>& args) {
 +  assert(args.IsConstructCall() == true);
 +  HandleScope scope(node_isolate);
 +  CipherBase* cipher = new CipherBase(args[0]->IsTrue() ? kCipher : kDecipher);
 +  cipher->Wrap(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, 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;
 -  }
 +void CipherBase::Init(char* cipher_type, char* key_buf, int key_buf_len) {
 +  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);
 +  assert(cipher_ == NULL);
 +  cipher_ = EVP_get_cipherbyname(cipher_type);
 +  if (cipher_ == NULL) {
 +    return ThrowError("Unknown cipher");
    }
  
 -  int SetAutoPadding(bool auto_padding) {
 -    if (!initialised_) return 0;
 -    return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
 -  }
 +  unsigned char key[EVP_MAX_KEY_LENGTH];
 +  unsigned char iv[EVP_MAX_IV_LENGTH];
  
 -  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;
 +  int key_len = EVP_BytesToKey(cipher_,
 +                               EVP_md5(),
 +                               NULL,
 +                               reinterpret_cast<unsigned char*>(key_buf),
 +                               key_buf_len,
 +                               1,
 +                               key,
 +                               iv);
 +
 +  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");
    }
  
 +  EVP_CipherInit_ex(&ctx_,
 +                    NULL,
 +                    NULL,
 +                    reinterpret_cast<unsigned char*>(key),
 +                    reinterpret_cast<unsigned char*>(iv),
 +                    kind_ == kCipher);
 +  initialised_ = true;
 +}
 +
  
 - protected:
 +void CipherBase::Init(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> New(const Arguments& args) {
 -    HandleScope scope;
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    Cipher *cipher = new Cipher();
 -    cipher->Wrap(args.This());
 -    return args.This();
 +  if (args.Length() < 2 ||
 +      !(args[0]->IsString() && Buffer::HasInstance(args[1]))) {
 +    return ThrowError("Must give cipher-type, key");
    }
  
 -  static Handle<Value> CipherInit(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 +  String::Utf8Value cipher_type(args[0]);
 +  char* key_buf = Buffer::Data(args[1]);
 +  ssize_t key_buf_len = Buffer::Length(args[1]);
 +  cipher->Init(*cipher_type, key_buf, key_buf_len);
 +}
  
 -    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")));
 -    }
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_buf_len = Buffer::Length(args[1]);
 +void CipherBase::InitIv(char* cipher_type,
 +                        char* key,
 +                        int key_len,
 +                        char* iv,
 +                        int iv_len) {
 +  HandleScope scope(node_isolate);
  
 -    if (key_buf_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  cipher_ = EVP_get_cipherbyname(cipher_type);
 +  if (cipher_ == NULL) {
 +    return ThrowError("Unknown cipher");
 +  }
  
 -    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);
 +  /* 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");
 +  }
  
 -    String::Utf8Value cipherType(args[0]);
 +  EVP_CipherInit_ex(&ctx_,
 +                    NULL,
 +                    NULL,
 +                    reinterpret_cast<unsigned char*>(key),
 +                    reinterpret_cast<unsigned char*>(iv),
 +                    kind_ == kCipher);
 +  initialised_ = true;
 +}
  
 -    bool r = cipher->CipherInit(*cipherType, key_buf, key_buf_len);
  
 -    delete [] key_buf;
 +void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) return ThrowCryptoError(ERR_get_error());
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    return args.This();
 +  if (args.Length() < 3 || !args[0]->IsString()) {
 +    return ThrowError("Must give cipher-type, key, and iv as argument");
    }
  
-     size_t buflen = StringBytes::StorageSize(args[0], encoding);
 +  ASSERT_IS_BUFFER(args[1]);
 +  ASSERT_IS_BUFFER(args[2]);
 +
 +  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]);
 +  cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len);
 +}
 +
 +
 +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);
 +}
 +
 +
 +void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
 +
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
 +
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +
 +  unsigned char* out = NULL;
 +  bool r;
 +  int out_len = 0;
 +
 +  // Only copy the data if we have to, because it's a string
 +  if (args[0]->IsString()) {
++    Local<String> string = args[0].As<String>();
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
-     size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++    if (!StringBytes::IsValidString(string, encoding))
++      return ThrowTypeError("Bad input string");
++    size_t buflen = StringBytes::StorageSize(string, encoding);
 +    char* buf = new char[buflen];
++    size_t written = StringBytes::Write(buf, buflen, string, 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> CipherInitIv(const Arguments& args) {
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 +  if (!r) {
 +    delete[] out;
 +    return ThrowCryptoTypeError(ERR_get_error());
 +  }
  
 -    HandleScope scope;
 +  Local<Object> buf = Buffer::New(reinterpret_cast<char*>(out), out_len);
 +  if (out) delete[] out;
  
 +  args.GetReturnValue().Set(buf);
 +}
  
 -    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")));
 -    }
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_len = Buffer::Length(args[1]);
 +bool CipherBase::SetAutoPadding(bool auto_padding) {
 +  if (!initialised_) return false;
 +  return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding);
 +}
  
 -    if (key_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
  
 -    ASSERT_IS_BUFFER(args[2]);
 -    ssize_t iv_len = Buffer::Length(args[2]);
 +void CipherBase::SetAutoPadding(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
 +  cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
 +}
  
 -    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 CipherBase::Final(unsigned char** out, int *out_len) {
 +  if (!initialised_) return false;
  
 -    char* iv_buf = new char[iv_len];
 -    ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY);
 -    assert(iv_written == iv_len);
 +  *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;
  
 -    String::Utf8Value cipherType(args[0]);
 +  return r;
 +}
  
 -    bool r = cipher->CipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
  
 -    delete [] key_buf;
 -    delete [] iv_buf;
 +void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) return ThrowCryptoError(ERR_get_error());
 +  CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
  
 -    return args.This();
 -  }
 +  unsigned char* out_value = NULL;
 +  int out_len = -1;
 +  Local<Value> outString;
  
 -  static Handle<Value> CipherUpdate(const Arguments& args) {
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 +  bool r = cipher->Final(&out_value, &out_len);
  
 -    HandleScope scope;
 +  if (out_len <= 0 || !r) {
 +    delete[] out_value;
 +    out_value = NULL;
 +    out_len = 0;
 +    if (!r) return ThrowCryptoTypeError(ERR_get_error());
 +  }
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +  args.GetReturnValue().Set(
 +      Buffer::New(reinterpret_cast<char*>(out_value), out_len));
 +}
  
 -    // 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()) {
 -      Local<String> string = args[0].As<String>();
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      if (!StringBytes::IsValidString(string, encoding))
 -        return ThrowTypeError("Bad input string");
 -      size_t buflen = StringBytes::StorageSize(string, encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, string, 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);
 -    }
  
 -    if (r == 0) {
 -      delete[] out;
 -      return ThrowCryptoTypeError(ERR_get_error());
 -    }
 +void Hmac::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -    Local<Value> outString;
 -    outString = Encode(out, out_len, BUFFER);
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    if (out) delete[] out;
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    return scope.Close(outString);
 -  }
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest);
  
 -  static Handle<Value> SetAutoPadding(const Arguments& args) {
 -    HandleScope scope;
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
 +  target->Set(String::NewSymbol("Hmac"), t->GetFunction());
 +}
  
 -    cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
  
 -    return Undefined();
 -  }
 +void Hmac::New(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
 +  Hmac* hmac = new Hmac();
 +  hmac->Wrap(args.This());
 +}
  
 -  static Handle<Value> CipherFinal(const Arguments& args) {
 -    Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
  
 -    HandleScope scope;
 +void Hmac::HmacInit(char* hashType, char* key, int key_len) {
 +  HandleScope scope(node_isolate);
  
 -    unsigned char* out_value = NULL;
 -    int out_len = -1;
 -    Local<Value> outString ;
 +  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;
 +}
  
 -    int r = cipher->CipherFinal(&out_value, &out_len);
  
 -    if (out_len <= 0 || r == 0) {
 -      delete[] out_value;
 -      out_value = NULL;
 -      if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
 -    }
 +void Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    outString = Encode(out_value, out_len, BUFFER);
 +  Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    delete [] out_value;
 -    return scope.Close(outString);
 +  if (args.Length() < 2 || !args[0]->IsString()) {
 +    return ThrowError("Must give hashtype string, key as arguments");
    }
  
 -  Cipher () : ObjectWrap ()
 -  {
 -    initialised_ = false;
 -  }
 +  ASSERT_IS_BUFFER(args[1]);
  
 -  ~Cipher () {
 -    if (initialised_) {
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -    }
 -  }
 +  String::Utf8Value hashType(args[0]);
  
 - private:
 +  char* buffer_data = Buffer::Data(args[1]);
 +  size_t buffer_length = Buffer::Length(args[1]);
 +  hmac->HmacInit(*hashType, buffer_data, buffer_length);
 +}
  
 -  EVP_CIPHER_CTX ctx; /* coverity[member_decl] */
 -  const EVP_CIPHER *cipher; /* coverity[member_decl] */
 -  bool initialised_;
 -};
  
 +bool Hmac::HmacUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  HMAC_Update(&ctx_, reinterpret_cast<unsigned char*>(data), len);
 +  return true;
 +}
  
  
 -class Decipher : public ObjectWrap {
 - public:
 -  static void
 -  Initialize (v8::Handle<v8::Object> target)
 -  {
 -    HandleScope scope;
 +void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +  Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    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);
 +  // Only copy the data if we have to, because it's a string
 +  bool r;
 +  if (args[0]->IsString()) {
++    Local<String> string = args[0].As<String>();
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
-     size_t buflen = StringBytes::StorageSize(args[0], encoding);
++    if (!StringBytes::IsValidString(string, encoding))
++      return ThrowTypeError("Bad input string");
++    size_t buflen = StringBytes::StorageSize(string, encoding);
 +    char* buf = new char[buflen];
-     size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++    size_t written = StringBytes::Write(buf, buflen, string, 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);
 +  }
  
 -    target->Set(String::NewSymbol("Decipher"), t->GetFunction());
 +  if (!r) {
 +    return ThrowTypeError("HmacUpdate fail");
    }
 +}
  
 -  bool DecipherInit(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;
 -    }
 +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;
 +}
  
 -    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;
 -    }
  
 -    *out_len = len+EVP_CIPHER_CTX_block_size(&ctx);
 -    *out = new unsigned char[*out_len];
 +void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
 +
 +  Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
  
 -    return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len);
 +  enum encoding encoding = BUFFER;
 +  if (args.Length() >= 1) {
 +    encoding = ParseEncoding(args[0]->ToString(), BUFFER);
    }
  
 -  int SetAutoPadding(bool auto_padding) {
 -    if (!initialised_) return 0;
 -    return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
 +  unsigned char* md_value = NULL;
 +  unsigned int md_len = 0;
 +
 +  bool r = hmac->HmacDigest(&md_value, &md_len);
 +  if (!r) {
 +    md_value = NULL;
 +    md_len = 0;
    }
  
 -  // coverity[alloc_arg]
 -  int DecipherFinal(unsigned char** out, int *out_len) {
 -    int r;
 +  Local<Value> rc = StringBytes::Encode(
 +        reinterpret_cast<const char*>(md_value), md_len, encoding);
 +  delete[] md_value;
 +  args.GetReturnValue().Set(rc);
 +}
  
 -    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 Hash::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, "update", HashUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest);
  
 -    Decipher *cipher = new Decipher();
 -    cipher->Wrap(args.This());
 -    return args.This();
 -  }
 +  target->Set(String::NewSymbol("Hash"), t->GetFunction());
 +}
  
 -  static Handle<Value> DecipherInit(const Arguments& args) {
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
  
 -    HandleScope scope;
 +void Hash::New(const FunctionCallbackInfo<Value>& 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")));
 -    }
 +  if (args.Length() == 0 || !args[0]->IsString()) {
 +    return ThrowError("Must give hashtype string as argument");
 +  }
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_len = Buffer::Length(args[1]);
 +  String::Utf8Value hashType(args[0]);
  
 -    if (key_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  Hash* hash = new Hash();
 +  if (!hash->HashInit(*hashType)) {
 +    delete hash;
 +    return ThrowError("Digest method not supported");
 +  }
  
 -    char* key_buf = new char[key_len];
 -    ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
 -    assert(key_written == key_len);
 +  hash->Wrap(args.This());
 +}
  
 -    String::Utf8Value cipherType(args[0]);
  
 -    bool r = cipher->DecipherInit(*cipherType, key_buf,key_len);
 +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;
 +}
  
 -    delete [] key_buf;
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("DecipherInit error")));
 -    }
 +bool Hash::HashUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  EVP_DigestUpdate(&mdctx_, data, len);
 +  return true;
 +}
  
 -    return args.This();
 -  }
  
 -  static Handle<Value> DecipherInitIv(const Arguments& args) {
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
 +void Hash::HashUpdate(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    HandleScope scope;
 +  Hash* hash = ObjectWrap::Unwrap<Hash>(args.This());
  
 -    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")));
 -    }
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t key_len = Buffer::Length(args[1]);
 +  // Only copy the data if we have to, because it's a string
 +  bool r;
 +  if (args[0]->IsString()) {
++    Local<String> string = args[0].As<String>();
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
-     size_t buflen = StringBytes::StorageSize(args[0], encoding);
++    if (!StringBytes::IsValidString(string, encoding))
++      return ThrowTypeError("Bad input string");
++    size_t buflen = StringBytes::StorageSize(string, encoding);
 +    char* buf = new char[buflen];
-     size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++    size_t written = StringBytes::Write(buf, buflen, string, 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);
 +  }
  
 -    if (key_len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 +  if (!r) {
 +    return ThrowTypeError("HashUpdate fail");
 +  }
 +}
  
 -    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);
 -    }
 +void Hash::HashDigest(const FunctionCallbackInfo<Value>& 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);
 +  Hash* hash = ObjectWrap::Unwrap<Hash>(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);
 +  if (!hash->initialised_) {
 +    return ThrowError("Not initialized");
 +  }
  
 -    String::Utf8Value cipherType(args[0]);
 +  enum encoding encoding = BUFFER;
 +  if (args.Length() >= 1) {
 +    encoding = ParseEncoding(args[0]->ToString(), BUFFER);
 +  }
  
 -    bool r = cipher->DecipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
 +  unsigned char md_value[EVP_MAX_MD_SIZE];
 +  unsigned int md_len;
  
 -    delete [] key_buf;
 -    delete [] iv_buf;
 +  EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len);
 +  EVP_MD_CTX_cleanup(&hash->mdctx_);
 +  hash->initialised_ = false;
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("DecipherInitIv error")));
 -    }
 +  Local<Value> rc = StringBytes::Encode(
 +      reinterpret_cast<const char*>(md_value), md_len, encoding);
 +  args.GetReturnValue().Set(rc);
 +}
  
 -    return args.This();
 -  }
  
 -  static Handle<Value> DecipherUpdate(const Arguments& args) {
 -    HandleScope scope;
 +void Sign::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    ASSERT_IS_STRING_OR_BUFFER(args[0]);
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    // 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()) {
 -      Local<String> string = args[0].As<String>();
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      if (!StringBytes::IsValidString(string, encoding))
 -        return ThrowTypeError("Bad input string");
 -      size_t buflen = StringBytes::StorageSize(string, encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, string, 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);
 -    }
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal);
  
 -    if (r == 0) {
 -      delete[] out;
 -      return ThrowCryptoTypeError(ERR_get_error());
 -    }
 +  target->Set(String::NewSymbol("Sign"), t->GetFunction());
 +}
 +
 +
 +void Sign::New(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
 +  Sign* sign = new Sign();
 +  sign->Wrap(args.This());
 +}
  
 -    Local<Value> outString;
 -    outString = Encode(out, out_len, BUFFER);
  
 -    if (out) delete [] out;
 +void Sign::SignInit(const char* sign_type) {
 +  HandleScope scope(node_isolate);
  
 -    return scope.Close(outString);
 +  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;
 +}
 +
  
 -  static Handle<Value> SetAutoPadding(const Arguments& args) {
 -    HandleScope scope;
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
 +void Sign::SignInit(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
 +  Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    return Undefined();
 +  if (args.Length() == 0 || !args[0]->IsString()) {
 +    return ThrowError("Must give signtype string as argument");
    }
  
 -  static Handle<Value> DecipherFinal(const Arguments& args) {
 -    HandleScope scope;
 +  String::Utf8Value sign_type(args[0]);
 +  sign->SignInit(*sign_type);
 +}
 +
  
 -    Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
 +bool Sign::SignUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  EVP_SignUpdate(&mdctx_, data, len);
 +  return true;
 +}
  
 -    unsigned char* out_value = NULL;
 -    int out_len = -1;
 -    Local<Value> outString;
  
 -    int r = cipher->DecipherFinal(&out_value, &out_len);
 +void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    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());
 -    }
 +  Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    outString = Encode(out_value, out_len, BUFFER);
 -    delete [] out_value;
 -    return scope.Close(outString);
 -  }
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -  Decipher () : ObjectWrap () {
 -    initialised_ = false;
 +  // Only copy the data if we have to, because it's a string
 +  int r;
 +  if (args[0]->IsString()) {
++    Local<String> string = args[0].As<String>();
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
-     size_t buflen = StringBytes::StorageSize(args[0], encoding);
++    if (!StringBytes::IsValidString(string, encoding))
++      return ThrowTypeError("Bad input string");
++    size_t buflen = StringBytes::StorageSize(string, encoding);
 +    char* buf = new char[buflen];
-     size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++    size_t written = StringBytes::Write(buf, buflen, string, 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);
    }
  
 -  ~Decipher () {
 -    if (initialised_) {
 -      EVP_CIPHER_CTX_cleanup(&ctx);
 -    }
 +  if (!r) {
 +    return ThrowTypeError("SignUpdate fail");
    }
 +}
  
 - private:
  
 -  EVP_CIPHER_CTX ctx;
 -  const EVP_CIPHER *cipher_;
 -  bool initialised_;
 -};
 +bool Sign::SignFinal(unsigned char** md_value,
 +                     unsigned int *md_len,
 +                     char* key_pem,
 +                     int key_pem_len) {
 +  if (!initialised_) return false;
  
 +  BIO* bp = NULL;
 +  EVP_PKEY* pkey = NULL;
 +  bp = BIO_new(BIO_s_mem());
 +  if (!BIO_write(bp, key_pem, key_pem_len)) return false;
  
 +  pkey = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
 +  if (pkey == NULL) return 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;
 +}
  
 -class Hmac : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest);
 +  unsigned char* md_value;
 +  unsigned int md_len;
  
 -    target->Set(String::NewSymbol("Hmac"), t->GetFunction());
 +  enum encoding encoding = BUFFER;
 +  if (args.Length() >= 2) {
 +    encoding = ParseEncoding(args[1]->ToString(), BUFFER);
    }
  
 -  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_BUFFER(args[0]);
 +  ssize_t len = Buffer::Length(args[0]);
 +  char* buf = Buffer::Data(args[0]);
  
 -  }
 +  md_len = 8192; // Maximum key size is 8192 bits
 +  md_value = new unsigned char[md_len];
  
 -  int HmacUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    HMAC_Update(&ctx, (unsigned char*)data, len);
 -    return 1;
 +  bool r = sign->SignFinal(&md_value, &md_len, buf, len);
 +  if (!r) {
 +    delete[] md_value;
 +    md_value = NULL;
 +    md_len = 0;
    }
  
 -  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;
 -  }
 +  Local<Value> rc = StringBytes::Encode(
 +      reinterpret_cast<const char*>(md_value), md_len, encoding);
 +  delete[] md_value;
 +  args.GetReturnValue().Set(rc);
 +}
  
  
 - protected:
 +void Verify::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    Hmac *hmac = new Hmac();
 -    hmac->Wrap(args.This());
 -    return args.This();
 -  }
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -  static Handle<Value> HmacInit(const Arguments& args) {
 -    Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
 +  NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit);
 +  NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate);
 +  NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal);
  
 -    HandleScope scope;
 +  target->Set(String::NewSymbol("Verify"), t->GetFunction());
 +}
  
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give hashtype string as argument")));
 -    }
  
 -    ASSERT_IS_BUFFER(args[1]);
 -    ssize_t len = Buffer::Length(args[1]);
 +void Verify::New(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
 +  Verify* verify = new Verify();
 +  verify->Wrap(args.This());
 +}
  
 -    if (len < 0) {
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
  
 -    String::Utf8Value hashType(args[0]);
 +void Verify::VerifyInit(const char* verify_type) {
 +  HandleScope scope(node_isolate);
  
 -    bool r;
 -
 -    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);
 -
 -      r = hmac->HmacInit(*hashType, buf, len);
 -
 -      delete [] buf;
 -    }
 -
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("hmac error")));
 -    }
 -
 -    return args.This();
 +  assert(md_ == NULL);
 +  md_ = EVP_get_digestbyname(verify_type);
 +  if (md_ == NULL) {
 +    return ThrowError("Unknown message digest");
    }
  
 -  static Handle<Value> HmacUpdate(const Arguments& args) {
 -    Hmac *hmac = ObjectWrap::Unwrap<Hmac>(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()) {
 -      Local<String> string = args[0].As<String>();
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      if (!StringBytes::IsValidString(string, encoding))
 -        return ThrowTypeError("Bad input string");
 -      size_t buflen = StringBytes::StorageSize(string, encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, string, 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);
 -    }
 -
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("HmacUpdate fail"));
 -      return ThrowException(exception);
 -    }
 -
 -    return args.This();
 -  }
 -
 -  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;
 -
 -    int r = hmac->HmacDigest(&md_value, &md_len);
 -    if (r == 0) {
 -      md_value = NULL;
 -      md_len = 0;
 -    }
 +  EVP_MD_CTX_init(&mdctx_);
 +  EVP_VerifyInit_ex(&mdctx_, md_, NULL);
 +  initialised_ = true;
 +}
  
 -    outString = StringBytes::Encode(
 -          reinterpret_cast<const char*>(md_value), md_len, encoding);
  
 -    delete[] md_value;
 -    return scope.Close(outString);
 -  }
 +void Verify::VerifyInit(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -  Hmac () : ObjectWrap () {
 -    initialised_ = false;
 -  }
 +  Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
  
 -  ~Hmac () {
 -    if (initialised_) {
 -      HMAC_CTX_cleanup(&ctx);
 -    }
 +  if (args.Length() == 0 || !args[0]->IsString()) {
 +    return ThrowError("Must give verifytype string as argument");
    }
  
 - private:
 -
 -  HMAC_CTX ctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 -};
 +  String::Utf8Value verify_type(args[0]);
 +  verify->VerifyInit(*verify_type);
 +}
  
  
 -class Hash : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
 +bool Verify::VerifyUpdate(char* data, int len) {
 +  if (!initialised_) return false;
 +  EVP_VerifyUpdate(&mdctx_, data, len);
 +  return true;
 +}
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +void Verify::VerifyUpdate(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest);
 +  Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
  
 -    target->Set(String::NewSymbol("Hash"), t->GetFunction());
 -  }
 +  ASSERT_IS_STRING_OR_BUFFER(args[0]);
  
 -  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;
 +  // Only copy the data if we have to, because it's a string
 +  bool r;
 +  if (args[0]->IsString()) {
++    Local<String> string = args[0].As<String>();
 +    enum encoding encoding = ParseEncoding(args[1], BINARY);
-     size_t buflen = StringBytes::StorageSize(args[0], encoding);
++    if (!StringBytes::IsValidString(string, encoding))
++      return ThrowTypeError("Bad input string");
++    size_t buflen = StringBytes::StorageSize(string, encoding);
 +    char* buf = new char[buflen];
-     size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++    size_t written = StringBytes::Write(buf, buflen, string, 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);
    }
  
 -  int HashUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    EVP_DigestUpdate(&mdctx, data, len);
 -    return 1;
 +  if (!r) {
 +    return ThrowTypeError("VerifyUpdate fail");
    }
 +}
  
  
 - protected:
 -
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 -
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give hashtype string as argument")));
 -    }
 -
 -    String::Utf8Value hashType(args[0]);
 +bool Verify::VerifyFinal(char* key_pem,
 +                         int key_pem_len,
 +                         unsigned char* sig,
 +                         int siglen) {
 +  HandleScope scope(node_isolate);
  
 -    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();
 +  if (!initialised_) {
 +    ThrowError("Verify not initalised");
 +    return false;
    }
  
 -  static Handle<Value> HashUpdate(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Hash *hash = ObjectWrap::Unwrap<Hash>(args.This());
 -
 -    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()) {
 -      Local<String> string = args[0].As<String>();
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      if (!StringBytes::IsValidString(string, encoding))
 -        return ThrowTypeError("Bad input string");
 -      size_t buflen = StringBytes::StorageSize(string, encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, string, 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);
 -    }
 -
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("HashUpdate fail"));
 -      return ThrowException(exception);
 +  EVP_PKEY* pkey = NULL;
 +  BIO* bp = NULL;
 +  X509* x509 = NULL;
 +  bool fatal = true;
 +  int r = 0;
 +
 +  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;
  
 -    return args.This();
 +    pkey = X509_get_pubkey(x509);
 +    if (pkey == NULL)
 +      goto exit;
    }
  
 -  static Handle<Value> HashDigest(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Hash *hash = ObjectWrap::Unwrap<Hash>(args.This());
 -
 -    if (!hash->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 -
 -    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;
 +  fatal = false;
 +  r = EVP_VerifyFinal(&mdctx_, sig, siglen, pkey);
  
 -    EVP_DigestFinal_ex(&hash->mdctx, md_value, &md_len);
 -    EVP_MD_CTX_cleanup(&hash->mdctx);
 -    hash->initialised_ = false;
 +exit:
 +  if (pkey != NULL)
 +    EVP_PKEY_free(pkey);
 +  if (bp != NULL)
 +    BIO_free_all(bp);
 +  if (x509 != NULL)
 +    X509_free(x509);
  
 -    return scope.Close(StringBytes::Encode(
 -          reinterpret_cast<const char*>(md_value), md_len, encoding));
 -  }
 +  EVP_MD_CTX_cleanup(&mdctx_);
 +  initialised_ = false;
  
 -  Hash () : ObjectWrap () {
 -    initialised_ = false;
 -  }
 -
 -  ~Hash () {
 -    if (initialised_) {
 -      EVP_MD_CTX_cleanup(&mdctx);
 -    }
 +  if (fatal) {
 +    unsigned long err = ERR_get_error();
 +    ThrowCryptoError(err);
 +    return false;
    }
  
 - private:
 -
 -  EVP_MD_CTX mdctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 -};
 +  return r == 1;
 +}
  
 -class Sign : public ObjectWrap {
 - public:
 -  static void
 -  Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
  
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
 +  Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal);
 +  ASSERT_IS_BUFFER(args[0]);
 +  char* kbuf = Buffer::Data(args[0]);
 +  ssize_t klen = Buffer::Length(args[0]);
  
 -    target->Set(String::NewSymbol("Sign"), 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 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;
 +  ssize_t hlen = StringBytes::Size(args[1], encoding);
  
 +  // 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]));
    }
  
 -  int SignUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    EVP_SignUpdate(&mdctx, data, len);
 -    return 1;
 +  bool rc = verify->VerifyFinal(kbuf, klen, hbuf, hlen);
 +  if (args[1]->IsString()) {
 +    delete[] hbuf;
    }
 +  args.GetReturnValue().Set(rc);
 +}
  
 -  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;
 -
 -    pkey = PEM_read_bio_PrivateKey( bp, NULL, NULL, NULL );
 -    if (pkey == NULL) return 0;
 -
 -    EVP_SignFinal(&mdctx, *md_value, md_len, pkey);
 -    EVP_MD_CTX_cleanup(&mdctx);
 -    initialised_ = false;
 -    EVP_PKEY_free(pkey);
 -    BIO_free(bp);
 -    return 1;
 -  }
  
 +void DiffieHellman::Initialize(v8::Handle<v8::Object> target) {
 +  HandleScope scope(node_isolate);
  
 - protected:
 +  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 +  t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    Sign *sign = new Sign();
 -    sign->Wrap(args.This());
 +  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 args.This();
 -  }
 +  target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction());
  
 -  static Handle<Value> SignInit(const Arguments& args) {
 -    HandleScope scope;
 +  Local<FunctionTemplate> t2 = FunctionTemplate::New(DiffieHellmanGroup);
 +  t2->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
 +  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);
  
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give signtype string as argument")));
 -    }
 +  target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction());
 +}
  
 -    String::Utf8Value signType(args[0]);
  
 -    bool r = sign->SignInit(*signType);
 +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;
 +}
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("SignInit error")));
 -    }
  
 -    return 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;
 +}
  
 -  static Handle<Value> SignUpdate(const Arguments& args) {
 -    Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
  
 -    HandleScope scope;
 +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;
 +}
  
 -    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()) {
 -      Local<String> string = args[0].As<String>();
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      if (!StringBytes::IsValidString(string, encoding))
 -        return ThrowTypeError("Bad input string");
 -      size_t buflen = StringBytes::StorageSize(string, encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, string, 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);
 -    }
 +void DiffieHellman::DiffieHellmanGroup(
 +    const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("SignUpdate fail"));
 -      return ThrowException(exception);
 -    }
 +  DiffieHellman* diffieHellman = new DiffieHellman();
  
 -    return args.This();
 +  if (args.Length() != 1 || !args[0]->IsString()) {
 +    return ThrowError("No group name given");
    }
  
 -  static Handle<Value> SignFinal(const Arguments& args) {
 -    Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
 +  String::Utf8Value group_name(args[0]);
  
 -    HandleScope scope;
 -
 -    unsigned char* md_value;
 -    unsigned int md_len;
 -    Local<Value> outString;
 -
 -    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);
 -    }
 +  modp_group* it = modp_groups;
  
 -    char* buf = new char[len];
 -    ssize_t written = DecodeWrite(buf, len, args[0], BUFFER);
 -    assert(written == len);
 -
 -    md_len = 8192; // Maximum key size is 8192 bits
 -    md_value = new unsigned char[md_len];
 -
 -    int r = sign->SignFinal(&md_value, &md_len, buf, len);
 -    if (r == 0) {
 -      md_value = NULL;
 -      md_len = r;
 -    }
 -
 -    delete [] buf;
 -
 -    outString = StringBytes::Encode(
 -        reinterpret_cast<const char*>(md_value), md_len, encoding);
 -
 -    delete [] md_value;
 -    return scope.Close(outString);
 -  }
 -
 -  Sign () : ObjectWrap () {
 -    initialised_ = false;
 +  while(it->name != NULL) {
 +    if (!strcasecmp(*group_name, it->name))
 +      break;
 +    it++;
    }
  
 -  ~Sign () {
 -    if (initialised_) {
 -      EVP_MD_CTX_cleanup(&mdctx);
 -    }
 +  if (it->name != NULL) {
 +    diffieHellman->Init(it->prime,
 +                        it->prime_size,
 +                        it->gen,
 +                        it->gen_size);
 +  } else {
 +    return ThrowError("Unknown group");
    }
  
 - private:
 -
 -  EVP_MD_CTX mdctx; /* coverity[member_decl] */
 -  const EVP_MD *md; /* coverity[member_decl] */
 -  bool initialised_;
 -};
 -
 -class Verify : public ObjectWrap {
 - public:
 -  static void Initialize (v8::Handle<v8::Object> target) {
 -    HandleScope scope;
 -
 -    Local<FunctionTemplate> t = FunctionTemplate::New(New);
 +  diffieHellman->Wrap(args.This());
 +}
  
 -    t->InstanceTemplate()->SetInternalFieldCount(1);
  
 -    NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit);
 -    NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate);
 -    NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal);
 +void DiffieHellman::New(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    target->Set(String::NewSymbol("Verify"), t->GetFunction());
 -  }
 +  DiffieHellman* diffieHellman = new DiffieHellman();
 +  bool initialized = false;
  
 -
 -  bool VerifyInit (const char* verifyType) {
 -    md = EVP_get_digestbyname(verifyType);
 -    if(!md) {
 -      fprintf(stderr, "node-crypto : Unknown message digest %s\n", verifyType);
 -      return false;
 +  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]));
      }
 -    EVP_MD_CTX_init(&mdctx);
 -    EVP_VerifyInit_ex(&mdctx, md, NULL);
 -    initialised_ = true;
 -    return true;
    }
  
 -
 -  int VerifyUpdate(char* data, int len) {
 -    if (!initialised_) return 0;
 -    EVP_VerifyUpdate(&mdctx, data, len);
 -    return 1;
 +  if (!initialized) {
 +    return ThrowError("Initialization failed");
    }
  
 +  diffieHellman->Wrap(args.This());
 +}
  
 -  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;
 -      }
 -
 -      pkey = X509_get_pubkey(x509);
 -      if (pkey == NULL) {
 -        ERR_print_errors_fp(stderr);
 -        return 0;
 -      }
 -    }
  
 -    r = EVP_VerifyFinal(&mdctx, sig, siglen, pkey);
 +void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    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;
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    return r;
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -
 - protected:
 -
 -  static Handle<Value> New (const Arguments& args) {
 -    HandleScope scope;
 -
 -    Verify *verify = new Verify();
 -    verify->Wrap(args.This());
 -
 -    return args.This();
 +  if (!DH_generate_key(diffieHellman->dh)) {
 +    return ThrowError("Key generation failed");
    }
  
 +  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));
  
 -  static Handle<Value> VerifyInit(const Arguments& args) {
 -    Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
 -
 -    HandleScope scope;
 -
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(String::New(
 -        "Must give verifytype string as argument")));
 -    }
 +  args.GetReturnValue().Set(Encode(data, dataSize, BUFFER));
 +  delete[] data;
 +}
  
 -    String::Utf8Value verifyType(args[0]);
  
 -    bool r = verify->VerifyInit(*verifyType);
 +void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) {
 -      return ThrowException(Exception::Error(String::New("VerifyInit error")));
 -    }
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    return args.This();
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("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));
  
 -  static Handle<Value> VerifyUpdate(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
 +  args.GetReturnValue().Set(Encode(data, dataSize, BUFFER));
 +  delete[] data;
 +}
  
 -    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()) {
 -      Local<String> string = args[0].As<String>();
 -      enum encoding encoding = ParseEncoding(args[1], BINARY);
 -      if (!StringBytes::IsValidString(string, encoding))
 -        return ThrowTypeError("Bad input string");
 -      size_t buflen = StringBytes::StorageSize(string, encoding);
 -      char* buf = new char[buflen];
 -      size_t written = StringBytes::Write(buf, buflen, string, 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);
 -    }
 +void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    if (!r) {
 -      Local<Value> exception = Exception::TypeError(String::New("VerifyUpdate fail"));
 -      return ThrowException(exception);
 -    }
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    return args.This();
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 +  int dataSize = BN_num_bytes(diffieHellman->dh->g);
 +  char* data = new char[dataSize];
 +  BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data));
  
 -  static Handle<Value> VerifyFinal(const Arguments& args) {
 -    HandleScope scope;
 -
 -    Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
 -
 -    ASSERT_IS_BUFFER(args[0]);
 -    ssize_t klen = Buffer::Length(args[0]);
 -
 -    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);
 -
 -    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);
 -    }
 -
 -    ssize_t hlen = StringBytes::Size(args[1], encoding);
 -
 -    if (hlen < 0) {
 -      delete[] kbuf;
 -      Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
 -      return ThrowException(exception);
 -    }
 -
 -    unsigned char* hbuf = new unsigned char[hlen];
 -    ssize_t hwritten = StringBytes::Write(
 -        reinterpret_cast<char*>(hbuf), hlen, args[1], encoding);
 -    assert(hwritten == hlen);
 +  args.GetReturnValue().Set(Encode(data, dataSize, BUFFER));
 +  delete[] data;
 +}
  
 -    int r;
 -    r = verify->VerifyFinal(kbuf, klen, hbuf, hlen);
  
 -    delete[] kbuf;
 -    delete[] hbuf;
 +void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& 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 (diffieHellman->dh->pub_key == NULL) {
 +    return ThrowError("No public key - did you forget to generate one?");
    }
  
 - private:
 -
 -  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);
 -
 -    NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys);
 -    NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret);
 -    NODE_SET_PROTOTYPE_METHOD(t, "getPrime", GetPrime);
 -    NODE_SET_PROTOTYPE_METHOD(t, "getGenerator", GetGenerator);
 -    NODE_SET_PROTOTYPE_METHOD(t, "getPublicKey", GetPublicKey);
 -    NODE_SET_PROTOTYPE_METHOD(t, "getPrivateKey", GetPrivateKey);
 -    NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey);
 -    NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey);
 -
 -    target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction());
 -
 -    Local<FunctionTemplate> t2 = FunctionTemplate::New(DiffieHellmanGroup);
 -    t2->InstanceTemplate()->SetInternalFieldCount(1);
 +  args.GetReturnValue().Set(Encode(data, dataSize, BUFFER));
 +  delete[] data;
 +}
  
 -    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);
  
 -    target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction());
 -  }
 +void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -  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;
 -  }
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -  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;
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  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;
 +  if (diffieHellman->dh->priv_key == NULL) {
 +    return ThrowError("No private key - did you forget to generate one?");
    }
  
 - protected:
 -  static Handle<Value> DiffieHellmanGroup(const Arguments& args) {
 -    HandleScope scope;
 -
 -    DiffieHellman* diffieHellman = new DiffieHellman();
 -
 -    if (args.Length() != 1 || !args[0]->IsString()) {
 -      return ThrowException(Exception::Error(
 -          String::New("No group name given")));
 -    }
 +  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));
  
 -    String::Utf8Value group_name(args[0]);
 +  args.GetReturnValue().Set(Encode(data, dataSize, BUFFER));
 +  delete[] data;
 +}
  
 -    modp_group* it = modp_groups;
  
 -    while(it->name != NULL) {
 -      if (!strcasecmp(*group_name, it->name))
 -          break;
 -      it++;
 -    }
 +void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -    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")));
 -    }
 -
 -    diffieHellman->Wrap(args.This());
 +  DiffieHellman* diffieHellman =
 +      ObjectWrap::Unwrap<DiffieHellman>(args.This());
  
 -    return args.This();
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  static Handle<Value> New(const Arguments& args) {
 -    HandleScope scope;
 -
 -    DiffieHellman* diffieHellman = new DiffieHellman();
 -    bool initialized = false;
 -
 -    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")));
 -    }
 -
 -    diffieHellman->Wrap(args.This());
 +  ClearErrorOnReturn clear_error_on_return;
 +  (void) &clear_error_on_return;  // Silence compiler warning.
 +  BIGNUM* key = NULL;
  
 -    return args.This();
 +  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);
    }
  
 -  static Handle<Value> GenerateKeys(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 -
 -    HandleScope scope;
 -
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(
 -            String::New("Not initialized")));
 -    }
 -
 -    if (!DH_generate_key(diffieHellman->dh)) {
 -      return ThrowException(Exception::Error(
 -            String::New("Key generation failed")));
 -    }
 +  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);
  
 -    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 (size == -1) {
 +    int checkResult;
 +    int checked;
  
 -    outString = Encode(data, dataSize, BUFFER);
 +    checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult);
 +    BN_free(key);
      delete[] data;
  
 -    return scope.Close(outString);
 -  }
 -
 -  static Handle<Value> GetPrime(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 -
 -    HandleScope scope;
 -
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 +    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");
      }
 -
 -    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);
    }
  
 -  static Handle<Value> GetGenerator(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 -
 -    HandleScope scope;
 -
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 -
 -    int dataSize = BN_num_bytes(diffieHellman->dh->g);
 -    char* data = new char[dataSize];
 -    BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data));
 +  BN_free(key);
 +  assert(size >= 0);
  
 -    Local<Value> outString;
 -
 -    outString = Encode(data, dataSize, BUFFER);
 -
 -    delete[] data;
 -
 -    return scope.Close(outString);
 +  // 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);
    }
  
 -  static Handle<Value> GetPublicKey(const Arguments& args) {
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 -
 -    HandleScope scope;
 -
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 -
 -    if (diffieHellman->dh->pub_key == NULL) {
 -      return ThrowException(Exception::Error(
 -            String::New("No public key - did you forget to generate one?")));
 -    }
 -
 -    int dataSize = BN_num_bytes(diffieHellman->dh->pub_key);
 -    char* data = new char[dataSize];
 -    BN_bn2bin(diffieHellman->dh->pub_key,
 -        reinterpret_cast<unsigned char*>(data));
 -
 -    Local<Value> outString;
 -
 -    outString = Encode(data, dataSize, BUFFER);
 +  args.GetReturnValue().Set(Encode(data, dataSize, BUFFER));
 +  delete[] data;
 +}
  
 -    delete[] data;
  
 -    return scope.Close(outString);
 -  }
 +void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
 +  HandleScope scope(node_isolate);
  
 -  static Handle<Value> GetPrivateKey(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")));
 -    }
 -
 -    if (diffieHellman->dh->priv_key == NULL) {
 -      return ThrowException(Exception::Error(
 -            String::New("No private key - did you forget to generate one?")));
 -    }
 -
 -    int dataSize = BN_num_bytes(diffieHellman->dh->priv_key);
 -    char* data = new char[dataSize];
 -    BN_bn2bin(diffieHellman->dh->priv_key,
 -        reinterpret_cast<unsigned char*>(data));
 -
 -    Local<Value> outString;
 -
 -    outString = Encode(data, dataSize, BUFFER);
 -
 -    delete[] data;
 -
 -    return scope.Close(outString);
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  static Handle<Value> ComputeSecret(const Arguments& args) {
 -    HandleScope scope;
 -
 -    DiffieHellman* diffieHellman =
 -      ObjectWrap::Unwrap<DiffieHellman>(args.This());
 -
 -    if (!diffieHellman->initialised_) {
 -      return ThrowException(Exception::Error(String::New("Not initialized")));
 -    }
 -
 -    ClearErrorOnReturn clear_error_on_return;
 -    (void) &clear_error_on_return;  // Silence compiler warning.
 -    BIGNUM* key = 0;
 -
 -    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();
 -  }
  
 -  static Handle<Value> SetPrivateKey(const Arguments& args) {
 -    HandleScope scope;
 +void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& 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();
 -  }
 -
 -  DiffieHellman() : ObjectWrap() {
 -    initialised_ = false;
 -    dh = NULL;
 +  if (!diffieHellman->initialised_) {
 +    return ThrowError("Not initialized");
    }
  
 -  ~DiffieHellman() {
 -    if (dh != NULL) {
 -      DH_free(dh);
 -    }
 +  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);
    }
 +}
  
 - 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
diff --cc src/node_os.cc
@@@ -131,29 -116,30 +131,31 @@@ static void GetCPUInfo(const FunctionCa
    uv_cpu_info_t* cpu_infos;
    int count, i;
  
 -  uv_err_t err = uv_cpu_info(&cpu_infos, &count);
 -
 -  if (err.code != UV_OK) {
 -    return Undefined();
 -  }
 +  int err = uv_cpu_info(&cpu_infos, &count);
 +  if (err) return;
  
    Local<Array> cpus = Array::New();
 -
    for (i = 0; i < count; i++) {
+     uv_cpu_info_t* ci = cpu_infos + i;
      Local<Object> times_info = Object::New();
 -    times_info->Set(String::New("user"), Number::New(ci->cpu_times.user));
 -    times_info->Set(String::New("nice"), Number::New(ci->cpu_times.nice));
 -    times_info->Set(String::New("sys"), Number::New(ci->cpu_times.sys));
 -    times_info->Set(String::New("idle"), Number::New(ci->cpu_times.idle));
 -    times_info->Set(String::New("irq"), Number::New(ci->cpu_times.irq));
 +    times_info->Set(String::New("user"),
-       Integer::New(cpu_infos[i].cpu_times.user, node_isolate));
++                    Number::New(node_isolate, ci->cpu_times.user));
 +    times_info->Set(String::New("nice"),
-       Integer::New(cpu_infos[i].cpu_times.nice, node_isolate));
++                    Number::New(node_isolate, ci->cpu_times.nice));
 +    times_info->Set(String::New("sys"),
-       Integer::New(cpu_infos[i].cpu_times.sys, node_isolate));
++                    Number::New(node_isolate, ci->cpu_times.sys));
 +    times_info->Set(String::New("idle"),
-       Integer::New(cpu_infos[i].cpu_times.idle, node_isolate));
++                    Number::New(node_isolate, ci->cpu_times.idle));
 +    times_info->Set(String::New("irq"),
-       Integer::New(cpu_infos[i].cpu_times.irq, node_isolate));
++                    Number::New(node_isolate, ci->cpu_times.irq));
  
      Local<Object> cpu_info = Object::New();
-     cpu_info->Set(String::New("model"), String::New(cpu_infos[i].model));
-     cpu_info->Set(String::New("speed"),
-                   Integer::New(cpu_infos[i].speed, node_isolate));
+     cpu_info->Set(String::New("model"), String::New(ci->model));
 -    cpu_info->Set(String::New("speed"), Number::New(ci->speed));
++    cpu_info->Set(String::New("speed"), Number::New(node_isolate, ci->speed));
      cpu_info->Set(String::New("times"), times_info);
-     (*cpus)->Set(i,cpu_info);
+     (*cpus)->Set(i, cpu_info);
    }
  
    uv_free_cpu_info(cpu_infos, count);
Simple merge
Simple merge