@@ -5449,11 +5449,18 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
5449
5449
// Only instantiate within a valid HandleScope.
5450
5450
class RandomBytesRequest : public AsyncWrap {
5451
5451
public:
5452
- RandomBytesRequest (Environment* env, Local<Object> object, size_t size)
5452
+ enum FreeMode { FREE_DATA, DONT_FREE_DATA };
5453
+
5454
+ RandomBytesRequest (Environment* env,
5455
+ Local<Object> object,
5456
+ size_t size,
5457
+ char * data,
5458
+ FreeMode free_mode)
5453
5459
: AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO),
5454
5460
error_ (0 ),
5455
5461
size_(size),
5456
- data_(node::Malloc(size)) {
5462
+ data_(data),
5463
+ free_mode_(free_mode) {
5457
5464
Wrap (object, this );
5458
5465
}
5459
5466
@@ -5474,9 +5481,15 @@ class RandomBytesRequest : public AsyncWrap {
5474
5481
return data_;
5475
5482
}
5476
5483
5484
+ inline void set_data (char * data) {
5485
+ data_ = data;
5486
+ }
5487
+
5477
5488
inline void release () {
5478
- free (data_);
5479
5489
size_ = 0 ;
5490
+ if (free_mode_ == FREE_DATA) {
5491
+ free (data_);
5492
+ }
5480
5493
}
5481
5494
5482
5495
inline void return_memory (char ** d, size_t * len) {
@@ -5502,6 +5515,7 @@ class RandomBytesRequest : public AsyncWrap {
5502
5515
unsigned long error_; // NOLINT(runtime/int)
5503
5516
size_t size_;
5504
5517
char * data_;
5518
+ const FreeMode free_mode_;
5505
5519
};
5506
5520
5507
5521
@@ -5540,7 +5554,18 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
5540
5554
size_t size;
5541
5555
req->return_memory (&data, &size);
5542
5556
argv[0 ] = Null (req->env ()->isolate ());
5543
- argv[1 ] = Buffer::New (req->env (), data, size).ToLocalChecked ();
5557
+ Local<Value> buffer =
5558
+ req->object ()->Get (req->env ()->context (),
5559
+ req->env ()->buffer_string ()).ToLocalChecked ();
5560
+
5561
+ if (buffer->IsUint8Array ()) {
5562
+ CHECK_LE (req->size (), Buffer::Length (buffer));
5563
+ char * buf = Buffer::Data (buffer);
5564
+ memcpy (buf, data, req->size ());
5565
+ argv[1 ] = buffer;
5566
+ } else {
5567
+ argv[1 ] = Buffer::New (req->env (), data, size).ToLocalChecked ();
5568
+ }
5544
5569
}
5545
5570
}
5546
5571
@@ -5559,11 +5584,22 @@ void RandomBytesAfter(uv_work_t* work_req, int status) {
5559
5584
}
5560
5585
5561
5586
5587
+ void RandomBytesProcessSync (Environment* env,
5588
+ RandomBytesRequest* req,
5589
+ Local<Value> argv[2 ]) {
5590
+ env->PrintSyncTrace ();
5591
+ RandomBytesWork (req->work_req ());
5592
+ RandomBytesCheck (req, argv);
5593
+ delete req;
5594
+
5595
+ if (!argv[0 ]->IsNull ())
5596
+ env->isolate ()->ThrowException (argv[0 ]);
5597
+ }
5598
+
5599
+
5562
5600
void RandomBytes (const FunctionCallbackInfo<Value>& args) {
5563
5601
Environment* env = Environment::GetCurrent (args);
5564
5602
5565
- // maybe allow a buffer to write to? cuts down on object creation
5566
- // when generating random data in a loop
5567
5603
if (!args[0 ]->IsUint32 ()) {
5568
5604
return env->ThrowTypeError (" size must be a number >= 0" );
5569
5605
}
@@ -5573,7 +5609,13 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
5573
5609
return env->ThrowRangeError (" size is not a valid Smi" );
5574
5610
5575
5611
Local<Object> obj = env->NewInternalFieldObject ();
5576
- RandomBytesRequest* req = new RandomBytesRequest (env, obj, size);
5612
+ char * data = node::Malloc (size);
5613
+ RandomBytesRequest* req =
5614
+ new RandomBytesRequest (env,
5615
+ obj,
5616
+ size,
5617
+ data,
5618
+ RandomBytesRequest::FREE_DATA);
5577
5619
5578
5620
if (args[1 ]->IsFunction ()) {
5579
5621
obj->Set (env->ondone_string (), args[1 ]);
@@ -5586,15 +5628,55 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
5586
5628
RandomBytesAfter);
5587
5629
args.GetReturnValue ().Set (obj);
5588
5630
} else {
5589
- env->PrintSyncTrace ();
5590
5631
Local<Value> argv[2 ];
5591
- RandomBytesWork (req->work_req ());
5592
- RandomBytesCheck (req, argv);
5593
- delete req;
5632
+ RandomBytesProcessSync (env, req, argv);
5633
+ if (argv[0 ]->IsNull ())
5634
+ args.GetReturnValue ().Set (argv[1 ]);
5635
+ }
5636
+ }
5594
5637
5595
- if (!argv[0 ]->IsNull ())
5596
- env->isolate ()->ThrowException (argv[0 ]);
5597
- else
5638
+
5639
+ void RandomBytesBuffer (const FunctionCallbackInfo<Value>& args) {
5640
+ Environment* env = Environment::GetCurrent (args);
5641
+
5642
+ CHECK (args[0 ]->IsUint8Array ());
5643
+ CHECK (args[1 ]->IsUint32 ());
5644
+ CHECK (args[2 ]->IsUint32 ());
5645
+
5646
+ int64_t offset = args[1 ]->IntegerValue ();
5647
+ int64_t size = args[2 ]->IntegerValue ();
5648
+
5649
+ Local<Object> obj = env->NewInternalFieldObject ();
5650
+ obj->Set (env->context (), env->buffer_string (), args[0 ]).FromJust ();
5651
+ char * data = Buffer::Data (args[0 ]);
5652
+ data += offset;
5653
+
5654
+ RandomBytesRequest* req =
5655
+ new RandomBytesRequest (env,
5656
+ obj,
5657
+ size,
5658
+ data,
5659
+ RandomBytesRequest::DONT_FREE_DATA);
5660
+ if (args[3 ]->IsFunction ()) {
5661
+ obj->Set (env->context (),
5662
+ FIXED_ONE_BYTE_STRING (args.GetIsolate (), " ondone" ),
5663
+ args[3 ]).FromJust ();
5664
+
5665
+ if (env->in_domain ()) {
5666
+ obj->Set (env->context (),
5667
+ env->domain_string (),
5668
+ env->domain_array ()->Get (0 )).FromJust ();
5669
+ }
5670
+
5671
+ uv_queue_work (env->event_loop (),
5672
+ req->work_req (),
5673
+ RandomBytesWork,
5674
+ RandomBytesAfter);
5675
+ args.GetReturnValue ().Set (obj);
5676
+ } else {
5677
+ Local<Value> argv[2 ];
5678
+ RandomBytesProcessSync (env, req, argv);
5679
+ if (argv[0 ]->IsNull ())
5598
5680
args.GetReturnValue ().Set (argv[1 ]);
5599
5681
}
5600
5682
}
@@ -6019,6 +6101,7 @@ void InitCrypto(Local<Object> target,
6019
6101
env->SetMethod (target, " setFipsCrypto" , SetFipsCrypto);
6020
6102
env->SetMethod (target, " PBKDF2" , PBKDF2);
6021
6103
env->SetMethod (target, " randomBytes" , RandomBytes);
6104
+ env->SetMethod (target, " randomFill" , RandomBytesBuffer);
6022
6105
env->SetMethod (target, " timingSafeEqual" , TimingSafeEqual);
6023
6106
env->SetMethod (target, " getSSLCiphers" , GetSSLCiphers);
6024
6107
env->SetMethod (target, " getCiphers" , GetCiphers);
0 commit comments