From 83d17e509f11793b5ba5bb09fe573e8357ac5c81 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 12 Mar 2013 14:09:27 +0400 Subject: [PATCH] crypto: merge Cipher and Decipher --- lib/crypto.js | 8 +- src/node_crypto.cc | 598 +++++++++++---------------------------------- src/node_crypto.h | 87 +++---- 3 files changed, 180 insertions(+), 513 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index 01d4b7125b..a51d005e2b 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -216,7 +216,7 @@ exports.createCipher = exports.Cipher = Cipher; function Cipher(cipher, password, options) { if (!(this instanceof Cipher)) return new Cipher(cipher, password); - this._binding = new binding.Cipher; + this._binding = new binding.CipherBase(true); this._binding.init(cipher, toBuf(password)); this._decoder = null; @@ -276,7 +276,7 @@ exports.createCipheriv = exports.Cipheriv = Cipheriv; function Cipheriv(cipher, key, iv, options) { if (!(this instanceof Cipheriv)) return new Cipheriv(cipher, key, iv); - this._binding = new binding.Cipher(); + this._binding = new binding.CipherBase(true); this._binding.initiv(cipher, toBuf(key), toBuf(iv)); this._decoder = null; @@ -298,7 +298,7 @@ function Decipher(cipher, password, options) { if (!(this instanceof Decipher)) return new Decipher(cipher, password); - this._binding = new binding.Decipher; + this._binding = new binding.CipherBase(false); this._binding.init(cipher, toBuf(password)); this._decoder = null; @@ -321,7 +321,7 @@ function Decipheriv(cipher, key, iv, options) { if (!(this instanceof Decipheriv)) return new Decipheriv(cipher, key, iv); - this._binding = new binding.Decipher; + this._binding = new binding.CipherBase(false); this._binding.initiv(cipher, toBuf(key), toBuf(iv)); this._decoder = null; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index b2c6697df2..f4974c8f88 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2036,532 +2036,218 @@ Handle Connection::SetSNICallback(const Arguments& args) { #endif -void Cipher::Initialize(v8::Handle target) { +void CipherBase::Initialize(Handle target) { HandleScope scope; Local t = FunctionTemplate::New(New); 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, "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); - NODE_SET_PROTOTYPE_METHOD(t, "final", CipherFinal); - target->Set(String::NewSymbol("Cipher"), t->GetFunction()); + target->Set(String::NewSymbol("CipherBase"), t->GetFunction()); } -bool Cipher:: 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; - } - - 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 Cipher::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; -} - - -int Cipher::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); -} - - -int Cipher::SetAutoPadding(bool auto_padding) { - if (!initialised_) return 0; - return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0); -} - - -int Cipher::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; -} - - -Handle Cipher::New(const Arguments& args) { +Handle CipherBase::New(const Arguments& args) { HandleScope scope; - Cipher *cipher = new Cipher(); + CipherBase* cipher = new CipherBase(args[0]->IsTrue() ? kCipher : kDecipher); cipher->Wrap(args.This()); return args.This(); } -Handle Cipher::CipherInit(const Arguments& args) { - HandleScope scope; - - Cipher *cipher = ObjectWrap::Unwrap(args.This()); - - if (args.Length() <= 1 - || !args[0]->IsString() - || !(args[1]->IsString() || Buffer::HasInstance(args[1]))) - { - return ThrowException(Exception::Error(String::New( - "Must give cipher-type, key"))); - } - - ASSERT_IS_BUFFER(args[1]); - ssize_t key_buf_len = Buffer::Length(args[1]); - - if (key_buf_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - - 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); - - String::Utf8Value cipherType(args[0]); - - bool r = cipher->CipherInit(*cipherType, key_buf, key_buf_len); - - delete [] key_buf; - - if (!r) return ThrowCryptoError(ERR_get_error()); - - return args.This(); -} - - -Handle Cipher::CipherInitIv(const Arguments& args) { - Cipher *cipher = ObjectWrap::Unwrap(args.This()); +Handle CipherBase::Init(char* cipher_type, + char* key_buf, + int key_buf_len) { HandleScope scope; - - 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]); - - if (key_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - - ASSERT_IS_BUFFER(args[2]); - ssize_t iv_len = Buffer::Length(args[2]); - - if (iv_len < 0) { - Local 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); - - char* iv_buf = new char[iv_len]; - ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY); - assert(iv_written == iv_len); - - String::Utf8Value cipherType(args[0]); - - bool r = cipher->CipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len); - - delete [] key_buf; - delete [] iv_buf; - - if (!r) return ThrowCryptoError(ERR_get_error()); - - return args.This(); -} - - -Handle Cipher::CipherUpdate(const Arguments& args) { - Cipher *cipher = ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - ASSERT_IS_BUFFER(args[0]); - - unsigned char* out=0; - int out_len=0, r; - char* buffer_data = Buffer::Data(args[0]); - size_t buffer_length = Buffer::Length(args[0]); - - r = cipher->CipherUpdate(buffer_data, buffer_length, &out, &out_len); - - if (r == 0) { - delete [] out; - return ThrowCryptoTypeError(ERR_get_error()); - } - - Local outString; - outString = Encode(out, out_len, BUFFER); - - if (out) delete [] out; - - return scope.Close(outString); -} - - -Handle Cipher::SetAutoPadding(const Arguments& args) { - HandleScope scope; - Cipher *cipher = ObjectWrap::Unwrap(args.This()); - - cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue()); - - return Undefined(); -} - - -Handle Cipher::CipherFinal(const Arguments& args) { - Cipher *cipher = ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - unsigned char* out_value = NULL; - int out_len = -1; - Local outString ; - - 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()); + assert(cipher_ == NULL); + cipher_ = EVP_get_cipherbyname(cipher_type); + if (cipher_ == NULL) { + return ThrowError("Unknown cipher"); } - outString = Encode(out_value, out_len, BUFFER); - - delete [] out_value; - return scope.Close(outString); -} - - -void Decipher::Initialize(v8::Handle target) { - HandleScope scope; - - Local t = FunctionTemplate::New(New); - - t->InstanceTemplate()->SetInternalFieldCount(1); - - NODE_SET_PROTOTYPE_METHOD(t, "init", DecipherInit); - NODE_SET_PROTOTYPE_METHOD(t, "initiv", DecipherInitIv); - NODE_SET_PROTOTYPE_METHOD(t, "update", DecipherUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "final", DecipherFinal); - NODE_SET_PROTOTYPE_METHOD(t, "finaltol", DecipherFinal); // remove someday - NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding); - - target->Set(String::NewSymbol("Decipher"), t->GetFunction()); -} - - -bool Decipher::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; - } + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; - 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), + reinterpret_cast(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_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, - (unsigned char*)key, - (unsigned char*)iv, false); - initialised_ = true; - return true; -} - -bool Decipher::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); + EVP_CipherInit_ex(&ctx_, + NULL, + NULL, + reinterpret_cast(key), + reinterpret_cast(iv), + kind_ == kCipher); initialised_ = true; - return true; -} - - -int Decipher::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]; - - return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len); + return Null(); } -int Decipher::SetAutoPadding(bool auto_padding) { - if (!initialised_) return 0; - return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0); -} - +Handle CipherBase::Init(const Arguments& args) { + HandleScope scope; -int Decipher::DecipherFinal(unsigned char** out, int *out_len) { - int r; + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); - if (!initialised_) { - *out_len = 0; - *out = NULL; - return 0; + if (args.Length() < 2 || + !(args[0]->IsString() && Buffer::HasInstance(args[1]))) { + return ThrowError("Must give cipher-type, key"); } - *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; -} - + String::Utf8Value cipher_type(args[0]); + char* key_buf = Buffer::Data(args[1]); + ssize_t key_buf_len = Buffer::Length(args[1]); -Handle Decipher::New(const Arguments& args) { - HandleScope scope; + Handle ret = cipher->Init(*cipher_type, key_buf, key_buf_len); - Decipher *cipher = new Decipher(); - cipher->Wrap(args.This()); - return args.This(); + if (ret->IsNull()) { + return args.This(); + } else { + // Exception + return scope.Close(ret); + } } -Handle Decipher::DecipherInit(const Arguments& args) { - Decipher *cipher = ObjectWrap::Unwrap(args.This()); - +Handle CipherBase::InitIv(char* cipher_type, + char* key, + int key_len, + char* iv, + int iv_len) { HandleScope scope; - 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"))); + cipher_ = EVP_get_cipherbyname(cipher_type); + if (cipher_ == NULL) { + return ThrowError("Unknown cipher"); } - ASSERT_IS_BUFFER(args[1]); - ssize_t key_len = Buffer::Length(args[1]); - - if (key_len < 0) { - Local 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); - - String::Utf8Value cipherType(args[0]); - - bool r = cipher->DecipherInit(*cipherType, key_buf,key_len); - - delete [] key_buf; - - if (!r) { - return ThrowException(Exception::Error(String::New("DecipherInit error"))); - } - - return args.This(); + /* 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"); + } + + EVP_CipherInit_ex(&ctx_, + NULL, + NULL, + reinterpret_cast(key), + reinterpret_cast(iv), + kind_ == kCipher); + initialised_ = true; + return Null(); } -Handle Decipher::DecipherInitIv(const Arguments& args) { - Decipher *cipher = ObjectWrap::Unwrap(args.This()); - +Handle CipherBase::InitIv(const Arguments& args) { HandleScope scope; - 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"))); - } + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); - ASSERT_IS_BUFFER(args[1]); - ssize_t key_len = Buffer::Length(args[1]); - - if (key_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); + if (args.Length() < 3 || !args[0]->IsString()) { + return ThrowError("Must give cipher-type, key, and iv as argument"); } + ASSERT_IS_BUFFER(args[1]); ASSERT_IS_BUFFER(args[2]); - ssize_t iv_len = Buffer::Length(args[2]); - - if (iv_len < 0) { - Local 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); - char* iv_buf = new char[iv_len]; - ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY); - assert(iv_written == iv_len); - - String::Utf8Value cipherType(args[0]); - - bool r = cipher->DecipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len); + 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]); - delete [] key_buf; - delete [] iv_buf; + Handle ret = cipher->InitIv(*cipher_type, + key_buf, + key_len, + iv_buf, + iv_len); - if (!r) { - return ThrowException(Exception::Error(String::New("DecipherInitIv error"))); + if (ret->IsNull()) { + return args.This(); + } else { + // Exception + return scope.Close(ret); } +} - return args.This(); + +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(data), + len); } -Handle Decipher::DecipherUpdate(const Arguments& args) { +Handle CipherBase::Update(const Arguments& args) { HandleScope scope; - Decipher *cipher = ObjectWrap::Unwrap(args.This()); + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); ASSERT_IS_BUFFER(args[0]); - ssize_t len; - - char* buf; - // if alloc_buf then buf must be deleted later - bool alloc_buf = false; + unsigned char* out = NULL; + bool r; + int out_len = 0; char* buffer_data = Buffer::Data(args[0]); size_t buffer_length = Buffer::Length(args[0]); - buf = buffer_data; - len = buffer_length; - - unsigned char* out=0; - int out_len=0; - int r = cipher->DecipherUpdate(buf, len, &out, &out_len); + r = cipher->Update(buffer_data, buffer_length, &out, &out_len); if (!r) { - delete [] out; + delete[] out; return ThrowCryptoTypeError(ERR_get_error()); } - Local outString; - outString = Encode(out, out_len, BUFFER); + Buffer* buf = Buffer::New(reinterpret_cast(out), out_len); - if (out) delete [] out; + return scope.Close(buf->handle_); +} - if (alloc_buf) delete [] buf; - return scope.Close(outString); +bool CipherBase::SetAutoPadding(bool auto_padding) { + if (!initialised_) return false; + return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding); } -Handle Decipher::SetAutoPadding(const Arguments& args) { +Handle CipherBase::SetAutoPadding(const Arguments& args) { HandleScope scope; - Decipher *cipher = ObjectWrap::Unwrap(args.This()); + + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue()); @@ -2569,26 +2255,39 @@ Handle Decipher::SetAutoPadding(const Arguments& args) { } -Handle Decipher::DecipherFinal(const Arguments& args) { +bool CipherBase::Final(unsigned char** out, int *out_len) { + if (!initialised_) return false; + + *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; + + return r; +} + + +Handle CipherBase::Final(const Arguments& args) { HandleScope scope; - Decipher *cipher = ObjectWrap::Unwrap(args.This()); + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); unsigned char* out_value = NULL; int out_len = -1; Local outString; - int r = cipher->DecipherFinal(&out_value, &out_len); + bool r = cipher->Final(&out_value, &out_len); - if (out_len <= 0 || r == 0) { - delete [] out_value; // allocated even if out_len == 0 + if (out_len <= 0 || !r) { + delete[] out_value; out_value = NULL; - if (r == 0) return ThrowCryptoTypeError(ERR_get_error()); + out_len = 0; + if (!r) return ThrowCryptoTypeError(ERR_get_error()); } - outString = Encode(out_value, out_len, BUFFER); - delete [] out_value; - return scope.Close(outString); + Buffer* buf = Buffer::New(reinterpret_cast(out_value), out_len); + + return scope.Close(buf->handle_); } @@ -3946,8 +3645,7 @@ void InitCrypto(Handle target) { SecureContext::Initialize(target); Connection::Initialize(target); - Cipher::Initialize(target); - Decipher::Initialize(target); + CipherBase::Initialize(target); DiffieHellman::Initialize(target); Hmac::Initialize(target); Hash::Initialize(target); diff --git a/src/node_crypto.h b/src/node_crypto.h index 0feeb71b35..28c48b390f 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -276,79 +276,48 @@ class Connection : ObjectWrap { friend class SecureContext; }; -class Cipher : public ObjectWrap { +class CipherBase : public ObjectWrap { public: - static void Initialize (v8::Handle target); - - bool CipherInit(char* cipherType, char* key_buf, int key_buf_len); - bool CipherInitIv(char* cipherType, - char* key, - int key_len, - char* iv, - int iv_len); - int CipherUpdate(char* data, int len, unsigned char** out, int* out_len); - int SetAutoPadding(bool auto_padding); - int CipherFinal(unsigned char** out, int *out_len); + static void Initialize(v8::Handle target); protected: - static v8::Handle New(const v8::Arguments& args); - static v8::Handle CipherInit(const v8::Arguments& args); - static v8::Handle CipherInitIv(const v8::Arguments& args); - static v8::Handle CipherUpdate(const v8::Arguments& args); - static v8::Handle SetAutoPadding(const v8::Arguments& args); - static v8::Handle CipherFinal(const v8::Arguments& args); - - Cipher() : ObjectWrap(), initialised_(false) { - } - - ~Cipher() { - if (initialised_) { - EVP_CIPHER_CTX_cleanup(&ctx); - } - } - - private: - EVP_CIPHER_CTX ctx; /* coverity[member_decl] */ - const EVP_CIPHER *cipher; /* coverity[member_decl] */ - bool initialised_; -}; - -class Decipher : public ObjectWrap { - public: - static void Initialize(v8::Handle target); + enum CipherKind { + kCipher, + kDecipher + }; - bool DecipherInit(char* cipherType, char* key_buf, int key_buf_len); - bool DecipherInitIv(char* cipherType, - char* key, - int key_len, - char* iv, - int iv_len); - int DecipherUpdate(char* data, int len, unsigned char** out, int* out_len); - int SetAutoPadding(bool auto_padding); - int DecipherFinal(unsigned char** out, int *out_len); + v8::Handle Init(char* cipher_type, char* key_buf, int key_buf_len); + v8::Handle InitIv(char* cipher_type, + char* key, + int key_len, + char* iv, + int iv_len); + bool Update(char* data, int len, unsigned char** out, int* out_len); + bool Final(unsigned char** out, int *out_len); + bool SetAutoPadding(bool auto_padding); - protected: static v8::Handle New(const v8::Arguments& args); - static v8::Handle DecipherInit(const v8::Arguments& args); - - static v8::Handle DecipherInitIv(const v8::Arguments& args); - static v8::Handle DecipherUpdate(const v8::Arguments& args); + static v8::Handle Init(const v8::Arguments& args); + static v8::Handle InitIv(const v8::Arguments& args); + static v8::Handle Update(const v8::Arguments& args); + static v8::Handle Final(const v8::Arguments& args); static v8::Handle SetAutoPadding(const v8::Arguments& args); - static v8::Handle DecipherFinal(const v8::Arguments& args); - Decipher() : ObjectWrap(), initialised_(false) { + CipherBase(CipherKind kind) : cipher_(NULL), + initialised_(false), + kind_(kind) { } - ~Decipher() { - if (initialised_) { - EVP_CIPHER_CTX_cleanup(&ctx); - } + ~CipherBase() { + if (!initialised_) return; + EVP_CIPHER_CTX_cleanup(&ctx_); } private: - EVP_CIPHER_CTX ctx; - const EVP_CIPHER *cipher_; + EVP_CIPHER_CTX ctx_; /* coverity[member_decl] */ + const EVP_CIPHER* cipher_; /* coverity[member_decl] */ bool initialised_; + CipherKind kind_; }; class Hmac : public ObjectWrap {