diff options
author | Evan Lucas <evanlucas@me.com> | 2016-12-09 17:13:14 -0600 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2018-02-12 19:28:00 -0500 |
commit | 6f62f83468b873b0cb5ce4d46ffcf4d3836681b7 (patch) | |
tree | f7d0f20d9fe0d0334da49d96dfe2635e3f217161 /src | |
parent | 7af1ad0ec15546761233c2e90008316551db2bbd (diff) | |
download | node-new-6f62f83468b873b0cb5ce4d46ffcf4d3836681b7.tar.gz |
crypto: add randomFill and randomFillSync
crypto.randomFill and crypto.randomFillSync are similar to
crypto.randomBytes, but allow passing in a buffer as the first
argument. This allows us to reuse buffers to prevent having to
create a new one on every call.
PR-URL: https://github.com/nodejs/node/pull/10209
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'src')
-rw-r--r-- | src/node_crypto.cc | 111 |
1 files changed, 97 insertions, 14 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc index af892d4367..9dcbcdc658 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5595,11 +5595,18 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) { // Only instantiate within a valid HandleScope. class RandomBytesRequest : public AsyncWrap { public: - RandomBytesRequest(Environment* env, Local<Object> object, size_t size) + enum FreeMode { FREE_DATA, DONT_FREE_DATA }; + + RandomBytesRequest(Environment* env, + Local<Object> object, + size_t size, + char* data, + FreeMode free_mode) : AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO), error_(0), size_(size), - data_(node::Malloc(size)) { + data_(data), + free_mode_(free_mode) { Wrap(object, this); } @@ -5620,9 +5627,15 @@ class RandomBytesRequest : public AsyncWrap { return data_; } + inline void set_data(char* data) { + data_ = data; + } + inline void release() { - free(data_); size_ = 0; + if (free_mode_ == FREE_DATA) { + free(data_); + } } inline void return_memory(char** d, size_t* len) { @@ -5648,6 +5661,7 @@ class RandomBytesRequest : public AsyncWrap { unsigned long error_; // NOLINT(runtime/int) size_t size_; char* data_; + const FreeMode free_mode_; }; @@ -5686,7 +5700,18 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) { size_t size; req->return_memory(&data, &size); argv[0] = Null(req->env()->isolate()); - argv[1] = Buffer::New(req->env(), data, size).ToLocalChecked(); + Local<Value> buffer = + req->object()->Get(req->env()->context(), + req->env()->buffer_string()).ToLocalChecked(); + + if (buffer->IsUint8Array()) { + CHECK_LE(req->size(), Buffer::Length(buffer)); + char* buf = Buffer::Data(buffer); + memcpy(buf, data, req->size()); + argv[1] = buffer; + } else { + argv[1] = Buffer::New(req->env(), data, size).ToLocalChecked(); + } } } @@ -5705,11 +5730,22 @@ void RandomBytesAfter(uv_work_t* work_req, int status) { } +void RandomBytesProcessSync(Environment* env, + RandomBytesRequest* req, + Local<Value> argv[2]) { + env->PrintSyncTrace(); + RandomBytesWork(req->work_req()); + RandomBytesCheck(req, argv); + delete req; + + if (!argv[0]->IsNull()) + env->isolate()->ThrowException(argv[0]); +} + + void RandomBytes(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); - // maybe allow a buffer to write to? cuts down on object creation - // when generating random data in a loop if (!args[0]->IsUint32()) { return env->ThrowTypeError("size must be a number >= 0"); } @@ -5719,7 +5755,13 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) { return env->ThrowRangeError("size is not a valid Smi"); Local<Object> obj = env->NewInternalFieldObject(); - RandomBytesRequest* req = new RandomBytesRequest(env, obj, size); + char* data = node::Malloc(size); + RandomBytesRequest* req = + new RandomBytesRequest(env, + obj, + size, + data, + RandomBytesRequest::FREE_DATA); if (args[1]->IsFunction()) { obj->Set(FIXED_ONE_BYTE_STRING(args.GetIsolate(), "ondone"), args[1]); @@ -5732,15 +5774,55 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) { RandomBytesAfter); args.GetReturnValue().Set(obj); } else { - env->PrintSyncTrace(); Local<Value> argv[2]; - RandomBytesWork(req->work_req()); - RandomBytesCheck(req, argv); - delete req; + RandomBytesProcessSync(env, req, argv); + if (argv[0]->IsNull()) + args.GetReturnValue().Set(argv[1]); + } +} - if (!argv[0]->IsNull()) - env->isolate()->ThrowException(argv[0]); - else + +void RandomBytesBuffer(const FunctionCallbackInfo<Value>& args) { + Environment* env = Environment::GetCurrent(args); + + CHECK(args[0]->IsUint8Array()); + CHECK(args[1]->IsUint32()); + CHECK(args[2]->IsUint32()); + + int64_t offset = args[1]->IntegerValue(); + int64_t size = args[2]->IntegerValue(); + + Local<Object> obj = env->NewInternalFieldObject(); + obj->Set(env->context(), env->buffer_string(), args[0]).FromJust(); + char* data = Buffer::Data(args[0]); + data += offset; + + RandomBytesRequest* req = + new RandomBytesRequest(env, + obj, + size, + data, + RandomBytesRequest::DONT_FREE_DATA); + if (args[3]->IsFunction()) { + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(args.GetIsolate(), "ondone"), + args[3]).FromJust(); + + if (env->in_domain()) { + obj->Set(env->context(), + env->domain_string(), + env->domain_array()->Get(0)).FromJust(); + } + + uv_queue_work(env->event_loop(), + req->work_req(), + RandomBytesWork, + RandomBytesAfter); + args.GetReturnValue().Set(obj); + } else { + Local<Value> argv[2]; + RandomBytesProcessSync(env, req, argv); + if (argv[0]->IsNull()) args.GetReturnValue().Set(argv[1]); } } @@ -6168,6 +6250,7 @@ void InitCrypto(Local<Object> target, env->SetMethod(target, "setFipsCrypto", SetFipsCrypto); env->SetMethod(target, "PBKDF2", PBKDF2); env->SetMethod(target, "randomBytes", RandomBytes); + env->SetMethod(target, "randomFill", RandomBytesBuffer); env->SetMethod(target, "timingSafeEqual", TimingSafeEqual); env->SetMethod(target, "getSSLCiphers", GetSSLCiphers); env->SetMethod(target, "getCiphers", GetCiphers); |