◐ Shell
clean mode source ↗

crypto: refactor randomBytes() · nodejs/node@2d9c3cc

@@ -82,7 +82,6 @@ using v8::NewStringType;

8282

using v8::Nothing;

8383

using v8::Null;

8484

using v8::Object;

85-

using v8::ObjectTemplate;

8685

using v8::PropertyAttribute;

8786

using v8::ReadOnly;

8887

using v8::Signature;

@@ -4589,208 +4588,50 @@ inline void CopyBuffer(Local<Value> buf, std::vector<char>* vec) {

45894588

}

45904589459145904592-

// Only instantiate within a valid HandleScope.

4593-

class RandomBytesRequest : public AsyncWrap, public ThreadPoolWork {

4594-

public:

4595-

enum FreeMode { FREE_DATA, DONT_FREE_DATA };

4596-4597-

RandomBytesRequest(Environment* env,

4598-

Local<Object> object,

4599-

size_t size,

4600-

char* data,

4601-

FreeMode free_mode)

4602-

: AsyncWrap(env, object, AsyncWrap::PROVIDER_RANDOMBYTESREQUEST),

4603-

ThreadPoolWork(env),

4604-

error_(0),

4605-

size_(size),

4606-

data_(data),

4607-

free_mode_(free_mode) {

4608-

}

4609-4610-

inline size_t size() const {

4611-

return size_;

4612-

}

4613-4614-

inline char* data() const {

4615-

return data_;

4616-

}

4617-4618-

inline void set_data(char* data) {

4619-

data_ = data;

4620-

}

4591+

struct RandomBytesJob : public CryptoJob {

4592+

unsigned char* data;

4593+

size_t size;

4594+

CryptoErrorVector errors;

4595+

Maybe<int> rc;

462145964622-

inline void release() {

4623-

size_ = 0;

4624-

if (free_mode_ == FREE_DATA) {

4625-

free(data_);

4626-

data_ = nullptr;

4627-

}

4628-

}

4597+

inline explicit RandomBytesJob(Environment* env)

4598+

: CryptoJob(env), rc(Nothing<int>()) {}

462945994630-

inline void return_memory(char** d, size_t* len) {

4631-

*d = data_;

4632-

data_ = nullptr;

4633-

*len = size_;

4634-

size_ = 0;

4600+

inline void DoThreadPoolWork() override {

4601+

CheckEntropy(); // Ensure that OpenSSL's PRNG is properly seeded.

4602+

rc = Just(RAND_bytes(data, size));

4603+

if (0 == rc.FromJust()) errors.Capture();

46354604

}

463646054637-

inline unsigned long error() const { // NOLINT(runtime/int)

4638-

return error_;

4606+

inline void AfterThreadPoolWork() override {

4607+

Local<Value> arg = ToResult();

4608+

async_wrap->MakeCallback(env->ondone_string(), 1, &arg);

46394609

}

464046104641-

inline void set_error(unsigned long err) { // NOLINT(runtime/int)

4642-

error_ = err;

4611+

inline Local<Value> ToResult() const {

4612+

if (errors.empty()) return Undefined(env->isolate());

4613+

return errors.ToException(env);

46434614

}

4644-4645-

size_t self_size() const override { return sizeof(*this); }

4646-4647-

void DoThreadPoolWork() override;

4648-

void AfterThreadPoolWork(int status) override;

4649-4650-

private:

4651-

unsigned long error_; // NOLINT(runtime/int)

4652-

size_t size_;

4653-

char* data_;

4654-

const FreeMode free_mode_;

46554615

};

46564616465746174658-

void RandomBytesRequest::DoThreadPoolWork() {

4659-

// Ensure that OpenSSL's PRNG is properly seeded.

4660-

CheckEntropy();

4661-4662-

const int r = RAND_bytes(reinterpret_cast<unsigned char*>(data_), size_);

4663-4664-

// RAND_bytes() returns 0 on error.

4665-

if (r == 0) {

4666-

set_error(ERR_get_error()); // NOLINT(runtime/int)

4667-

} else if (r == -1) {

4668-

set_error(static_cast<unsigned long>(-1)); // NOLINT(runtime/int)

4669-

}

4670-

}

4671-4672-4673-

// don't call this function without a valid HandleScope

4674-

void RandomBytesCheck(RandomBytesRequest* req, Local<Value> (*argv)[2]) {

4675-

if (req->error()) {

4676-

char errmsg[256] = "Operation not supported";

4677-4678-

if (req->error() != static_cast<unsigned long>(-1)) // NOLINT(runtime/int)

4679-

ERR_error_string_n(req->error(), errmsg, sizeof errmsg);

4680-4681-

(*argv)[0] = Exception::Error(OneByteString(req->env()->isolate(), errmsg));

4682-

(*argv)[1] = Null(req->env()->isolate());

4683-

req->release();

4684-

} else {

4685-

char* data = nullptr;

4686-

size_t size;

4687-

req->return_memory(&data, &size);

4688-

(*argv)[0] = Null(req->env()->isolate());

4689-

Local<Value> buffer =

4690-

req->object()->Get(req->env()->context(),

4691-

req->env()->buffer_string()).ToLocalChecked();

4692-4693-

if (buffer->IsArrayBufferView()) {

4694-

CHECK_LE(req->size(), Buffer::Length(buffer));

4695-

char* buf = Buffer::Data(buffer);

4696-

memcpy(buf, data, req->size());

4697-

(*argv)[1] = buffer;

4698-

} else {

4699-

(*argv)[1] = Buffer::New(req->env(), data, size)

4700-

.ToLocalChecked();

4701-

}

4702-

}

4703-

}

4704-4705-4706-

void RandomBytesRequest::AfterThreadPoolWork(int status) {

4707-

std::unique_ptr<RandomBytesRequest> req(this);

4708-

if (status == UV_ECANCELED)

4709-

return;

4710-

CHECK_EQ(status, 0);

4711-

HandleScope handle_scope(env()->isolate());

4712-

Context::Scope context_scope(env()->context());

4713-

Local<Value> argv[2];

4714-

RandomBytesCheck(this, &argv);

4715-

MakeCallback(env()->ondone_string(), arraysize(argv), argv);

4716-

}

4717-4718-4719-

void RandomBytesProcessSync(Environment* env,

4720-

std::unique_ptr<RandomBytesRequest> req,

4721-

Local<Value> (*argv)[2]) {

4722-

env->PrintSyncTrace();

4723-

req->DoThreadPoolWork();

4724-

RandomBytesCheck(req.get(), argv);

4725-4726-

if (!(*argv)[0]->IsNull())

4727-

env->isolate()->ThrowException((*argv)[0]);

4728-

}

4729-4730-47314618

void RandomBytes(const FunctionCallbackInfo<Value>& args) {

4619+

CHECK(args[0]->IsArrayBufferView()); // buffer; wrap object retains ref.

4620+

CHECK(args[1]->IsUint32()); // offset

4621+

CHECK(args[2]->IsUint32()); // size

4622+

CHECK(args[3]->IsObject() || args[3]->IsUndefined()); // wrap object

4623+

const uint32_t offset = args[1].As<Uint32>()->Value();

4624+

const uint32_t size = args[2].As<Uint32>()->Value();

4625+

CHECK_GE(offset + size, offset); // Overflow check.

4626+

CHECK_LE(offset + size, Buffer::Length(args[0])); // Bounds check.

47324627

Environment* env = Environment::GetCurrent(args);

4733-4734-

const int64_t size = args[0]->IntegerValue();

4735-

CHECK(size <= Buffer::kMaxLength);

4736-4737-

Local<Object> obj = env->randombytes_constructor_template()->

4738-

NewInstance(env->context()).ToLocalChecked();

4739-

char* data = node::Malloc(size);

4740-

std::unique_ptr<RandomBytesRequest> req(

4741-

new RandomBytesRequest(env,

4742-

obj,

4743-

size,

4744-

data,

4745-

RandomBytesRequest::FREE_DATA));

4746-4747-

if (args[1]->IsFunction()) {

4748-

obj->Set(env->context(), env->ondone_string(), args[1]).FromJust();

4749-4750-

req.release()->ScheduleWork();

4751-

args.GetReturnValue().Set(obj);

4752-

} else {

4753-

Local<Value> argv[2];

4754-

RandomBytesProcessSync(env, std::move(req), &argv);

4755-

if (argv[0]->IsNull())

4756-

args.GetReturnValue().Set(argv[1]);

4757-

}

4758-

}

4759-4760-4761-

void RandomBytesBuffer(const FunctionCallbackInfo<Value>& args) {

4762-

Environment* env = Environment::GetCurrent(args);

4763-4764-

CHECK(args[0]->IsArrayBufferView());

4765-

CHECK(args[1]->IsUint32());

4766-

CHECK(args[2]->IsUint32());

4767-4768-

int64_t offset = args[1]->IntegerValue();

4769-

int64_t size = args[2]->IntegerValue();

4770-4771-

Local<Object> obj = env->randombytes_constructor_template()->

4772-

NewInstance(env->context()).ToLocalChecked();

4773-

obj->Set(env->context(), env->buffer_string(), args[0]).FromJust();

4774-

char* data = Buffer::Data(args[0]);

4775-

data += offset;

4776-4777-

std::unique_ptr<RandomBytesRequest> req(

4778-

new RandomBytesRequest(env,

4779-

obj,

4780-

size,

4781-

data,

4782-

RandomBytesRequest::DONT_FREE_DATA));

4783-

if (args[3]->IsFunction()) {

4784-

obj->Set(env->context(), env->ondone_string(), args[3]).FromJust();

4785-4786-

req.release()->ScheduleWork();

4787-

args.GetReturnValue().Set(obj);

4788-

} else {

4789-

Local<Value> argv[2];

4790-

RandomBytesProcessSync(env, std::move(req), &argv);

4791-

if (argv[0]->IsNull())

4792-

args.GetReturnValue().Set(argv[1]);

4793-

}

4628+

std::unique_ptr<RandomBytesJob> job(new RandomBytesJob(env));

4629+

job->data = reinterpret_cast<unsigned char*>(Buffer::Data(args[0])) + offset;

4630+

job->size = size;

4631+

if (args[3]->IsObject()) return RandomBytesJob::Run(std::move(job), args[3]);

4632+

env->PrintSyncTrace();

4633+

job->DoThreadPoolWork();

4634+

args.GetReturnValue().Set(job->ToResult());

47944635

}

4795463647964637

@@ -5355,7 +5196,6 @@ void Initialize(Local<Object> target,

5355519653565197

env->SetMethod(target, "pbkdf2", PBKDF2);

53575198

env->SetMethod(target, "randomBytes", RandomBytes);

5358-

env->SetMethod(target, "randomFill", RandomBytesBuffer);

53595199

env->SetMethod(target, "timingSafeEqual", TimingSafeEqual);

53605200

env->SetMethod(target, "getSSLCiphers", GetSSLCiphers);

53615201

env->SetMethod(target, "getCiphers", GetCiphers);

@@ -5380,13 +5220,6 @@ void Initialize(Local<Object> target,

53805220

#ifndef OPENSSL_NO_SCRYPT

53815221

env->SetMethod(target, "scrypt", Scrypt);

53825222

#endif // OPENSSL_NO_SCRYPT

5383-5384-

Local<FunctionTemplate> rb = FunctionTemplate::New(env->isolate());

5385-

rb->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "RandomBytes"));

5386-

AsyncWrap::AddWrapMethods(env, rb);

5387-

Local<ObjectTemplate> rbt = rb->InstanceTemplate();

5388-

rbt->SetInternalFieldCount(1);

5389-

env->set_randombytes_constructor_template(rbt);

53905223

}

5391522453925225

} // namespace crypto