Persistent<FunctionTemplate> Buffer::constructor_template;
- static inline size_t base64_decoded_size(const char *src, size_t size) {
- const char *const end = src + size;
- const int remainder = size % 4;
-
- size = (size / 4) * 3;
- if (remainder) {
- if (size == 0 && remainder == 1) {
- // special case: 1-byte input cannot be decoded
- size = 0;
- } else {
- // non-padded input, add 1 or 2 extra bytes
- size += 1 + (remainder == 3);
- }
- }
-
- // check for trailing padding (1 or 2 bytes)
- if (size > 0) {
- if (end[-1] == '=') size--;
- if (end[-2] == '=') size--;
- }
-
- return size;
- }
-
-
- static size_t ByteLength (Handle<String> string, enum encoding enc) {
- HandleScope scope(node_isolate);
-
- if (enc == UTF8) {
- return string->Utf8Length();
- } else if (enc == BASE64) {
- String::Utf8Value v(string);
- return base64_decoded_size(*v, v.length());
- } else if (enc == UCS2) {
- return string->Length() * 2;
- } else if (enc == HEX) {
- return string->Length() / 2;
- } else {
- return string->Length();
- }
- }
-
-
Handle<Object> Buffer::New(Handle<String> string) {
- HandleScope scope;
+ HandleScope scope(node_isolate);
// get Buffer from global scope.
Local<Object> global = v8::Context::GetCurrent()->Global();
handle_->SetIndexedPropertiesToExternalArrayData(data_,
kExternalUnsignedByteArray,
length_);
- handle_->Set(length_symbol, Integer::NewFromUnsigned(length_));
+ handle_->Set(length_symbol, Integer::NewFromUnsigned(length_, node_isolate));
}
- Handle<Value> Buffer::BinarySlice(const Arguments &args) {
+
- HandleScope scope;
+ template <encoding encoding>
+ Handle<Value> Buffer::StringSlice(const Arguments& args) {
+ HandleScope scope(node_isolate);
Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
SLICE_ARGS(args[0], args[1])
}
- // supports regular and URL-safe base64
- static const int unbase64_table[] =
- {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,62,-1,63
- ,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1
- ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14
- ,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,63
- ,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
- ,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- };
- #define unbase64(x) unbase64_table[(uint8_t)(x)]
-
-
- Handle<Value> Buffer::Base64Slice(const Arguments &args) {
- HandleScope scope(node_isolate);
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
-
- unsigned slen = end - start;
- const char* src = parent->data_ + start;
-
- unsigned dlen = (slen + 2 - ((slen + 2) % 3)) / 3 * 4;
- char* dst = new char[dlen];
-
- unsigned a;
- unsigned b;
- unsigned c;
- unsigned i;
- unsigned k;
- unsigned n;
-
- static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
-
- i = 0;
- k = 0;
- n = slen / 3 * 3;
-
- while (i < n) {
- a = src[i + 0] & 0xff;
- b = src[i + 1] & 0xff;
- c = src[i + 2] & 0xff;
-
- dst[k + 0] = table[a >> 2];
- dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
- dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
- dst[k + 3] = table[c & 0x3f];
-
- i += 3;
- k += 4;
- }
-
- if (n != slen) {
- switch (slen - n) {
- case 1:
- a = src[i + 0] & 0xff;
- dst[k + 0] = table[a >> 2];
- dst[k + 1] = table[(a & 3) << 4];
- dst[k + 2] = '=';
- dst[k + 3] = '=';
- break;
-
- case 2:
- a = src[i + 0] & 0xff;
- b = src[i + 1] & 0xff;
- dst[k + 0] = table[a >> 2];
- dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
- dst[k + 2] = table[(b & 0x0f) << 2];
- dst[k + 3] = '=';
- break;
- }
- }
-
- Local<String> string = String::New(dst, dlen);
- delete [] dst;
--
- return scope.Close(string);
+ Handle<Value> Buffer::Base64Slice(const Arguments& args) {
+ return Buffer::StringSlice<BASE64>(args);
}
}
- // var charsWritten = buffer.utf8Write(string, offset, [maxLength]);
- Handle<Value> Buffer::Utf8Write(const Arguments &args) {
- HandleScope scope(node_isolate);
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (!args[0]->IsString()) {
- return ThrowException(Exception::TypeError(String::New(
- "Argument must be a string")));
- }
-
- Local<String> s = args[0]->ToString();
-
- size_t offset = args[1]->Uint32Value();
-
- int length = s->Length();
-
- if (length == 0) {
- return scope.Close(Integer::New(0, node_isolate));
- }
-
- if (length > 0 && offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(buffer->length_ - offset, max_length);
-
- char* p = buffer->data_ + offset;
-
- int char_written;
-
- int written = s->WriteUtf8(p,
- max_length,
- &char_written,
- (String::HINT_MANY_WRITES_EXPECTED |
- String::NO_NULL_TERMINATION));
-
- return scope.Close(Integer::New(written, node_isolate));
+ Handle<Value> Buffer::Base64Write(const Arguments& args) {
+ return Buffer::StringWrite<BASE64>(args);
}
-
- // var charsWritten = buffer.ucs2Write(string, offset, [maxLength]);
- Handle<Value> Buffer::Ucs2Write(const Arguments &args) {
- HandleScope scope(node_isolate);
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (!args[0]->IsString()) {
- return ThrowTypeError("Argument must be a string");
- }
-
- Local<String> s = args[0]->ToString();
-
- size_t offset = args[1]->Uint32Value();
-
- if (s->Length() > 0 && offset >= buffer->length_) {
- return ThrowException(Exception::TypeError(String::New(
- "Offset is out of bounds")));
- }
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(buffer->length_ - offset, max_length) / 2;
-
- uint16_t* p = (uint16_t*)(buffer->data_ + offset);
-
- int written = s->Write(p,
- 0,
- max_length,
- (String::HINT_MANY_WRITES_EXPECTED |
- String::NO_NULL_TERMINATION));
-
- return scope.Close(Integer::New(written * 2, node_isolate));
+ Handle<Value> Buffer::BinaryWrite(const Arguments& args) {
+ return Buffer::StringWrite<BINARY>(args);
}
-
- inline unsigned hex2bin(char c) {
- if (c >= '0' && c <= '9') return c - '0';
- if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
- if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
- return static_cast<unsigned>(-1);
+ Handle<Value> Buffer::Utf8Write(const Arguments& args) {
+ return Buffer::StringWrite<UTF8>(args);
}
+ Handle<Value> Buffer::Ucs2Write(const Arguments& args) {
+ return Buffer::StringWrite<UCS2>(args);
+ }
Handle<Value> Buffer::HexWrite(const Arguments& args) {
- HandleScope scope(node_isolate);
- Buffer* parent = ObjectWrap::Unwrap<Buffer>(args.This());
-
- if (args[0]->IsString() == false) {
- return ThrowTypeError("Argument must be a string");
- }
-
- Local<String> s = args[0].As<String>();
-
- if (s->Length() % 2 != 0) {
- return ThrowTypeError("Invalid hex string");
- }
-
- uint32_t start = args[1]->Uint32Value();
- uint32_t size = args[2]->Uint32Value();
- uint32_t end = start + size;
-
- if (start >= parent->length_) {
- Local<Integer> val = Integer::New(0, node_isolate);
- return scope.Close(val);
- }
-
- if (end < start || end > parent->length_) { // Overflow + bounds check.
- end = parent->length_;
- size = parent->length_ - start;
- }
-
- if (size == 0) {
- Local<Integer> val = Integer::New(0, node_isolate);
- return scope.Close(val);
- }
-
- char* dst = parent->data_ + start;
- String::AsciiValue string(s);
- const char* src = *string;
- uint32_t max = string.length() / 2;
-
- if (max > size) {
- max = size;
- }
-
- for (uint32_t i = 0; i < max; ++i) {
- unsigned a = hex2bin(src[i * 2 + 0]);
- unsigned b = hex2bin(src[i * 2 + 1]);
- if (!~a || !~b) return ThrowTypeError("Invalid hex string");
- dst[i] = a * 16 + b;
- }
-
- return scope.Close(Integer::New(max, node_isolate));
+ return Buffer::StringWrite<HEX>(args);
}
+ Handle<Value> Buffer::AsciiWrite(const Arguments& args) {
+ return Buffer::StringWrite<ASCII>(args);
+ }
- // var charsWritten = buffer.asciiWrite(string, offset);
- Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
+ template <encoding encoding>
+ Handle<Value> Buffer::StringWrite(const Arguments& args) {
- HandleScope scope;
+ HandleScope scope(node_isolate);
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
+ Buffer* buffer = ObjectWrap::Unwrap<Buffer>(args.This());
if (!args[0]->IsString()) {
return ThrowTypeError("Argument must be a string");
}
- Local<String> s = args[0]->ToString();
- size_t length = s->Length();
- size_t offset = args[1]->Int32Value();
+ Local<String> str = args[0].As<String>();
- if (length > 0 && offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(length, MIN(buffer->length_ - offset, max_length));
-
- char *p = buffer->data_ + offset;
-
- int written = s->WriteOneByte(reinterpret_cast<uint8_t*>(p),
- 0,
- max_length,
- (String::HINT_MANY_WRITES_EXPECTED |
- String::NO_NULL_TERMINATION));
-
- return scope.Close(Integer::New(written, node_isolate));
- }
-
-
- // var bytesWritten = buffer.base64Write(string, offset, [maxLength]);
- Handle<Value> Buffer::Base64Write(const Arguments &args) {
- HandleScope scope(node_isolate);
-
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
+ if (encoding == HEX && str->Length() % 2 != 0)
+ return ThrowTypeError("Invalid hex string");
- if (!args[0]->IsString()) {
- return ThrowTypeError("Argument must be a string");
- }
+
- String::AsciiValue s(args[0]);
- size_t length = s.length();
size_t offset = args[1]->Int32Value();
size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
: args[2]->Uint32Value();
- max_length = MIN(length, MIN(buffer->length_ - offset, max_length));
-
- if (max_length && offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
-
- char a, b, c, d;
- char* start = buffer->data_ + offset;
- char* dst = start;
- char* const dstEnd = dst + max_length;
- const char* src = *s;
- const char* const srcEnd = src + s.length();
-
- while (src < srcEnd && dst < dstEnd) {
- int remaining = srcEnd - src;
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining == 0 || *src == '=') break;
- a = unbase64(*src++);
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining <= 1 || *src == '=') break;
- b = unbase64(*src++);
-
- *dst++ = (a << 2) | ((b & 0x30) >> 4);
- if (dst == dstEnd) break;
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining <= 2 || *src == '=') break;
- c = unbase64(*src++);
-
- *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
- if (dst == dstEnd) break;
-
- while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
- if (remaining <= 3 || *src == '=') break;
- d = unbase64(*src++);
-
- *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
- }
-
- return scope.Close(Integer::New(dst - start, node_isolate));
- }
-
-
- Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
- HandleScope scope(node_isolate);
-
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
+ max_length = MIN(buffer->length_ - offset, max_length);
- if (!args[0]->IsString()) {
- return ThrowTypeError("Argument must be a string");
+ if (max_length == 0) {
+ // shortcut: nothing to write anyway
+ Local<Integer> val = Integer::New(0);
- constructor_template->GetFunction()->Set(chars_written_sym, val);
+ return scope.Close(val);
}
- Local<String> s = args[0]->ToString();
- size_t length = s->Length();
- size_t offset = args[1]->Int32Value();
+ if (encoding == UCS2)
+ max_length = max_length / 2;
- if (s->Length() > 0 && offset >= buffer->length_) {
+ if (offset >= buffer->length_) {
return ThrowTypeError("Offset is out of bounds");
}
- char *p = (char*)buffer->data_ + offset;
-
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(length, MIN(buffer->length_ - offset, max_length));
-
- int written = DecodeWrite(p, max_length, s, BINARY);
+ char* start = buffer->data_ + offset;
- int chars_written;
+ size_t written = StringBytes::Write(start,
+ max_length,
+ str,
+ encoding,
- &chars_written);
-
- constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(chars_written));
++ NULL);
- return scope.Close(Integer::New(written));
+ return scope.Close(Integer::New(written, node_isolate));
}
-
static bool is_big_endian() {
const union { uint8_t u8[2]; uint16_t u16; } u = {{0, 1}};
return u.u16 == 1 ? true : false;
Local<String> s = args[0]->ToString();
enum encoding e = ParseEncoding(args[1], UTF8);
- return scope.Close(Integer::New(node::ByteLength(s, e), node_isolate));
- return scope.Close(Integer::New(StringBytes::Size(s, e)));
++ return scope.Close(Integer::New(StringBytes::Size(s, e), node_isolate));
}
void Buffer::Initialize(Handle<Object> target) {
- HandleScope scope;
+ HandleScope scope(node_isolate);
- // sanity checks
- assert(unbase64('/') == 63);
- assert(unbase64('+') == 62);
- assert(unbase64('T') == 19);
- assert(unbase64('Z') == 25);
- assert(unbase64('t') == 45);
- assert(unbase64('z') == 51);
- assert(unbase64(' ') == -2);
- assert(unbase64('\n') == -2);
- assert(unbase64('\r') == -2);
-
length_symbol = NODE_PSYMBOL("length");
- chars_written_sym = NODE_PSYMBOL("_charsWritten");
Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
- constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template = Persistent<FunctionTemplate>::New(node_isolate, t);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
#endif
-class Cipher : public ObjectWrap {
- public:
- static void Initialize (v8::Handle<v8::Object> target) {
- HandleScope scope;
-
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+void CipherBase::Initialize(Handle<Object> target) {
+ HandleScope scope(node_isolate);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
- NODE_SET_PROTOTYPE_METHOD(t, "init", CipherInit);
- NODE_SET_PROTOTYPE_METHOD(t, "initiv", CipherInitIv);
- NODE_SET_PROTOTYPE_METHOD(t, "update", CipherUpdate);
- NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
- NODE_SET_PROTOTYPE_METHOD(t, "final", CipherFinal);
-
- target->Set(String::NewSymbol("Cipher"), t->GetFunction());
- }
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+ NODE_SET_PROTOTYPE_METHOD(t, "init", Init);
+ NODE_SET_PROTOTYPE_METHOD(t, "initiv", InitIv);
+ NODE_SET_PROTOTYPE_METHOD(t, "update", Update);
+ NODE_SET_PROTOTYPE_METHOD(t, "final", Final);
+ NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
- bool CipherInit(char* cipherType, char* key_buf, int key_buf_len) {
- cipher = EVP_get_cipherbyname(cipherType);
- if(!cipher) {
- fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
- return false;
- }
+ target->Set(String::NewSymbol("CipherBase"), t->GetFunction());
+}
- unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
- int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL,
- (unsigned char*) key_buf, key_buf_len, 1, key, iv);
- EVP_CIPHER_CTX_init(&ctx);
- EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
- if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
- fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- return false;
- }
- EVP_CipherInit_ex(&ctx, NULL, NULL,
- (unsigned char*)key,
- (unsigned char*)iv, true);
- initialised_ = true;
- return true;
- }
-
-
- bool CipherInitIv(char* cipherType,
- char* key,
- int key_len,
- char* iv,
- int iv_len) {
- cipher = EVP_get_cipherbyname(cipherType);
- if(!cipher) {
- fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
- return false;
- }
- /* OpenSSL versions up to 0.9.8l failed to return the correct
- iv_length (0) for ECB ciphers */
- if (EVP_CIPHER_iv_length(cipher) != iv_len &&
- !(EVP_CIPHER_mode(cipher) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
- fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len);
- return false;
- }
- EVP_CIPHER_CTX_init(&ctx);
- EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
- if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
- fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- return false;
- }
- EVP_CipherInit_ex(&ctx, NULL, NULL,
- (unsigned char*)key,
- (unsigned char*)iv, true);
- initialised_ = true;
- return true;
- }
+Handle<Value> CipherBase::New(const Arguments& args) {
+ HandleScope scope(node_isolate);
- int CipherUpdate(char* data, int len, unsigned char** out, int* out_len) {
- if (!initialised_) return 0;
- *out_len = len+EVP_CIPHER_CTX_block_size(&ctx);
- *out = new unsigned char[*out_len];
- return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len);
- }
+ CipherBase* cipher = new CipherBase(args[0]->IsTrue() ? kCipher : kDecipher);
+ cipher->Wrap(args.This());
+ return args.This();
+}
-
- int SetAutoPadding(bool auto_padding) {
- if (!initialised_) return 0;
- return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
- }
+Handle<Value> CipherBase::Init(char* cipher_type,
+ char* key_buf,
+ int key_buf_len) {
+ HandleScope scope(node_isolate);
- int CipherFinal(unsigned char** out, int *out_len) {
- if (!initialised_) return 0;
- *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
- int r = EVP_CipherFinal_ex(&ctx,*out, out_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- initialised_ = false;
- return r;
+ assert(cipher_ == NULL);
+ cipher_ = EVP_get_cipherbyname(cipher_type);
+ if (cipher_ == NULL) {
+ return ThrowError("Unknown cipher");
}
+ unsigned char key[EVP_MAX_KEY_LENGTH];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
- protected:
-
- static Handle<Value> New(const Arguments& args) {
- HandleScope scope;
+ int key_len = EVP_BytesToKey(cipher_,
+ EVP_md5(),
+ NULL,
+ reinterpret_cast<unsigned char*>(key_buf),
+ key_buf_len,
+ 1,
+ key,
+ iv);
- Cipher *cipher = new Cipher();
- cipher->Wrap(args.This());
- return args.This();
+ EVP_CIPHER_CTX_init(&ctx_);
+ EVP_CipherInit_ex(&ctx_, cipher_, NULL, NULL, NULL, kind_ == kCipher);
+ if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) {
+ EVP_CIPHER_CTX_cleanup(&ctx_);
+ return ThrowError("Invalid key length");
}
- static Handle<Value> CipherInit(const Arguments& args) {
- HandleScope scope;
-
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
-
- if (args.Length() <= 1
- || !args[0]->IsString()
- || !(args[1]->IsString() || Buffer::HasInstance(args[1])))
- {
- return ThrowException(Exception::Error(String::New(
- "Must give cipher-type, key")));
- }
+ EVP_CipherInit_ex(&ctx_,
+ NULL,
+ NULL,
+ reinterpret_cast<unsigned char*>(key),
+ reinterpret_cast<unsigned char*>(iv),
+ kind_ == kCipher);
+ initialised_ = true;
+ return Null(node_isolate);
+}
- ASSERT_IS_BUFFER(args[1]);
- ssize_t key_buf_len = Buffer::Length(args[1]);
- if (key_buf_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+Handle<Value> CipherBase::Init(const Arguments& args) {
+ HandleScope scope(node_isolate);
- char* key_buf = new char[key_buf_len];
- ssize_t key_written = DecodeWrite(key_buf, key_buf_len, args[1], BINARY);
- assert(key_written == key_buf_len);
+ CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
- String::Utf8Value cipherType(args[0]);
-
- bool r = cipher->CipherInit(*cipherType, key_buf, key_buf_len);
+ if (args.Length() < 2 ||
+ !(args[0]->IsString() && Buffer::HasInstance(args[1]))) {
+ return ThrowError("Must give cipher-type, key");
+ }
- delete [] key_buf;
+ String::Utf8Value cipher_type(args[0]);
+ char* key_buf = Buffer::Data(args[1]);
+ ssize_t key_buf_len = Buffer::Length(args[1]);
- if (!r) return ThrowCryptoError(ERR_get_error());
+ Handle<Value> ret = cipher->Init(*cipher_type, key_buf, key_buf_len);
+ if (ret->IsNull()) {
return args.This();
+ } else {
+ // Exception
+ return scope.Close(ret);
}
+}
- static Handle<Value> CipherInitIv(const Arguments& args) {
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
-
- HandleScope scope;
-
+Handle<Value> CipherBase::InitIv(char* cipher_type,
+ char* key,
+ int key_len,
+ char* iv,
+ int iv_len) {
+ HandleScope scope(node_isolate);
- if (args.Length() <= 2
- || !args[0]->IsString()
- || !(args[1]->IsString() || Buffer::HasInstance(args[1]))
- || !(args[2]->IsString() || Buffer::HasInstance(args[2])))
- {
- return ThrowException(Exception::Error(String::New(
- "Must give cipher-type, key, and iv as argument")));
- }
+ cipher_ = EVP_get_cipherbyname(cipher_type);
+ if (cipher_ == NULL) {
+ return ThrowError("Unknown cipher");
+ }
- ASSERT_IS_BUFFER(args[1]);
- ssize_t key_len = Buffer::Length(args[1]);
+ /* OpenSSL versions up to 0.9.8l failed to return the correct
+ iv_length (0) for ECB ciphers */
+ if (EVP_CIPHER_iv_length(cipher_) != iv_len &&
+ !(EVP_CIPHER_mode(cipher_) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
+ return ThrowError("Invalid IV length");
+ }
+ EVP_CIPHER_CTX_init(&ctx_);
+ EVP_CipherInit_ex(&ctx_, cipher_, NULL, NULL, NULL, kind_ == kCipher);
+ if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) {
+ EVP_CIPHER_CTX_cleanup(&ctx_);
+ return ThrowError("Invalid key length");
+ }
- if (key_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+ EVP_CipherInit_ex(&ctx_,
+ NULL,
+ NULL,
+ reinterpret_cast<unsigned char*>(key),
+ reinterpret_cast<unsigned char*>(iv),
+ kind_ == kCipher);
+ initialised_ = true;
+ return Null(node_isolate);
+}
- ASSERT_IS_BUFFER(args[2]);
- ssize_t iv_len = Buffer::Length(args[2]);
- if (iv_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+Handle<Value> CipherBase::InitIv(const Arguments& args) {
+ HandleScope scope(node_isolate);
- char* key_buf = new char[key_len];
- ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
- assert(key_written == key_len);
+ CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
- char* iv_buf = new char[iv_len];
- ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY);
- assert(iv_written == iv_len);
-
- String::Utf8Value cipherType(args[0]);
+ if (args.Length() < 3 || !args[0]->IsString()) {
+ return ThrowError("Must give cipher-type, key, and iv as argument");
+ }
- bool r = cipher->CipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
+ ASSERT_IS_BUFFER(args[1]);
+ ASSERT_IS_BUFFER(args[2]);
- delete [] key_buf;
- delete [] iv_buf;
+ String::Utf8Value cipher_type(args[0]);
+ ssize_t key_len = Buffer::Length(args[1]);
+ char* key_buf = Buffer::Data(args[1]);
+ ssize_t iv_len = Buffer::Length(args[2]);
+ char* iv_buf = Buffer::Data(args[2]);
- if (!r) return ThrowCryptoError(ERR_get_error());
+ Handle<Value> ret = cipher->InitIv(*cipher_type,
+ key_buf,
+ key_len,
+ iv_buf,
+ iv_len);
+ if (ret->IsNull()) {
return args.This();
+ } else {
+ // Exception
+ return scope.Close(ret);
}
+}
- static Handle<Value> CipherUpdate(const Arguments& args) {
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
- HandleScope scope;
+bool CipherBase::Update(char* data,
+ int len,
+ unsigned char** out,
+ int* out_len) {
+ if (!initialised_) return 0;
+ *out_len = len + EVP_CIPHER_CTX_block_size(&ctx_);
+ *out = new unsigned char[*out_len];
+ return EVP_CipherUpdate(&ctx_,
+ *out,
+ out_len,
+ reinterpret_cast<unsigned char*>(data),
+ len);
+}
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
- // Only copy the data if we have to, because it's a string
- unsigned char* out = 0;
- int out_len = 0, r;
- if (args[0]->IsString()) {
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- size_t buflen = StringBytes::StorageSize(args[0], encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
- r = cipher->CipherUpdate(buf, written, &out, &out_len);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = cipher->CipherUpdate(buf, buflen, &out, &out_len);
- }
+Handle<Value> CipherBase::Update(const Arguments& args) {
+ HandleScope scope(node_isolate);
- if (r == 0) {
- delete[] out;
- return ThrowCryptoTypeError(ERR_get_error());
- }
+ CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
- ASSERT_IS_BUFFER(args[0]);
- Local<Value> outString;
- outString = Encode(out, out_len, BUFFER);
++ ASSERT_IS_STRING_OR_BUFFER(args[0]);
- if (out) delete[] out;
+ unsigned char* out = NULL;
+ bool r;
+ int out_len = 0;
- char* buffer_data = Buffer::Data(args[0]);
- size_t buffer_length = Buffer::Length(args[0]);
- r = cipher->Update(buffer_data, buffer_length, &out, &out_len);
- return scope.Close(outString);
++ // Only copy the data if we have to, because it's a string
++ if (args[0]->IsString()) {
++ enum encoding encoding = ParseEncoding(args[1], BINARY);
++ size_t buflen = StringBytes::StorageSize(args[0], encoding);
++ char* buf = new char[buflen];
++ size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++ r = cipher->Update(buf, written, &out, &out_len);
++ delete[] buf;
++ } else {
++ char* buf = Buffer::Data(args[0]);
++ size_t buflen = Buffer::Length(args[0]);
++ r = cipher->Update(buf, buflen, &out, &out_len);
+ }
- static Handle<Value> SetAutoPadding(const Arguments& args) {
- HandleScope scope;
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
-
- cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
-
- return Undefined();
+ if (!r) {
+ delete[] out;
+ return ThrowCryptoTypeError(ERR_get_error());
}
- static Handle<Value> CipherFinal(const Arguments& args) {
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
-
- HandleScope scope;
+ Buffer* buf = Buffer::New(reinterpret_cast<char*>(out), out_len);
- unsigned char* out_value = NULL;
- int out_len = -1;
- Local<Value> outString ;
++ if (out) delete[] out;
+
- int r = cipher->CipherFinal(&out_value, &out_len);
+ return scope.Close(buf->handle_);
+}
- if (out_len <= 0 || r == 0) {
- delete[] out_value;
- out_value = NULL;
- if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
- }
- outString = Encode(out_value, out_len, BUFFER);
+bool CipherBase::SetAutoPadding(bool auto_padding) {
+ if (!initialised_) return false;
+ return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding);
+}
- delete [] out_value;
- return scope.Close(outString);
- }
- Cipher () : ObjectWrap ()
- {
- initialised_ = false;
- }
+Handle<Value> CipherBase::SetAutoPadding(const Arguments& args) {
+ HandleScope scope(node_isolate);
- ~Cipher () {
- if (initialised_) {
- EVP_CIPHER_CTX_cleanup(&ctx);
- }
- }
+ CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
- private:
+ cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
- EVP_CIPHER_CTX ctx; /* coverity[member_decl] */
- const EVP_CIPHER *cipher; /* coverity[member_decl] */
- bool initialised_;
-};
+ return Undefined(node_isolate);
+}
+bool CipherBase::Final(unsigned char** out, int *out_len) {
+ if (!initialised_) return false;
-class Decipher : public ObjectWrap {
- public:
- static void
- Initialize (v8::Handle<v8::Object> target)
- {
- HandleScope scope;
+ *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;
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ return r;
+}
- 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);
+Handle<Value> CipherBase::Final(const Arguments& args) {
+ HandleScope scope(node_isolate);
- target->Set(String::NewSymbol("Decipher"), t->GetFunction());
- }
+ CipherBase* cipher = ObjectWrap::Unwrap<CipherBase>(args.This());
- bool DecipherInit(char* cipherType, char* key_buf, int key_buf_len) {
- cipher_ = EVP_get_cipherbyname(cipherType);
+ unsigned char* out_value = NULL;
+ int out_len = -1;
+ Local<Value> outString;
- if(!cipher_) {
- fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
- return false;
- }
+ bool r = cipher->Final(&out_value, &out_len);
- 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];
-
- return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len);
+ if (out_len <= 0 || !r) {
+ delete[] out_value;
+ out_value = NULL;
+ out_len = 0;
+ if (!r) return ThrowCryptoTypeError(ERR_get_error());
}
- int SetAutoPadding(bool auto_padding) {
- if (!initialised_) return 0;
- return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
- }
+ Buffer* buf = Buffer::New(reinterpret_cast<char*>(out_value), out_len);
- // coverity[alloc_arg]
- int DecipherFinal(unsigned char** out, int *out_len) {
- int r;
+ return scope.Close(buf->handle_);
+}
- if (!initialised_) {
- *out_len = 0;
- *out = NULL;
- return 0;
- }
- *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
- r = EVP_CipherFinal_ex(&ctx,*out,out_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- initialised_ = false;
- return r;
- }
+void Hmac::Initialize(v8::Handle<v8::Object> target) {
+ HandleScope scope(node_isolate);
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
- protected:
+ t->InstanceTemplate()->SetInternalFieldCount(1);
- static Handle<Value> New (const Arguments& args) {
- HandleScope scope;
+ NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit);
+ NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate);
+ NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest);
- Decipher *cipher = new Decipher();
- cipher->Wrap(args.This());
- return args.This();
- }
+ target->Set(String::NewSymbol("Hmac"), t->GetFunction());
+}
- static Handle<Value> DecipherInit(const Arguments& args) {
- Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
- HandleScope scope;
+Handle<Value> Hmac::New(const Arguments& args) {
+ HandleScope scope(node_isolate);
- if (args.Length() <= 1
- || !args[0]->IsString()
- || !(args[1]->IsString() || Buffer::HasInstance(args[1])))
- {
- return ThrowException(Exception::Error(String::New(
- "Must give cipher-type, key as argument")));
- }
+ Hmac* hmac = new Hmac();
+ hmac->Wrap(args.This());
+ return args.This();
+}
- ASSERT_IS_BUFFER(args[1]);
- ssize_t key_len = Buffer::Length(args[1]);
- if (key_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+Handle<Value> Hmac::HmacInit(char* hashType, char* key, int key_len) {
+ HandleScope scope(node_isolate);
- char* key_buf = new char[key_len];
- ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
- assert(key_written == key_len);
+ assert(md_ == NULL);
+ md_ = EVP_get_digestbyname(hashType);
+ if (md_ == NULL) {
+ return ThrowError("Unknown message digest");
+ }
+ HMAC_CTX_init(&ctx_);
+ if (key_len == 0) {
+ HMAC_Init(&ctx_, "", 0, md_);
+ } else {
+ HMAC_Init(&ctx_, key, key_len, md_);
+ }
+ initialised_ = true;
- String::Utf8Value cipherType(args[0]);
+ return Null(node_isolate);
+}
- bool r = cipher->DecipherInit(*cipherType, key_buf,key_len);
- delete [] key_buf;
+Handle<Value> Hmac::HmacInit(const Arguments& args) {
+ HandleScope scope(node_isolate);
- if (!r) {
- return ThrowException(Exception::Error(String::New("DecipherInit error")));
- }
+ Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
- return args.This();
+ if (args.Length() < 2 || !args[0]->IsString()) {
+ return ThrowError("Must give hashtype string, key as arguments");
}
- static Handle<Value> DecipherInitIv(const Arguments& args) {
- Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
+
- HandleScope scope;
+ ASSERT_IS_BUFFER(args[1]);
- if (args.Length() <= 2
- || !args[0]->IsString()
- || !(args[1]->IsString() || Buffer::HasInstance(args[1]))
- || !(args[2]->IsString() || Buffer::HasInstance(args[2])))
- {
- return ThrowException(Exception::Error(String::New(
- "Must give cipher-type, key, and iv as argument")));
- }
+ String::Utf8Value hashType(args[0]);
- ASSERT_IS_BUFFER(args[1]);
- ssize_t key_len = Buffer::Length(args[1]);
+ char* buffer_data = Buffer::Data(args[1]);
+ size_t buffer_length = Buffer::Length(args[1]);
- if (key_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+ Handle<Value> ret = hmac->HmacInit(*hashType, buffer_data, buffer_length);
- ASSERT_IS_BUFFER(args[2]);
- ssize_t iv_len = Buffer::Length(args[2]);
+ if (ret->IsNull()) {
+ return args.This();
+ } else {
+ // Exception
+ return ret;
+ }
+}
- if (iv_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
- char* key_buf = new char[key_len];
- ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
- assert(key_written == key_len);
+bool Hmac::HmacUpdate(char* data, int len) {
+ if (!initialised_) return false;
+ HMAC_Update(&ctx_, reinterpret_cast<unsigned char*>(data), len);
+ return true;
+}
- char* iv_buf = new char[iv_len];
- ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY);
- assert(iv_written == iv_len);
- String::Utf8Value cipherType(args[0]);
+Handle<Value> Hmac::HmacUpdate(const Arguments& args) {
+ HandleScope scope(node_isolate);
- bool r = cipher->DecipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
+ Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
- ASSERT_IS_BUFFER(args[0]);
- delete [] key_buf;
- delete [] iv_buf;
++ ASSERT_IS_STRING_OR_BUFFER(args[0]);
- if (!r) {
- return ThrowException(Exception::Error(String::New("DecipherInitIv error")));
- }
++ // Only copy the data if we have to, because it's a string
+ bool r;
-
- char* buffer_data = Buffer::Data(args[0]);
- size_t buffer_length = Buffer::Length(args[0]);
-
- r = hmac->HmacUpdate(buffer_data, buffer_length);
++ if (args[0]->IsString()) {
++ enum encoding encoding = ParseEncoding(args[1], BINARY);
++ size_t buflen = StringBytes::StorageSize(args[0], encoding);
++ char* buf = new char[buflen];
++ size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++ r = hmac->HmacUpdate(buf, written);
++ delete[] buf;
++ } else {
++ char* buf = Buffer::Data(args[0]);
++ size_t buflen = Buffer::Length(args[0]);
++ r = hmac->HmacUpdate(buf, buflen);
++ }
- return args.This();
+ if (!r) {
+ return ThrowTypeError("HmacUpdate fail");
}
- static Handle<Value> DecipherUpdate(const Arguments& args) {
- HandleScope scope;
+ return args.This();
+}
- Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
+bool Hmac::HmacDigest(unsigned char** md_value, unsigned int* md_len) {
+ if (!initialised_) return false;
+ *md_value = new unsigned char[EVP_MAX_MD_SIZE];
+ HMAC_Final(&ctx_, *md_value, md_len);
+ HMAC_CTX_cleanup(&ctx_);
+ initialised_ = false;
+ return true;
+}
- // Only copy the data if we have to, because it's a string
- unsigned char* out = 0;
- int out_len = 0, r;
- if (args[0]->IsString()) {
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- size_t buflen = StringBytes::StorageSize(args[0], encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
- r = cipher->DecipherUpdate(buf, written, &out, &out_len);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = cipher->DecipherUpdate(buf, buflen, &out, &out_len);
- }
- if (r == 0) {
- delete[] out;
- return ThrowCryptoTypeError(ERR_get_error());
- }
+Handle<Value> Hmac::HmacDigest(const Arguments& args) {
+ HandleScope scope(node_isolate);
+
+ Hmac* hmac = ObjectWrap::Unwrap<Hmac>(args.This());
- Local<Value> outString;
- outString = Encode(out, out_len, BUFFER);
++ enum encoding encoding = BUFFER;
++ if (args.Length() >= 1) {
++ encoding = ParseEncoding(args[0]->ToString(), BUFFER);
++ }
+
- if (out) delete [] out;
+ unsigned char* md_value = NULL;
+ unsigned int md_len = 0;
+ Local<Value> outString;
- return scope.Close(outString);
+ bool r = hmac->HmacDigest(&md_value, &md_len);
+ if (!r) {
+ md_value = NULL;
+ md_len = 0;
}
- Buffer* buf = Buffer::New(reinterpret_cast<char*>(md_value), md_len);
- static Handle<Value> SetAutoPadding(const Arguments& args) {
- HandleScope scope;
- Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
++ outString = StringBytes::Encode(
++ reinterpret_cast<const char*>(md_value), md_len, encoding);
- return scope.Close(buf->handle_);
- cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
++ delete[] md_value;
++ return scope.Close(outString);
+}
- return Undefined();
- }
- static Handle<Value> DecipherFinal(const Arguments& args) {
- HandleScope scope;
+void Hash::Initialize(v8::Handle<v8::Object> target) {
+ HandleScope scope(node_isolate);
- Decipher *cipher = ObjectWrap::Unwrap<Decipher>(args.This());
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
- unsigned char* out_value = NULL;
- int out_len = -1;
- Local<Value> outString;
+ t->InstanceTemplate()->SetInternalFieldCount(1);
- int r = cipher->DecipherFinal(&out_value, &out_len);
+ NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate);
+ NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest);
- if (out_len <= 0 || r == 0) {
- delete [] out_value; // allocated even if out_len == 0
- out_value = NULL;
- if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
- }
+ target->Set(String::NewSymbol("Hash"), t->GetFunction());
+}
- outString = Encode(out_value, out_len, BUFFER);
- delete [] out_value;
- return scope.Close(outString);
- }
- Decipher () : ObjectWrap () {
- initialised_ = false;
- }
+Handle<Value> Hash::New(const Arguments& args) {
+ HandleScope scope(node_isolate);
- ~Decipher () {
- if (initialised_) {
- EVP_CIPHER_CTX_cleanup(&ctx);
- }
+ if (args.Length() == 0 || !args[0]->IsString()) {
+ return ThrowError("Must give hashtype string as argument");
}
- private:
+ String::Utf8Value hashType(args[0]);
- EVP_CIPHER_CTX ctx;
- const EVP_CIPHER *cipher_;
- bool initialised_;
-};
+ Hash* hash = new Hash();
+ if (!hash->HashInit(*hashType)) {
+ delete hash;
+ return ThrowError("Digest method not supported");
+ }
+ hash->Wrap(args.This());
+ return args.This();
+}
+bool Hash::HashInit(const char* hashType) {
+ assert(md_ == NULL);
+ md_ = EVP_get_digestbyname(hashType);
+ if (md_ == NULL) return false;
+ EVP_MD_CTX_init(&mdctx_);
+ EVP_DigestInit_ex(&mdctx_, md_, NULL);
+ initialised_ = true;
+ return true;
+}
-class Hmac : public ObjectWrap {
- public:
- static void Initialize (v8::Handle<v8::Object> target) {
- HandleScope scope;
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+bool Hash::HashUpdate(char* data, int len) {
+ if (!initialised_) return false;
+ EVP_DigestUpdate(&mdctx_, data, len);
+ return true;
+}
- t->InstanceTemplate()->SetInternalFieldCount(1);
- NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit);
- NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate);
- NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest);
+Handle<Value> Hash::HashUpdate(const Arguments& args) {
+ HandleScope scope(node_isolate);
- target->Set(String::NewSymbol("Hmac"), t->GetFunction());
- }
+ Hash* hash = ObjectWrap::Unwrap<Hash>(args.This());
- ASSERT_IS_BUFFER(args[0]);
- bool HmacInit(char* hashType, char* key, int key_len) {
- md = EVP_get_digestbyname(hashType);
- if(!md) {
- fprintf(stderr, "node-crypto : Unknown message digest %s\n", hashType);
- return false;
- }
- HMAC_CTX_init(&ctx);
- if (key_len == 0) {
- HMAC_Init(&ctx, "", 0, md);
- } else {
- HMAC_Init(&ctx, key, key_len, md);
- }
- initialised_ = true;
- return true;
++ ASSERT_IS_STRING_OR_BUFFER(args[0]);
-
- char* buffer_data = Buffer::Data(args[0]);
- size_t buffer_length = Buffer::Length(args[0]);
- r = hash->HashUpdate(buffer_data, buffer_length);
++ // Only copy the data if we have to, because it's a string
+ bool r;
++ if (args[0]->IsString()) {
++ enum encoding encoding = ParseEncoding(args[1], BINARY);
++ size_t buflen = StringBytes::StorageSize(args[0], encoding);
++ char* buf = new char[buflen];
++ size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++ r = hash->HashUpdate(buf, written);
++ delete[] buf;
++ } else {
++ char* buf = Buffer::Data(args[0]);
++ size_t buflen = Buffer::Length(args[0]);
++ r = hash->HashUpdate(buf, buflen);
+ }
- int HmacUpdate(char* data, int len) {
- if (!initialised_) return 0;
- HMAC_Update(&ctx, (unsigned char*)data, len);
- return 1;
+ if (!r) {
+ return ThrowTypeError("HashUpdate fail");
}
- int HmacDigest(unsigned char** md_value, unsigned int *md_len) {
- if (!initialised_) return 0;
- *md_value = new unsigned char[EVP_MAX_MD_SIZE];
- HMAC_Final(&ctx, *md_value, md_len);
- HMAC_CTX_cleanup(&ctx);
- initialised_ = false;
- return 1;
- }
+ return args.This();
+}
- protected:
+Handle<Value> Hash::HashDigest(const Arguments& args) {
+ HandleScope scope(node_isolate);
- static Handle<Value> New (const Arguments& args) {
- HandleScope scope;
+ Hash* hash = ObjectWrap::Unwrap<Hash>(args.This());
- Hmac *hmac = new Hmac();
- hmac->Wrap(args.This());
- return args.This();
+ if (!hash->initialised_) {
+ return ThrowError("Not initialized");
}
- static Handle<Value> HmacInit(const Arguments& args) {
- Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
-
- HandleScope scope;
++ enum encoding encoding = BUFFER;
++ if (args.Length() >= 1) {
++ encoding = ParseEncoding(args[0]->ToString(), BUFFER);
++ }
+
- if (args.Length() == 0 || !args[0]->IsString()) {
- return ThrowException(Exception::Error(String::New(
- "Must give hashtype string as argument")));
- }
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
- ASSERT_IS_BUFFER(args[1]);
- ssize_t len = Buffer::Length(args[1]);
+ EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len);
+ EVP_MD_CTX_cleanup(&hash->mdctx_);
+ hash->initialised_ = false;
- Buffer* buf = Buffer::New(reinterpret_cast<char*>(md_value), md_len);
- if (len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
--
- return scope.Close(buf->handle_);
- String::Utf8Value hashType(args[0]);
++ return scope.Close(StringBytes::Encode(
++ reinterpret_cast<const char*>(md_value), md_len, encoding));
+}
- bool r;
- if( Buffer::HasInstance(args[1])) {
- char* buffer_data = Buffer::Data(args[1]);
- size_t buffer_length = Buffer::Length(args[1]);
+void Sign::Initialize(v8::Handle<v8::Object> target) {
+ HandleScope scope(node_isolate);
- 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);
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
- r = hmac->HmacInit(*hashType, buf, len);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
- delete [] buf;
- }
+ NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit);
+ NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate);
+ NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal);
- if (!r) {
- return ThrowException(Exception::Error(String::New("hmac error")));
- }
-
- return args.This();
- }
+ target->Set(String::NewSymbol("Sign"), t->GetFunction());
+}
- static Handle<Value> HmacUpdate(const Arguments& args) {
- Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
- HandleScope scope;
+Handle<Value> Sign::New(const Arguments& args) {
+ HandleScope scope(node_isolate);
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
+ Sign* sign = new Sign();
+ sign->Wrap(args.This());
- // Only copy the data if we have to, because it's a string
- int r;
- if (args[0]->IsString()) {
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- size_t buflen = StringBytes::StorageSize(args[0], encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
- r = hmac->HmacUpdate(buf, written);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = hmac->HmacUpdate(buf, buflen);
- }
+ return args.This();
+}
-
- if (!r) {
- Local<Value> exception = Exception::TypeError(String::New("HmacUpdate fail"));
- return ThrowException(exception);
- }
+Handle<Value> Sign::SignInit(const char* sign_type) {
+ HandleScope scope(node_isolate);
- return args.This();
+ assert(md_ == NULL);
+ md_ = EVP_get_digestbyname(sign_type);
+ if (!md_) {
+ return ThrowError("Uknown message digest");
}
+ EVP_MD_CTX_init(&mdctx_);
+ EVP_SignInit_ex(&mdctx_, md_, NULL);
+ initialised_ = true;
+ return Null(node_isolate);
+}
- static Handle<Value> HmacDigest(const Arguments& args) {
- Hmac *hmac = ObjectWrap::Unwrap<Hmac>(args.This());
-
- HandleScope scope;
-
- enum encoding encoding = BUFFER;
- if (args.Length() >= 1) {
- encoding = ParseEncoding(args[0]->ToString(), BUFFER);
- }
-
- unsigned char* md_value = NULL;
- unsigned int md_len = 0;
- Local<Value> outString;
- int r = hmac->HmacDigest(&md_value, &md_len);
- if (r == 0) {
- md_value = NULL;
- md_len = 0;
- }
+Handle<Value> Sign::SignInit(const Arguments& args) {
+ HandleScope scope(node_isolate);
- outString = StringBytes::Encode(
- reinterpret_cast<const char*>(md_value), md_len, encoding);
+ Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
- delete[] md_value;
- return scope.Close(outString);
+ if (args.Length() == 0 || !args[0]->IsString()) {
+ return ThrowError("Must give signtype string as argument");
}
- Hmac () : ObjectWrap () {
- initialised_ = false;
- }
+ String::Utf8Value sign_type(args[0]);
- ~Hmac () {
- if (initialised_) {
- HMAC_CTX_cleanup(&ctx);
- }
- }
+ Handle<Value> ret = sign->SignInit(*sign_type);
- private:
+ if (ret->IsNull()) {
+ return args.This();
+ } else {
+ // Exception
+ return scope.Close(ret);
+ }
+}
- HMAC_CTX ctx; /* coverity[member_decl] */
- const EVP_MD *md; /* coverity[member_decl] */
- bool initialised_;
-};
+bool Sign::SignUpdate(char* data, int len) {
+ if (!initialised_) return false;
+ EVP_SignUpdate(&mdctx_, data, len);
+ return true;
+}
-class Hash : public ObjectWrap {
- public:
- static void Initialize (v8::Handle<v8::Object> target) {
- HandleScope scope;
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+Handle<Value> Sign::SignUpdate(const Arguments& args) {
+ HandleScope scope(node_isolate);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
- ASSERT_IS_BUFFER(args[0]);
-
- bool r;
-
- char* buffer_data = Buffer::Data(args[0]);
- size_t buffer_length = Buffer::Length(args[0]);
- NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate);
- NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest);
++ ASSERT_IS_STRING_OR_BUFFER(args[0]);
- r = sign->SignUpdate(buffer_data, buffer_length);
- target->Set(String::NewSymbol("Hash"), t->GetFunction());
++ // Only copy the data if we have to, because it's a string
++ int r;
++ if (args[0]->IsString()) {
++ enum encoding encoding = ParseEncoding(args[1], BINARY);
++ size_t buflen = StringBytes::StorageSize(args[0], encoding);
++ char* buf = new char[buflen];
++ size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++ r = sign->SignUpdate(buf, written);
++ delete[] buf;
++ } else {
++ char* buf = Buffer::Data(args[0]);
++ size_t buflen = Buffer::Length(args[0]);
++ r = sign->SignUpdate(buf, buflen);
+ }
- bool HashInit (const char* hashType) {
- md = EVP_get_digestbyname(hashType);
- if(!md) return false;
- EVP_MD_CTX_init(&mdctx);
- EVP_DigestInit_ex(&mdctx, md, NULL);
- initialised_ = true;
- return true;
+ if (!r) {
+ return ThrowTypeError("SignUpdate fail");
}
- int HashUpdate(char* data, int len) {
- if (!initialised_) return 0;
- EVP_DigestUpdate(&mdctx, data, len);
- return 1;
- }
+ return args.This();
+}
- protected:
+bool Sign::SignFinal(unsigned char** md_value,
+ unsigned int *md_len,
+ char* key_pem,
+ int key_pem_len) {
+ if (!initialised_) return false;
- static Handle<Value> New (const Arguments& args) {
- HandleScope scope;
+ BIO* bp = NULL;
+ EVP_PKEY* pkey = NULL;
+ bp = BIO_new(BIO_s_mem());
+ if (!BIO_write(bp, key_pem, key_pem_len)) return false;
- if (args.Length() == 0 || !args[0]->IsString()) {
- return ThrowException(Exception::Error(String::New(
- "Must give hashtype string as argument")));
- }
+ pkey = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
+ if (pkey == NULL) return 0;
- String::Utf8Value hashType(args[0]);
+ EVP_SignFinal(&mdctx_, *md_value, md_len, pkey);
+ EVP_MD_CTX_cleanup(&mdctx_);
+ initialised_ = false;
+ EVP_PKEY_free(pkey);
+ BIO_free_all(bp);
+ return true;
+}
- Hash *hash = new Hash();
- if (!hash->HashInit(*hashType)) {
- delete hash;
- return ThrowException(Exception::Error(String::New(
- "Digest method not supported")));
- }
- hash->Wrap(args.This());
- return args.This();
- }
+Handle<Value> Sign::SignFinal(const Arguments& args) {
+ HandleScope scope(node_isolate);
- static Handle<Value> HashUpdate(const Arguments& args) {
- HandleScope scope;
+ Sign* sign = ObjectWrap::Unwrap<Sign>(args.This());
- Hash *hash = ObjectWrap::Unwrap<Hash>(args.This());
+ unsigned char* md_value;
+ unsigned int md_len;
+ Local<Value> outString;
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
++ enum encoding encoding = BUFFER;
++ if (args.Length() >= 2) {
++ encoding = ParseEncoding(args[1]->ToString(), BUFFER);
++ }
+
- // Only copy the data if we have to, because it's a string
- int r;
- if (args[0]->IsString()) {
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- size_t buflen = StringBytes::StorageSize(args[0], encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
- r = hash->HashUpdate(buf, written);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = hash->HashUpdate(buf, buflen);
- }
+ ASSERT_IS_BUFFER(args[0]);
+ ssize_t len = Buffer::Length(args[0]);
+ char* buf = Buffer::Data(args[0]);
- if (!r) {
- Local<Value> exception = Exception::TypeError(String::New("HashUpdate fail"));
- return ThrowException(exception);
- }
+ md_len = 8192; // Maximum key size is 8192 bits
+ md_value = new unsigned char[md_len];
- return args.This();
+ bool r = sign->SignFinal(&md_value, &md_len, buf, len);
+ if (!r) {
+ delete[] md_value;
+ md_value = NULL;
+ md_len = 0;
}
- Buffer* ret = Buffer::New(reinterpret_cast<char*>(md_value), md_len);
- delete[] md_value;
- static Handle<Value> HashDigest(const Arguments& args) {
- HandleScope scope;
++ outString = StringBytes::Encode(
++ reinterpret_cast<const char*>(md_value), md_len, encoding);
- return scope.Close(ret->handle_);
- Hash *hash = ObjectWrap::Unwrap<Hash>(args.This());
-
- if (!hash->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
- }
++ delete[] md_value;
++ return scope.Close(outString);
+}
- enum encoding encoding = BUFFER;
- if (args.Length() >= 1) {
- encoding = ParseEncoding(args[0]->ToString(), BUFFER);
- }
- unsigned char md_value[EVP_MAX_MD_SIZE];
- unsigned int md_len;
+void Verify::Initialize(v8::Handle<v8::Object> target) {
+ HandleScope scope(node_isolate);
- EVP_DigestFinal_ex(&hash->mdctx, md_value, &md_len);
- EVP_MD_CTX_cleanup(&hash->mdctx);
- hash->initialised_ = false;
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
- return scope.Close(StringBytes::Encode(
- reinterpret_cast<const char*>(md_value), md_len, encoding));
- }
+ t->InstanceTemplate()->SetInternalFieldCount(1);
- Hash () : ObjectWrap () {
- initialised_ = false;
- }
+ NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit);
+ NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate);
+ NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal);
- ~Hash () {
- if (initialised_) {
- EVP_MD_CTX_cleanup(&mdctx);
- }
- }
+ target->Set(String::NewSymbol("Verify"), t->GetFunction());
+}
- private:
- EVP_MD_CTX mdctx; /* coverity[member_decl] */
- const EVP_MD *md; /* coverity[member_decl] */
- bool initialised_;
-};
+Handle<Value> Verify::New(const Arguments& args) {
+ HandleScope scope(node_isolate);
-class Sign : public ObjectWrap {
- public:
- static void
- Initialize (v8::Handle<v8::Object> target) {
- HandleScope scope;
+ Verify* verify = new Verify();
+ verify->Wrap(args.This());
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ return args.This();
+}
- t->InstanceTemplate()->SetInternalFieldCount(1);
- NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit);
- NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate);
- NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal);
+Handle<Value> Verify::VerifyInit(const char* verify_type) {
+ HandleScope scope(node_isolate);
- target->Set(String::NewSymbol("Sign"), t->GetFunction());
+ assert(md_ == NULL);
+ md_ = EVP_get_digestbyname(verify_type);
+ if (md_ == NULL) {
+ return ThrowError("Unknown message digest");
}
- bool SignInit (const char* signType) {
- md = EVP_get_digestbyname(signType);
- if(!md) {
- printf("Unknown message digest %s\n", signType);
- return false;
- }
- EVP_MD_CTX_init(&mdctx);
- EVP_SignInit_ex(&mdctx, md, NULL);
- initialised_ = true;
- return true;
-
- }
+ EVP_MD_CTX_init(&mdctx_);
+ EVP_VerifyInit_ex(&mdctx_, md_, NULL);
+ initialised_ = true;
- int SignUpdate(char* data, int len) {
- if (!initialised_) return 0;
- EVP_SignUpdate(&mdctx, data, len);
- return 1;
- }
+ return Null(node_isolate);
+}
- int SignFinal(unsigned char** md_value,
- unsigned int *md_len,
- char* key_pem,
- int key_pemLen) {
- if (!initialised_) return 0;
- BIO *bp = NULL;
- EVP_PKEY* pkey;
- bp = BIO_new(BIO_s_mem());
- if(!BIO_write(bp, key_pem, key_pemLen)) return 0;
+Handle<Value> Verify::VerifyInit(const Arguments& args) {
+ HandleScope scope(node_isolate);
- pkey = PEM_read_bio_PrivateKey( bp, NULL, NULL, NULL );
- if (pkey == NULL) return 0;
+ Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
- EVP_SignFinal(&mdctx, *md_value, md_len, pkey);
- EVP_MD_CTX_cleanup(&mdctx);
- initialised_ = false;
- EVP_PKEY_free(pkey);
- BIO_free(bp);
- return 1;
+ if (args.Length() == 0 || !args[0]->IsString()) {
+ return ThrowError("Must give verifytype string as argument");
}
+ String::Utf8Value verify_type(args[0]);
- protected:
-
- static Handle<Value> New (const Arguments& args) {
- HandleScope scope;
-
- Sign *sign = new Sign();
- sign->Wrap(args.This());
+ Handle<Value> ret = verify->VerifyInit(*verify_type);
+ if (ret->IsNull()) {
return args.This();
+ } else {
+ // Exception
+ return scope.Close(ret);
}
+}
- static Handle<Value> SignInit(const Arguments& args) {
- HandleScope scope;
- Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
+bool Verify::VerifyUpdate(char* data, int len) {
+ if (!initialised_) return false;
+ EVP_VerifyUpdate(&mdctx_, data, len);
+ return true;
+}
- if (args.Length() == 0 || !args[0]->IsString()) {
- return ThrowException(Exception::Error(String::New(
- "Must give signtype string as argument")));
- }
- String::Utf8Value signType(args[0]);
+Handle<Value> Verify::VerifyUpdate(const Arguments& args) {
+ HandleScope scope(node_isolate);
- bool r = sign->SignInit(*signType);
+ Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
- ASSERT_IS_BUFFER(args[0]);
- if (!r) {
- return ThrowException(Exception::Error(String::New("SignInit error")));
- }
++ ASSERT_IS_STRING_OR_BUFFER(args[0]);
- return args.This();
++ // Only copy the data if we have to, because it's a string
+ bool r;
-
- char* buffer_data = Buffer::Data(args[0]);
- size_t buffer_length = Buffer::Length(args[0]);
-
- r = verify->VerifyUpdate(buffer_data, buffer_length);
++ if (args[0]->IsString()) {
++ enum encoding encoding = ParseEncoding(args[1], BINARY);
++ size_t buflen = StringBytes::StorageSize(args[0], encoding);
++ char* buf = new char[buflen];
++ size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
++ r = verify->VerifyUpdate(buf, written);
++ delete[] buf;
++ } else {
++ char* buf = Buffer::Data(args[0]);
++ size_t buflen = Buffer::Length(args[0]);
++ r = verify->VerifyUpdate(buf, buflen);
+ }
- static Handle<Value> SignUpdate(const Arguments& args) {
- Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
-
- HandleScope scope;
-
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
-
- // Only copy the data if we have to, because it's a string
- int r;
- if (args[0]->IsString()) {
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- size_t buflen = StringBytes::StorageSize(args[0], encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
- r = sign->SignUpdate(buf, written);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = sign->SignUpdate(buf, buflen);
- }
-
- if (!r) {
- Local<Value> exception = Exception::TypeError(String::New("SignUpdate fail"));
- return ThrowException(exception);
- }
-
- return args.This();
+ if (!r) {
+ return ThrowTypeError("VerifyUpdate fail");
}
- static Handle<Value> SignFinal(const Arguments& args) {
- Sign *sign = ObjectWrap::Unwrap<Sign>(args.This());
-
- HandleScope scope;
-
- unsigned char* md_value;
- unsigned int md_len;
- Local<Value> outString;
+ return args.This();
+}
- ASSERT_IS_BUFFER(args[0]);
- ssize_t len = Buffer::Length(args[0]);
- enum encoding encoding = BUFFER;
- if (args.Length() >= 2) {
- encoding = ParseEncoding(args[1]->ToString(), BUFFER);
- }
+Handle<Value> Verify::VerifyFinal(char* key_pem,
+ int key_pem_len,
+ unsigned char* sig,
+ int siglen) {
+ HandleScope scope(node_isolate);
- char* buf = new char[len];
- ssize_t written = DecodeWrite(buf, len, args[0], BUFFER);
- assert(written == len);
+ if (!initialised_) {
+ return ThrowError("Verify not initalised");
+ }
- md_len = 8192; // Maximum key size is 8192 bits
- md_value = new unsigned char[md_len];
+ EVP_PKEY* pkey = NULL;
+ BIO* bp = NULL;
+ X509* x509 = NULL;
+ bool fatal = true;
+ int r;
- int r = sign->SignFinal(&md_value, &md_len, buf, len);
- if (r == 0) {
- md_value = NULL;
- md_len = r;
+ bp = BIO_new(BIO_s_mem());
+ if (bp == NULL)
+ goto exit;
+
+ if (!BIO_write(bp, key_pem, key_pem_len))
+ goto exit;
+
+ // Check if this is a PKCS#8 or RSA public key before trying as X.509.
+ // Split this out into a separate function once we have more than one
+ // consumer of public keys.
+ if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
+ pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
+ if (pkey == NULL)
+ goto exit;
+ } else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
+ RSA* rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
+ if (rsa) {
+ pkey = EVP_PKEY_new();
+ if (pkey) EVP_PKEY_set1_RSA(pkey, rsa);
+ RSA_free(rsa);
}
+ if (pkey == NULL)
+ goto exit;
+ } else {
+ // X.509 fallback
+ x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL);
+ if (x509 == NULL)
+ goto exit;
- delete [] buf;
+ pkey = X509_get_pubkey(x509);
+ if (pkey == NULL)
+ goto exit;
+ }
- outString = StringBytes::Encode(
- reinterpret_cast<const char*>(md_value), md_len, encoding);
+ fatal = false;
+ r = EVP_VerifyFinal(&mdctx_, sig, siglen, pkey);
- delete [] md_value;
- return scope.Close(outString);
- }
+exit:
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+ if (bp != NULL)
+ BIO_free_all(bp);
+ if (x509 != NULL)
+ X509_free(x509);
- Sign () : ObjectWrap () {
- initialised_ = false;
- }
+ EVP_MD_CTX_cleanup(&mdctx_);
+ initialised_ = false;
- ~Sign () {
- if (initialised_) {
- EVP_MD_CTX_cleanup(&mdctx);
- }
+ if (fatal) {
+ unsigned long err = ERR_get_error();
+ return ThrowCryptoError(err);
}
- private:
-
- EVP_MD_CTX mdctx; /* coverity[member_decl] */
- const EVP_MD *md; /* coverity[member_decl] */
- bool initialised_;
-};
+ return scope.Close(r ? True(node_isolate) : False(node_isolate));
+}
-class Verify : public ObjectWrap {
- public:
- static void Initialize (v8::Handle<v8::Object> target) {
- HandleScope scope;
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+Handle<Value> Verify::VerifyFinal(const Arguments& args) {
+ HandleScope scope(node_isolate);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ Verify* verify = ObjectWrap::Unwrap<Verify>(args.This());
- NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit);
- NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate);
- NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal);
+ ASSERT_IS_BUFFER(args[0]);
+ char* kbuf = Buffer::Data(args[0]);
+ ssize_t klen = Buffer::Length(args[0]);
- ASSERT_IS_BUFFER(args[1]);
- unsigned char* hbuf = reinterpret_cast<unsigned char*>(Buffer::Data(args[1]));
- ssize_t hlen = Buffer::Length(args[1]);
- target->Set(String::NewSymbol("Verify"), t->GetFunction());
++ ASSERT_IS_STRING_OR_BUFFER(args[1]);
++ // BINARY works for both buffers and binary strings.
++ enum encoding encoding = BINARY;
++ if (args.Length() >= 3) {
++ encoding = ParseEncoding(args[2]->ToString(), BINARY);
+ }
- return scope.Close(verify->VerifyFinal(kbuf, klen, hbuf, hlen));
++ ssize_t hlen = StringBytes::Size(args[1], encoding);
+
- bool VerifyInit (const char* verifyType) {
- md = EVP_get_digestbyname(verifyType);
- if(!md) {
- fprintf(stderr, "node-crypto : Unknown message digest %s\n", verifyType);
- return false;
- }
- EVP_MD_CTX_init(&mdctx);
- EVP_VerifyInit_ex(&mdctx, md, NULL);
- initialised_ = true;
- return true;
++ // 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 VerifyUpdate(char* data, int len) {
- if (!initialised_) return 0;
- EVP_VerifyUpdate(&mdctx, data, len);
- return 1;
++ Local<Value> retval = Local<Value>::New(verify->VerifyFinal(kbuf, klen, hbuf, hlen));
++ if (args[1]->IsString()) {
++ delete[] hbuf;
+ }
++ return scope.Close(retval);
+}
- int VerifyFinal(char* key_pem, int key_pemLen, unsigned char* sig, int siglen) {
- if (!initialised_) return 0;
-
- EVP_PKEY* pkey = NULL;
- BIO *bp = NULL;
- X509 *x509 = NULL;
- int r = 0;
-
- bp = BIO_new(BIO_s_mem());
- if (bp == NULL) {
- ERR_print_errors_fp(stderr);
- return 0;
- }
- if(!BIO_write(bp, key_pem, key_pemLen)) {
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- // Check if this is a PKCS#8 or RSA public key before trying as X.509.
- // Split this out into a separate function once we have more than one
- // consumer of public keys.
- if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
- pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
- if (pkey == NULL) {
- ERR_print_errors_fp(stderr);
- return 0;
- }
- } else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
- RSA* rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
- if (rsa) {
- pkey = EVP_PKEY_new();
- if (pkey) EVP_PKEY_set1_RSA(pkey, rsa);
- RSA_free(rsa);
- }
- if (pkey == NULL) {
- ERR_print_errors_fp(stderr);
- return 0;
- }
- } else {
- // X.509 fallback
- x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL);
- if (x509 == NULL) {
- ERR_print_errors_fp(stderr);
- return 0;
- }
+void DiffieHellman::Initialize(v8::Handle<v8::Object> target) {
+ HandleScope scope(node_isolate);
- pkey = X509_get_pubkey(x509);
- if (pkey == NULL) {
- ERR_print_errors_fp(stderr);
- return 0;
- }
- }
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
- r = EVP_VerifyFinal(&mdctx, sig, siglen, pkey);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
- if(pkey != NULL)
- EVP_PKEY_free (pkey);
- if (x509 != NULL)
- X509_free(x509);
- if (bp != NULL)
- BIO_free(bp);
- EVP_MD_CTX_cleanup(&mdctx);
- initialised_ = false;
+ NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys);
+ NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret);
+ NODE_SET_PROTOTYPE_METHOD(t, "getPrime", GetPrime);
+ NODE_SET_PROTOTYPE_METHOD(t, "getGenerator", GetGenerator);
+ NODE_SET_PROTOTYPE_METHOD(t, "getPublicKey", GetPublicKey);
+ NODE_SET_PROTOTYPE_METHOD(t, "getPrivateKey", GetPrivateKey);
+ NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey);
+ NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey);
- return r;
- }
+ target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction());
+ Local<FunctionTemplate> t2 = FunctionTemplate::New(DiffieHellmanGroup);
+ t2->InstanceTemplate()->SetInternalFieldCount(1);
- protected:
+ NODE_SET_PROTOTYPE_METHOD(t2, "generateKeys", GenerateKeys);
+ NODE_SET_PROTOTYPE_METHOD(t2, "computeSecret", ComputeSecret);
+ NODE_SET_PROTOTYPE_METHOD(t2, "getPrime", GetPrime);
+ NODE_SET_PROTOTYPE_METHOD(t2, "getGenerator", GetGenerator);
+ NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey);
+ NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey);
- static Handle<Value> New (const Arguments& args) {
- HandleScope scope;
+ target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction());
+}
- Verify *verify = new Verify();
- verify->Wrap(args.This());
- return args.This();
- }
+bool DiffieHellman::Init(int primeLength) {
+ dh = DH_new();
+ DH_generate_parameters_ex(dh, primeLength, DH_GENERATOR_2, 0);
+ bool result = VerifyContext();
+ if (!result) return false;
+ initialised_ = true;
+ return true;
+}
- static Handle<Value> VerifyInit(const Arguments& args) {
- Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
+bool DiffieHellman::Init(unsigned char* p, int p_len) {
+ dh = DH_new();
+ dh->p = BN_bin2bn(p, p_len, 0);
+ dh->g = BN_new();
+ if (!BN_set_word(dh->g, 2)) return false;
+ bool result = VerifyContext();
+ if (!result) return false;
+ initialised_ = true;
+ return true;
+}
- HandleScope scope;
- if (args.Length() == 0 || !args[0]->IsString()) {
- return ThrowException(Exception::Error(String::New(
- "Must give verifytype string as argument")));
- }
+bool DiffieHellman::Init(unsigned char* p,
+ int p_len,
+ unsigned char* g,
+ int g_len) {
+ dh = DH_new();
+ dh->p = BN_bin2bn(p, p_len, 0);
+ dh->g = BN_bin2bn(g, g_len, 0);
+ initialised_ = true;
+ return true;
+}
- String::Utf8Value verifyType(args[0]);
- bool r = verify->VerifyInit(*verifyType);
+Handle<Value> DiffieHellman::DiffieHellmanGroup(const Arguments& args) {
+ HandleScope scope(node_isolate);
- if (!r) {
- return ThrowException(Exception::Error(String::New("VerifyInit error")));
- }
+ DiffieHellman* diffieHellman = new DiffieHellman();
- return args.This();
+ if (args.Length() != 1 || !args[0]->IsString()) {
+ return ThrowError("No group name given");
}
+ String::Utf8Value group_name(args[0]);
- static Handle<Value> VerifyUpdate(const Arguments& args) {
- HandleScope scope;
-
- Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
-
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
+ modp_group* it = modp_groups;
- // Only copy the data if we have to, because it's a string
- int r;
- if (args[0]->IsString()) {
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- size_t buflen = StringBytes::StorageSize(args[0], encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, args[0], encoding);
- r = verify->VerifyUpdate(buf, written);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = verify->VerifyUpdate(buf, buflen);
- }
-
- if (!r) {
- Local<Value> exception = Exception::TypeError(String::New("VerifyUpdate fail"));
- return ThrowException(exception);
- }
-
- return args.This();
+ while(it->name != NULL) {
+ if (!strcasecmp(*group_name, it->name))
+ break;
+ it++;
}
+ if (it->name != NULL) {
+ diffieHellman->Init(it->prime,
+ it->prime_size,
+ it->gen,
+ it->gen_size);
+ } else {
+ return ThrowError("Unknown group");
+ }
- static Handle<Value> VerifyFinal(const Arguments& args) {
- HandleScope scope;
-
- Verify *verify = ObjectWrap::Unwrap<Verify>(args.This());
+ diffieHellman->Wrap(args.This());
- ASSERT_IS_BUFFER(args[0]);
- ssize_t klen = Buffer::Length(args[0]);
+ return args.This();
+}
- if (klen < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
- char* kbuf = new char[klen];
- ssize_t kwritten = DecodeWrite(kbuf, klen, args[0], BINARY);
- assert(kwritten == klen);
+Handle<Value> DiffieHellman::New(const Arguments& args) {
+ HandleScope scope(node_isolate);
- ASSERT_IS_STRING_OR_BUFFER(args[1]);
+ DiffieHellman* diffieHellman = new DiffieHellman();
+ bool initialized = false;
- // BINARY works for both buffers and binary strings.
- enum encoding encoding = BINARY;
- if (args.Length() >= 3) {
- encoding = ParseEncoding(args[2]->ToString(), BINARY);
+ if (args.Length() > 0) {
+ if (args[0]->IsInt32()) {
+ initialized = diffieHellman->Init(args[0]->Int32Value());
+ } else {
+ initialized = diffieHellman->Init(
+ reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
+ Buffer::Length(args[0]));
}
+ }
- ssize_t hlen = StringBytes::Size(args[1], encoding);
+ if (!initialized) {
+ return ThrowError("Initialization failed");
+ }
- if (hlen < 0) {
- delete[] kbuf;
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+ diffieHellman->Wrap(args.This());
- unsigned char* hbuf = new unsigned char[hlen];
- ssize_t hwritten = StringBytes::Write(
- reinterpret_cast<char*>(hbuf), hlen, args[1], BINARY);
- assert(hwritten == hlen);
+ return args.This();
+}
- int r;
- r = verify->VerifyFinal(kbuf, klen, hbuf, hlen);
- delete[] kbuf;
- delete[] hbuf;
+Handle<Value> DiffieHellman::GenerateKeys(const Arguments& args) {
+ HandleScope scope(node_isolate);
- return Boolean::New(r && r != -1);
- }
+ DiffieHellman* diffieHellman =
+ ObjectWrap::Unwrap<DiffieHellman>(args.This());
- Verify () : ObjectWrap () {
- initialised_ = false;
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
}
- ~Verify () {
- if (initialised_) {
- EVP_MD_CTX_cleanup(&mdctx);
- }
+ if (!DH_generate_key(diffieHellman->dh)) {
+ return ThrowError("Key generation failed");
}
- private:
+ Local<Value> outString;
- EVP_MD_CTX mdctx; /* coverity[member_decl] */
- const EVP_MD *md; /* coverity[member_decl] */
- bool initialised_;
+ int dataSize = BN_num_bytes(diffieHellman->dh->pub_key);
+ char* data = new char[dataSize];
+ BN_bn2bin(diffieHellman->dh->pub_key,
+ reinterpret_cast<unsigned char*>(data));
-};
-
-class DiffieHellman : public ObjectWrap {
- public:
- static void Initialize(v8::Handle<v8::Object> target) {
- HandleScope scope;
-
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
-
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ outString = Encode(data, dataSize, BUFFER);
+ delete[] data;
- NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys);
- NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret);
- NODE_SET_PROTOTYPE_METHOD(t, "getPrime", GetPrime);
- NODE_SET_PROTOTYPE_METHOD(t, "getGenerator", GetGenerator);
- NODE_SET_PROTOTYPE_METHOD(t, "getPublicKey", GetPublicKey);
- NODE_SET_PROTOTYPE_METHOD(t, "getPrivateKey", GetPrivateKey);
- NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey);
- NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey);
+ return scope.Close(outString);
+}
- target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction());
- Local<FunctionTemplate> t2 = FunctionTemplate::New(DiffieHellmanGroup);
- t2->InstanceTemplate()->SetInternalFieldCount(1);
+Handle<Value> DiffieHellman::GetPrime(const Arguments& args) {
+ HandleScope scope(node_isolate);
- NODE_SET_PROTOTYPE_METHOD(t2, "generateKeys", GenerateKeys);
- NODE_SET_PROTOTYPE_METHOD(t2, "computeSecret", ComputeSecret);
- NODE_SET_PROTOTYPE_METHOD(t2, "getPrime", GetPrime);
- NODE_SET_PROTOTYPE_METHOD(t2, "getGenerator", GetGenerator);
- NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey);
- NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey);
+ DiffieHellman* diffieHellman =
+ ObjectWrap::Unwrap<DiffieHellman>(args.This());
- target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction());
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
}
- bool Init(int primeLength) {
- dh = DH_new();
- DH_generate_parameters_ex(dh, primeLength, DH_GENERATOR_2, 0);
- bool result = VerifyContext();
- if (!result) return false;
- initialised_ = true;
- return true;
- }
+ int dataSize = BN_num_bytes(diffieHellman->dh->p);
+ char* data = new char[dataSize];
+ BN_bn2bin(diffieHellman->dh->p, reinterpret_cast<unsigned char*>(data));
- bool Init(unsigned char* p, int p_len) {
- dh = DH_new();
- dh->p = BN_bin2bn(p, p_len, 0);
- dh->g = BN_new();
- if (!BN_set_word(dh->g, 2)) return false;
- bool result = VerifyContext();
- if (!result) return false;
- initialised_ = true;
- return true;
- }
+ Local<Value> outString;
- bool Init(unsigned char* p, int p_len, unsigned char* g, int g_len) {
- dh = DH_new();
- dh->p = BN_bin2bn(p, p_len, 0);
- dh->g = BN_bin2bn(g, g_len, 0);
- initialised_ = true;
- return true;
- }
+ outString = Encode(data, dataSize, BUFFER);
- protected:
- static Handle<Value> DiffieHellmanGroup(const Arguments& args) {
- HandleScope scope;
+ delete[] data;
- DiffieHellman* diffieHellman = new DiffieHellman();
+ return scope.Close(outString);
+}
- if (args.Length() != 1 || !args[0]->IsString()) {
- return ThrowException(Exception::Error(
- String::New("No group name given")));
- }
- String::Utf8Value group_name(args[0]);
+Handle<Value> DiffieHellman::GetGenerator(const Arguments& args) {
+ HandleScope scope(node_isolate);
- modp_group* it = modp_groups;
+ DiffieHellman* diffieHellman =
+ ObjectWrap::Unwrap<DiffieHellman>(args.This());
- while(it->name != NULL) {
- if (!strcasecmp(*group_name, it->name))
- break;
- it++;
- }
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
+ }
- if (it->name != NULL) {
- diffieHellman->Init(it->prime, it->prime_size,
- it->gen, it->gen_size);
- } else {
- return ThrowException(Exception::Error(
- String::New("Unknown group")));
- }
+ int dataSize = BN_num_bytes(diffieHellman->dh->g);
+ char* data = new char[dataSize];
+ BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data));
- diffieHellman->Wrap(args.This());
+ Local<Value> outString;
- return args.This();
- }
+ outString = Encode(data, dataSize, BUFFER);
- static Handle<Value> New(const Arguments& args) {
- HandleScope scope;
+ delete[] data;
- DiffieHellman* diffieHellman = new DiffieHellman();
- bool initialized = false;
+ return scope.Close(outString);
+}
- if (args.Length() > 0) {
- if (args[0]->IsInt32()) {
- initialized = diffieHellman->Init(args[0]->Int32Value());
- } else {
- initialized = diffieHellman->Init(
- reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
- Buffer::Length(args[0]));
- }
- }
- if (!initialized) {
- return ThrowException(Exception::Error(
- String::New("Initialization failed")));
- }
+Handle<Value> DiffieHellman::GetPublicKey(const Arguments& args) {
+ HandleScope scope(node_isolate);
- diffieHellman->Wrap(args.This());
+ DiffieHellman* diffieHellman =
+ ObjectWrap::Unwrap<DiffieHellman>(args.This());
- return args.This();
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
}
- static Handle<Value> GenerateKeys(const Arguments& args) {
- DiffieHellman* diffieHellman =
- ObjectWrap::Unwrap<DiffieHellman>(args.This());
+ if (diffieHellman->dh->pub_key == NULL) {
+ return ThrowError("No public key - did you forget to generate one?");
+ }
- HandleScope scope;
+ int dataSize = BN_num_bytes(diffieHellman->dh->pub_key);
+ char* data = new char[dataSize];
+ BN_bn2bin(diffieHellman->dh->pub_key,
+ reinterpret_cast<unsigned char*>(data));
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(
- String::New("Not initialized")));
- }
+ Local<Value> outString;
- if (!DH_generate_key(diffieHellman->dh)) {
- return ThrowException(Exception::Error(
- String::New("Key generation failed")));
- }
+ outString = Encode(data, dataSize, BUFFER);
- Local<Value> outString;
+ delete[] data;
- int dataSize = BN_num_bytes(diffieHellman->dh->pub_key);
- char* data = new char[dataSize];
- BN_bn2bin(diffieHellman->dh->pub_key,
- reinterpret_cast<unsigned char*>(data));
+ return scope.Close(outString);
+}
- outString = Encode(data, dataSize, BUFFER);
- delete[] data;
- return scope.Close(outString);
- }
+Handle<Value> DiffieHellman::GetPrivateKey(const Arguments& args) {
+ HandleScope scope(node_isolate);
- static Handle<Value> GetPrime(const Arguments& args) {
- DiffieHellman* diffieHellman =
+ DiffieHellman* diffieHellman =
ObjectWrap::Unwrap<DiffieHellman>(args.This());
- HandleScope scope;
-
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
- }
-
- int dataSize = BN_num_bytes(diffieHellman->dh->p);
- char* data = new char[dataSize];
- BN_bn2bin(diffieHellman->dh->p, reinterpret_cast<unsigned char*>(data));
-
- Local<Value> outString;
-
- outString = Encode(data, dataSize, BUFFER);
-
- delete[] data;
-
- return scope.Close(outString);
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
}
- static Handle<Value> GetGenerator(const Arguments& args) {
- DiffieHellman* diffieHellman =
- ObjectWrap::Unwrap<DiffieHellman>(args.This());
+ if (diffieHellman->dh->priv_key == NULL) {
+ return ThrowError("No private key - did you forget to generate one?");
+ }
- HandleScope scope;
+ int dataSize = BN_num_bytes(diffieHellman->dh->priv_key);
+ char* data = new char[dataSize];
+ BN_bn2bin(diffieHellman->dh->priv_key,
+ reinterpret_cast<unsigned char*>(data));
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
- }
+ Local<Value> outString;
- int dataSize = BN_num_bytes(diffieHellman->dh->g);
- char* data = new char[dataSize];
- BN_bn2bin(diffieHellman->dh->g, reinterpret_cast<unsigned char*>(data));
+ outString = Encode(data, dataSize, BUFFER);
- Local<Value> outString;
+ delete[] data;
- outString = Encode(data, dataSize, BUFFER);
+ return scope.Close(outString);
+}
- delete[] data;
- return scope.Close(outString);
- }
+Handle<Value> DiffieHellman::ComputeSecret(const Arguments& args) {
+ HandleScope scope(node_isolate);
- static Handle<Value> GetPublicKey(const Arguments& args) {
- DiffieHellman* diffieHellman =
+ DiffieHellman* diffieHellman =
ObjectWrap::Unwrap<DiffieHellman>(args.This());
- HandleScope scope;
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
+ }
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
- }
+ BIGNUM* key = NULL;
- if (diffieHellman->dh->pub_key == NULL) {
- return ThrowException(Exception::Error(
- String::New("No public key - did you forget to generate one?")));
- }
+ if (args.Length() == 0) {
+ return ThrowError("First argument must be other party's public key");
+ } else {
+ ASSERT_IS_BUFFER(args[0]);
+ key = BN_bin2bn(
+ reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
+ Buffer::Length(args[0]),
+ 0);
+ }
- int dataSize = BN_num_bytes(diffieHellman->dh->pub_key);
- char* data = new char[dataSize];
- BN_bn2bin(diffieHellman->dh->pub_key,
- reinterpret_cast<unsigned char*>(data));
+ int dataSize = DH_size(diffieHellman->dh);
+ char* data = new char[dataSize];
- Local<Value> outString;
+ int size = DH_compute_key(reinterpret_cast<unsigned char*>(data),
+ key,
+ diffieHellman->dh);
- outString = Encode(data, dataSize, BUFFER);
+ if (size == -1) {
+ int checkResult;
+ int checked;
+ checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult);
+ BN_free(key);
delete[] data;
- return scope.Close(outString);
- }
-
- static Handle<Value> GetPrivateKey(const Arguments& args) {
- DiffieHellman* diffieHellman =
- ObjectWrap::Unwrap<DiffieHellman>(args.This());
-
- HandleScope scope;
-
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
+ if (!checked) {
+ return ThrowError("Invalid key");
+ } else if (checkResult) {
+ if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) {
+ return ThrowError("Supplied key is too small");
+ } else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) {
+ return ThrowError("Supplied key is too large");
+ } else {
+ return ThrowError("Invalid key");
+ }
+ } else {
+ return ThrowError("Invalid key");
}
+ }
- if (diffieHellman->dh->priv_key == NULL) {
- return ThrowException(Exception::Error(
- String::New("No private key - did you forget to generate one?")));
- }
+ BN_free(key);
+ assert(size >= 0);
- int dataSize = BN_num_bytes(diffieHellman->dh->priv_key);
- char* data = new char[dataSize];
- BN_bn2bin(diffieHellman->dh->priv_key,
- reinterpret_cast<unsigned char*>(data));
+ // DH_size returns number of bytes in a prime number
+ // DH_compute_key returns number of bytes in a remainder of exponent, which
+ // may have less bytes than a prime number. Therefore add 0-padding to the
+ // allocated buffer.
+ if (size != dataSize) {
+ assert(dataSize > size);
+ memmove(data + dataSize - size, data, size);
+ memset(data, 0, dataSize - size);
+ }
- Local<Value> outString;
+ Local<Value> outString;
- outString = Encode(data, dataSize, BUFFER);
+ outString = Encode(data, dataSize, BUFFER);
- delete[] data;
+ delete[] data;
+ return scope.Close(outString);
+}
- return scope.Close(outString);
- }
- static Handle<Value> ComputeSecret(const Arguments& args) {
- HandleScope scope;
+Handle<Value> DiffieHellman::SetPublicKey(const Arguments& args) {
+ HandleScope scope(node_isolate);
- DiffieHellman* diffieHellman =
+ DiffieHellman* diffieHellman =
ObjectWrap::Unwrap<DiffieHellman>(args.This());
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
- }
-
- BIGNUM* key = 0;
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
+ }
- if (args.Length() == 0) {
- return ThrowException(Exception::Error(
- String::New("First argument must be other party's public key")));
- } else {
- ASSERT_IS_BUFFER(args[0]);
- key = BN_bin2bn(
+ if (args.Length() == 0) {
+ return ThrowError("First argument must be public key");
+ } else {
+ ASSERT_IS_BUFFER(args[0]);
+ diffieHellman->dh->pub_key = BN_bin2bn(
reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
Buffer::Length(args[0]), 0);
- }
-
- int dataSize = DH_size(diffieHellman->dh);
- char* data = new char[dataSize];
-
- int size = DH_compute_key(reinterpret_cast<unsigned char*>(data),
- key, diffieHellman->dh);
-
- if (size == -1) {
- int checkResult;
- int checked;
-
- checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult);
- BN_free(key);
- delete[] data;
-
- if (!checked) {
- return ThrowException(Exception::Error(String::New("Invalid key")));
- } else if (checkResult) {
- if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) {
- return ThrowException(Exception::Error(
- String::New("Supplied key is too small")));
- } else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) {
- return ThrowException(Exception::Error(
- String::New("Supplied key is too large")));
- } else {
- return ThrowException(Exception::Error(String::New("Invalid key")));
- }
- } else {
- return ThrowException(Exception::Error(String::New("Invalid key")));
- }
- }
-
- BN_free(key);
- assert(size >= 0);
-
- // DH_size returns number of bytes in a prime number
- // DH_compute_key returns number of bytes in a remainder of exponent, which
- // may have less bytes than a prime number. Therefore add 0-padding to the
- // allocated buffer.
- if (size != dataSize) {
- assert(dataSize > size);
- memmove(data + dataSize - size, data, size);
- memset(data, 0, dataSize - size);
- }
-
- Local<Value> outString;
-
- outString = Encode(data, dataSize, BUFFER);
-
- delete[] data;
- return scope.Close(outString);
}
- static Handle<Value> SetPublicKey(const Arguments& args) {
- HandleScope scope;
-
- DiffieHellman* diffieHellman =
- ObjectWrap::Unwrap<DiffieHellman>(args.This());
-
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(String::New("Not initialized")));
- }
-
- if (args.Length() == 0) {
- return ThrowException(Exception::Error(
- String::New("First argument must be public key")));
- } else {
- ASSERT_IS_BUFFER(args[0]);
- diffieHellman->dh->pub_key =
- BN_bin2bn(
- reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
- Buffer::Length(args[0]), 0);
- }
+ return args.This();
+}
- return args.This();
- }
- static Handle<Value> SetPrivateKey(const Arguments& args) {
- HandleScope scope;
+Handle<Value> DiffieHellman::SetPrivateKey(const Arguments& args) {
+ HandleScope scope(node_isolate);
- DiffieHellman* diffieHellman =
+ DiffieHellman* diffieHellman =
ObjectWrap::Unwrap<DiffieHellman>(args.This());
- if (!diffieHellman->initialised_) {
- return ThrowException(Exception::Error(
- String::New("Not initialized")));
- }
-
- if (args.Length() == 0) {
- return ThrowException(Exception::Error(
- String::New("First argument must be private key")));
- } else {
- ASSERT_IS_BUFFER(args[0]);
- diffieHellman->dh->priv_key =
- BN_bin2bn(
- reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
- Buffer::Length(args[0]), 0);
- }
-
- return args.This();
+ if (!diffieHellman->initialised_) {
+ return ThrowError("Not initialized");
}
- DiffieHellman() : ObjectWrap() {
- initialised_ = false;
- dh = NULL;
+ if (args.Length() == 0) {
+ return ThrowError("First argument must be private key");
+ } else {
+ ASSERT_IS_BUFFER(args[0]);
+ diffieHellman->dh->priv_key = BN_bin2bn(
+ reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
+ Buffer::Length(args[0]),
+ 0);
}
- ~DiffieHellman() {
- if (dh != NULL) {
- DH_free(dh);
- }
- }
+ return args.This();
+}
- private:
- bool VerifyContext() {
- int codes;
- if (!DH_check(dh, &codes)) return false;
- if (codes & DH_CHECK_P_NOT_SAFE_PRIME) return false;
- if (codes & DH_CHECK_P_NOT_PRIME) return false;
- if (codes & DH_UNABLE_TO_CHECK_GENERATOR) return false;
- if (codes & DH_NOT_SUITABLE_GENERATOR) return false;
- return true;
- }
- bool initialised_;
- DH* dh;
-};
+bool DiffieHellman::VerifyContext() {
+ int codes;
+ if (!DH_check(dh, &codes)) return false;
+ if (codes & DH_CHECK_P_NOT_SAFE_PRIME) return false;
+ if (codes & DH_CHECK_P_NOT_PRIME) return false;
+ if (codes & DH_UNABLE_TO_CHECK_GENERATOR) return false;
+ if (codes & DH_NOT_SUITABLE_GENERATOR) return false;
+ return true;
+}
struct pbkdf2_req {
--- /dev/null
- len = str->WriteAscii(buf, 0, buflen, flags);
+ // Copyright Joyent, Inc. and other Node contributors.
+ //
+ // Permission is hereby granted, free of charge, to any person obtaining a
+ // copy of this software and associated documentation files (the
+ // "Software"), to deal in the Software without restriction, including
+ // without limitation the rights to use, copy, modify, merge, publish,
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
+ // persons to whom the Software is furnished to do so, subject to the
+ // following conditions:
+ //
+ // The above copyright notice and this permission notice shall be included
+ // in all copies or substantial portions of the Software.
+ //
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ #include "string_bytes.h"
+
+ #include <assert.h>
+ #include <string.h> // memcpy
+ #include <limits.h>
+
+ #include "node.h"
+ #include "node_buffer.h"
+ #include "v8.h"
+
+ namespace node {
+
+ using v8::Local;
+ using v8::Handle;
+ using v8::HandleScope;
+ using v8::Object;
+ using v8::String;
+ using v8::Value;
+
+
+ //// Base 64 ////
+
+ #define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4)
+
+
+ // Doesn't check for padding at the end. Can be 1-2 bytes over.
+ static inline size_t base64_decoded_size_fast(size_t size) {
+ size_t remainder = size % 4;
+
+ size = (size / 4) * 3;
+ if (remainder) {
+ if (size == 0 && remainder == 1) {
+ // special case: 1-byte input cannot be decoded
+ size = 0;
+ } else {
+ // non-padded input, add 1 or 2 extra bytes
+ size += 1 + (remainder == 3);
+ }
+ }
+
+ return size;
+ }
+
+ static inline size_t base64_decoded_size(const char* src, size_t size) {
+ size = base64_decoded_size_fast(size);
+
+ const char* end = src + size;
+ // check for trailing padding (1 or 2 bytes)
+ if (size > 0) {
+ if (end[-1] == '=') size--;
+ if (size > 0 && end[-2] == '=') size--;
+ }
+
+ return size;
+ }
+
+
+ // supports regular and URL-safe base64
+ static const int unbase64_table[] =
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ #define unbase64(x) unbase64_table[(uint8_t)(x)]
+
+
+ static inline size_t base64_decode(char *buf,
+ size_t len,
+ const char *src,
+ const size_t srcLen) {
+ char a, b, c, d;
+ char* dst = buf;
+ char* dstEnd = buf + len;
+ const char* srcEnd = src + srcLen;
+
+ while (src < srcEnd && dst < dstEnd) {
+ int remaining = srcEnd - src;
+
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
+ if (remaining == 0 || *src == '=') break;
+ a = unbase64(*src++);
+
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
+ if (remaining <= 1 || *src == '=') break;
+ b = unbase64(*src++);
+
+ *dst++ = (a << 2) | ((b & 0x30) >> 4);
+ if (dst == dstEnd) break;
+
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
+ if (remaining <= 2 || *src == '=') break;
+ c = unbase64(*src++);
+
+ *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
+ if (dst == dstEnd) break;
+
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
+ if (remaining <= 3 || *src == '=') break;
+ d = unbase64(*src++);
+
+ *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
+ }
+
+ return dst - buf;
+ }
+
+
+ //// HEX ////
+
+ static inline unsigned hex2bin(char c) {
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
+ if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
+ return static_cast<unsigned>(-1);
+ }
+
+
+ static inline size_t hex_decode(char *buf,
+ size_t len,
+ const char *src,
+ const size_t srcLen) {
+ size_t i;
+ for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
+ unsigned a = hex2bin(src[i * 2 + 0]);
+ unsigned b = hex2bin(src[i * 2 + 1]);
+ if (!~a || !~b) return i;
+ buf[i] = a * 16 + b;
+ }
+
+ return i;
+ }
+
+
+ size_t StringBytes::Write(char* buf,
+ size_t buflen,
+ Handle<Value> val,
+ enum encoding encoding,
+ int* chars_written) {
+
+ HandleScope scope;
+ size_t len = 0;
+ bool is_buffer = Buffer::HasInstance(val);
+
+ // sometimes we use 'binary' when we mean 'buffer'
+ if (is_buffer && (encoding == BINARY || encoding == BUFFER)) {
+ // fast path, copy buffer data
+ Local<Object> valObj = Local<Object>::New(val.As<Object>());
+ const char* data = Buffer::Data(valObj);
+ size_t size = Buffer::Length(valObj);
+ size_t len = size < buflen ? size : buflen;
+ memcpy(buf, data, len);
+ return len;
+ }
+
+ Local<String> str = val->ToString();
+
+ int flags = String::NO_NULL_TERMINATION |
+ String::HINT_MANY_WRITES_EXPECTED;
+
+ switch (encoding) {
+ case ASCII:
- // TODO(isaacs): MayContainNonAscii is deprecated in V8 3.19, remove
- if (!str->MayContainNonAscii())
- data_size = str->Length();
- else
- data_size = 3 * str->Length();
++ len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
++ 0,
++ buflen,
++ flags);
+ if (chars_written != NULL) {
+ *chars_written = len;
+ }
+ break;
+
+ case UTF8:
+ len = str->WriteUtf8(buf, buflen, chars_written, flags);
+ break;
+
+ case UCS2:
+ len = str->Write(reinterpret_cast<uint16_t*>(buf), 0, buflen, flags);
+ if (chars_written != NULL) {
+ *chars_written = len;
+ }
+ len = len * sizeof(uint16_t);
+ break;
+
+ case BASE64: {
+ String::AsciiValue value(str);
+ len = base64_decode(buf, buflen, *value, value.length());
+ if (chars_written != NULL) {
+ *chars_written = len;
+ }
+ break;
+ }
+
+ case BINARY:
+ case BUFFER: {
+ // TODO(isaacs): THIS IS AWFUL!!!
+ uint16_t* twobytebuf = new uint16_t[buflen];
+
+ len = str->Write(twobytebuf, 0, buflen, flags);
+
+ for (size_t i = 0; i < buflen && i < len; i++) {
+ unsigned char *b = reinterpret_cast<unsigned char*>(&twobytebuf[i]);
+ buf[i] = b[0];
+ }
+
+ if (chars_written != NULL) {
+ *chars_written = len;
+ }
+
+ delete[] twobytebuf;
+ break;
+ }
+
+ case HEX: {
+ String::AsciiValue value(str);
+ len = hex_decode(buf, buflen, *value, value.length());
+ if (chars_written != NULL) {
+ *chars_written = len * 2;
+ }
+ break;
+ }
+
+ default:
+ assert(0 && "unknown encoding");
+ break;
+ }
+
+ return len;
+ }
+
+
+ // Quick and dirty size calculation
+ // Will always be at least big enough, but may have some extra
+ // UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
+ size_t StringBytes::StorageSize(Handle<Value> val, enum encoding encoding) {
+ HandleScope scope;
+ size_t data_size = 0;
+ bool is_buffer = Buffer::HasInstance(val);
+
+ if (is_buffer && (encoding == BUFFER || encoding == BINARY)) {
+ return Buffer::Length(val);
+ }
+
+ Local<String> str = val->ToString();
+
+ switch (encoding) {
+ case BINARY:
+ case BUFFER:
+ case ASCII:
+ data_size = str->Length();
+ break;
+
+ case UTF8:
+ // A single UCS2 codepoint never takes up more than 3 utf8 bytes.
+ // It is an exercise for the caller to decide when a string is
+ // long enough to justify calling Size() instead of StorageSize()
- // TODO(isaacs): MayContainNonAscii is deprecated in V8 3.19, remove
- if (!str->MayContainNonAscii())
- data_size = str->Length();
- else
- data_size = str->Utf8Length();
++ data_size = 3 * str->Length();
+ break;
+
+ case UCS2:
+ data_size = str->Length() * sizeof(uint16_t);
+ break;
+
+ case BASE64:
+ data_size = base64_decoded_size_fast(str->Length());
+ break;
+
+ case HEX:
+ assert(str->Length() % 2 == 0 && "invalid hex string length");
+ data_size = str->Length() / 2;
+ break;
+
+ default:
+ assert(0 && "unknown encoding");
+ break;
+ }
+
+ return data_size;
+ }
+
+
+ size_t StringBytes::Size(Handle<Value> val, enum encoding encoding) {
+ HandleScope scope;
+ size_t data_size = 0;
+ bool is_buffer = Buffer::HasInstance(val);
+
+ if (is_buffer && (encoding == BUFFER || encoding == BINARY)) {
+ return Buffer::Length(val);
+ }
+
+ Local<String> str = val->ToString();
+
+ switch (encoding) {
+ case BINARY:
+ case BUFFER:
+ case ASCII:
+ data_size = str->Length();
+ break;
+
+ case UTF8:
++ data_size = str->Utf8Length();
+ break;
+
+ case UCS2:
+ data_size = str->Length() * sizeof(uint16_t);
+ break;
+
+ case BASE64: {
+ String::AsciiValue value(str);
+ data_size = base64_decoded_size(*value, value.length());
+ break;
+ }
+
+ case HEX:
+ data_size = str->Length() / 2;
+ break;
+
+ default:
+ assert(0 && "unknown encoding");
+ break;
+ }
+
+ return data_size;
+ }
+
+
+
+
+ static bool contains_non_ascii_slow(const char* buf, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ if (buf[i] & 0x80) return true;
+ }
+ return false;
+ }
+
+
+ static bool contains_non_ascii(const char* src, size_t len) {
+ if (len < 16) {
+ return contains_non_ascii_slow(src, len);
+ }
+
+ const unsigned bytes_per_word = sizeof(void*);
+ const unsigned align_mask = bytes_per_word - 1;
+ const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
+
+ if (unaligned > 0) {
+ const unsigned n = bytes_per_word - unaligned;
+ if (contains_non_ascii_slow(src, n)) return true;
+ src += n;
+ len -= n;
+ }
+
+
+ #if BITS_PER_LONG == 64
+ const uintptr_t mask = 0x8080808080808080ll;
+ #else
+ const uintptr_t mask = 0x80808080l;
+ #endif
+
+ const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
+
+ for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
+ if (srcw[i] & mask) return true;
+ }
+
+ const unsigned remainder = len & align_mask;
+ if (remainder > 0) {
+ const size_t offset = len - remainder;
+ if (contains_non_ascii_slow(src + offset, remainder)) return true;
+ }
+
+ return false;
+ }
+
+
+ static void force_ascii_slow(const char* src, char* dst, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ dst[i] = src[i] & 0x7f;
+ }
+ }
+
+
+ static void force_ascii(const char* src, char* dst, size_t len) {
+ if (len < 16) {
+ force_ascii_slow(src, dst, len);
+ return;
+ }
+
+ const unsigned bytes_per_word = sizeof(void*);
+ const unsigned align_mask = bytes_per_word - 1;
+ const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
+ const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
+
+ if (src_unalign > 0) {
+ if (src_unalign == dst_unalign) {
+ const unsigned unalign = bytes_per_word - src_unalign;
+ force_ascii_slow(src, dst, unalign);
+ src += unalign;
+ dst += unalign;
+ len -= src_unalign;
+ } else {
+ force_ascii_slow(src, dst, len);
+ return;
+ }
+ }
+
+ #if BITS_PER_LONG == 64
+ const uintptr_t mask = ~0x8080808080808080ll;
+ #else
+ const uintptr_t mask = ~0x80808080l;
+ #endif
+
+ const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
+ uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
+
+ for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
+ dstw[i] = srcw[i] & mask;
+ }
+
+ const unsigned remainder = len & align_mask;
+ if (remainder > 0) {
+ const size_t offset = len - remainder;
+ force_ascii_slow(src + offset, dst + offset, remainder);
+ }
+ }
+
+
+ static size_t base64_encode(const char* src,
+ size_t slen,
+ char* dst,
+ size_t dlen) {
+ // We know how much we'll write, just make sure that there's space.
+ assert(dlen >= base64_encoded_size(slen) &&
+ "not enough space provided for base64 encode");
+
+ dlen = base64_encoded_size(slen);
+
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned i;
+ unsigned k;
+ unsigned n;
+
+ static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+ i = 0;
+ k = 0;
+ n = slen / 3 * 3;
+
+ while (i < n) {
+ a = src[i + 0] & 0xff;
+ b = src[i + 1] & 0xff;
+ c = src[i + 2] & 0xff;
+
+ dst[k + 0] = table[a >> 2];
+ dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
+ dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
+ dst[k + 3] = table[c & 0x3f];
+
+ i += 3;
+ k += 4;
+ }
+
+ if (n != slen) {
+ switch (slen - n) {
+ case 1:
+ a = src[i + 0] & 0xff;
+ dst[k + 0] = table[a >> 2];
+ dst[k + 1] = table[(a & 3) << 4];
+ dst[k + 2] = '=';
+ dst[k + 3] = '=';
+ break;
+
+ case 2:
+ a = src[i + 0] & 0xff;
+ b = src[i + 1] & 0xff;
+ dst[k + 0] = table[a >> 2];
+ dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
+ dst[k + 2] = table[(b & 0x0f) << 2];
+ dst[k + 3] = '=';
+ break;
+ }
+ }
+
+ return dlen;
+ }
+
+
+ static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
+ // We know how much we'll write, just make sure that there's space.
+ assert(dlen >= slen * 2 &&
+ "not enough space provided for hex encode");
+
+ dlen = slen * 2;
+ for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
+ static const char hex[] = "0123456789abcdef";
+ uint8_t val = static_cast<uint8_t>(src[i]);
+ dst[k + 0] = hex[val >> 4];
+ dst[k + 1] = hex[val & 15];
+ }
+
+ return dlen;
+ }
+
+
+
+ Local<Value> StringBytes::Encode(const char* buf,
+ size_t buflen,
+ enum encoding encoding) {
+ HandleScope scope;
+
+ assert(buflen <= Buffer::kMaxLength);
+ if (!buflen && encoding != BUFFER)
+ return scope.Close(String::Empty());
+
+ Local<String> val;
+ switch (encoding) {
+ case BUFFER:
+ return scope.Close(
+ Buffer::New(static_cast<const char*>(buf), buflen)->handle_);
+
+ case ASCII:
+ if (contains_non_ascii(buf, buflen)) {
+ char* out = new char[buflen];
+ force_ascii(buf, out, buflen);
+ val = String::New(out, buflen);
+ delete[] out;
+ } else {
+ val = String::New(buf, buflen);
+ }
+ break;
+
+ case UTF8:
+ val = String::New(buf, buflen);
+ break;
+
+ case BINARY: {
+ // TODO(isaacs) use ExternalTwoByteString?
+ const unsigned char *cbuf = reinterpret_cast<const unsigned char*>(buf);
+ uint16_t * twobytebuf = new uint16_t[buflen];
+ for (size_t i = 0; i < buflen; i++) {
+ // XXX is the following line platform independent?
+ twobytebuf[i] = cbuf[i];
+ }
+ val = String::New(twobytebuf, buflen);
+ delete[] twobytebuf;
+ break;
+ }
+
+ case BASE64: {
+ size_t dlen = base64_encoded_size(buflen);
+ char* dst = new char[dlen];
+
+ size_t written = base64_encode(buf, buflen, dst, dlen);
+ assert(written == dlen);
+
+ val = String::New(dst, dlen);
+ delete[] dst;
+ break;
+ }
+
+ case UCS2: {
+ const uint16_t* data = reinterpret_cast<const uint16_t*>(buf);
+ val = String::New(data, buflen / 2);
+ break;
+ }
+
+ case HEX: {
+ size_t dlen = buflen * 2;
+ char* dst = new char[dlen];
+ size_t written = hex_encode(buf, buflen, dst, dlen);
+ assert(written == dlen);
+
+ val = String::New(dst, dlen);
+ delete[] dst;
+ break;
+ }
+
+ default:
+ assert(0 && "unknown encoding");
+ break;
+ }
+
+ return scope.Close(val);
+ }
+
+ } // namespace node