summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvan Lucas <evanlucas@me.com>2016-12-09 17:13:14 -0600
committerMyles Borins <mylesborins@google.com>2018-02-12 19:28:00 -0500
commit6f62f83468b873b0cb5ce4d46ffcf4d3836681b7 (patch)
treef7d0f20d9fe0d0334da49d96dfe2635e3f217161 /src
parent7af1ad0ec15546761233c2e90008316551db2bbd (diff)
downloadnode-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.cc111
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);