@@ -5595,11 +5595,18 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
5595
5595
// Only instantiate within a valid HandleScope.
5596
5596
class RandomBytesRequest : public AsyncWrap {
5597
5597
public:
5598
- RandomBytesRequest (Environment* env, Local<Object> object, size_t size)
5598
+ enum FreeMode { FREE_DATA, DONT_FREE_DATA };
5599
+
5600
+ RandomBytesRequest (Environment* env,
5601
+ Local<Object> object,
5602
+ size_t size,
5603
+ char * data,
5604
+ FreeMode free_mode)
5599
5605
: AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO),
5600
5606
error_ (0 ),
5601
5607
size_(size),
5602
- data_(node::Malloc(size)) {
5608
+ data_(data),
5609
+ free_mode_(free_mode) {
5603
5610
Wrap (object, this );
5604
5611
}
5605
5612
@@ -5620,9 +5627,15 @@ class RandomBytesRequest : public AsyncWrap {
5620
5627
return data_;
5621
5628
}
5622
5629
5630
+ inline void set_data (char * data) {
5631
+ data_ = data;
5632
+ }
5633
+
5623
5634
inline void release () {
5624
- free (data_);
5625
5635
size_ = 0 ;
5636
+ if (free_mode_ == FREE_DATA) {
5637
+ free (data_);
5638
+ }
5626
5639
}
5627
5640
5628
5641
inline void return_memory (char ** d, size_t * len) {
@@ -5648,6 +5661,7 @@ class RandomBytesRequest : public AsyncWrap {
5648
5661
unsigned long error_; // NOLINT(runtime/int)
5649
5662
size_t size_;
5650
5663
char * data_;
5664
+ const FreeMode free_mode_;
5651
5665
};
5652
5666
5653
5667
@@ -5686,7 +5700,18 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
5686
5700
size_t size;
5687
5701
req->return_memory (&data, &size);
5688
5702
argv[0 ] = Null (req->env ()->isolate ());
5689
- argv[1 ] = Buffer::New (req->env (), data, size).ToLocalChecked ();
5703
+ Local<Value> buffer =
5704
+ req->object ()->Get (req->env ()->context (),
5705
+ req->env ()->buffer_string ()).ToLocalChecked ();
5706
+
5707
+ if (buffer->IsUint8Array ()) {
5708
+ CHECK_LE (req->size (), Buffer::Length (buffer));
5709
+ char * buf = Buffer::Data (buffer);
5710
+ memcpy (buf, data, req->size ());
5711
+ argv[1 ] = buffer;
5712
+ } else {
5713
+ argv[1 ] = Buffer::New (req->env (), data, size).ToLocalChecked ();
5714
+ }
5690
5715
}
5691
5716
}
5692
5717
@@ -5705,11 +5730,22 @@ void RandomBytesAfter(uv_work_t* work_req, int status) {
5705
5730
}
5706
5731
5707
5732
5733
+ void RandomBytesProcessSync (Environment* env,
5734
+ RandomBytesRequest* req,
5735
+ Local<Value> argv[2 ]) {
5736
+ env->PrintSyncTrace ();
5737
+ RandomBytesWork (req->work_req ());
5738
+ RandomBytesCheck (req, argv);
5739
+ delete req;
5740
+
5741
+ if (!argv[0 ]->IsNull ())
5742
+ env->isolate ()->ThrowException (argv[0 ]);
5743
+ }
5744
+
5745
+
5708
5746
void RandomBytes (const FunctionCallbackInfo<Value>& args) {
5709
5747
Environment* env = Environment::GetCurrent (args);
5710
5748
5711
- // maybe allow a buffer to write to? cuts down on object creation
5712
- // when generating random data in a loop
5713
5749
if (!args[0 ]->IsUint32 ()) {
5714
5750
return env->ThrowTypeError (" size must be a number >= 0" );
5715
5751
}
@@ -5719,7 +5755,13 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
5719
5755
return env->ThrowRangeError (" size is not a valid Smi" );
5720
5756
5721
5757
Local<Object> obj = env->NewInternalFieldObject ();
5722
- RandomBytesRequest* req = new RandomBytesRequest (env, obj, size);
5758
+ char * data = node::Malloc (size);
5759
+ RandomBytesRequest* req =
5760
+ new RandomBytesRequest (env,
5761
+ obj,
5762
+ size,
5763
+ data,
5764
+ RandomBytesRequest::FREE_DATA);
5723
5765
5724
5766
if (args[1 ]->IsFunction ()) {
5725
5767
obj->Set (FIXED_ONE_BYTE_STRING (args.GetIsolate (), " ondone" ), args[1 ]);
@@ -5732,15 +5774,55 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
5732
5774
RandomBytesAfter);
5733
5775
args.GetReturnValue ().Set (obj);
5734
5776
} else {
5735
- env->PrintSyncTrace ();
5736
5777
Local<Value> argv[2 ];
5737
- RandomBytesWork (req->work_req ());
5738
- RandomBytesCheck (req, argv);
5739
- delete req;
5778
+ RandomBytesProcessSync (env, req, argv);
5779
+ if (argv[0 ]->IsNull ())
5780
+ args.GetReturnValue ().Set (argv[1 ]);
5781
+ }
5782
+ }
5740
5783
5741
- if (!argv[0 ]->IsNull ())
5742
- env->isolate ()->ThrowException (argv[0 ]);
5743
- else
5784
+
5785
+ void RandomBytesBuffer (const FunctionCallbackInfo<Value>& args) {
5786
+ Environment* env = Environment::GetCurrent (args);
5787
+
5788
+ CHECK (args[0 ]->IsUint8Array ());
5789
+ CHECK (args[1 ]->IsUint32 ());
5790
+ CHECK (args[2 ]->IsUint32 ());
5791
+
5792
+ int64_t offset = args[1 ]->IntegerValue ();
5793
+ int64_t size = args[2 ]->IntegerValue ();
5794
+
5795
+ Local<Object> obj = env->NewInternalFieldObject ();
5796
+ obj->Set (env->context (), env->buffer_string (), args[0 ]).FromJust ();
5797
+ char * data = Buffer::Data (args[0 ]);
5798
+ data += offset;
5799
+
5800
+ RandomBytesRequest* req =
5801
+ new RandomBytesRequest (env,
5802
+ obj,
5803
+ size,
5804
+ data,
5805
+ RandomBytesRequest::DONT_FREE_DATA);
5806
+ if (args[3 ]->IsFunction ()) {
5807
+ obj->Set (env->context (),
5808
+ FIXED_ONE_BYTE_STRING (args.GetIsolate (), " ondone" ),
5809
+ args[3 ]).FromJust ();
5810
+
5811
+ if (env->in_domain ()) {
5812
+ obj->Set (env->context (),
5813
+ env->domain_string (),
5814
+ env->domain_array ()->Get (0 )).FromJust ();
5815
+ }
5816
+
5817
+ uv_queue_work (env->event_loop (),
5818
+ req->work_req (),
5819
+ RandomBytesWork,
5820
+ RandomBytesAfter);
5821
+ args.GetReturnValue ().Set (obj);
5822
+ } else {
5823
+ Local<Value> argv[2 ];
5824
+ RandomBytesProcessSync (env, req, argv);
5825
+ if (argv[0 ]->IsNull ())
5744
5826
args.GetReturnValue ().Set (argv[1 ]);
5745
5827
}
5746
5828
}
@@ -6168,6 +6250,7 @@ void InitCrypto(Local<Object> target,
6168
6250
env->SetMethod (target, " setFipsCrypto" , SetFipsCrypto);
6169
6251
env->SetMethod (target, " PBKDF2" , PBKDF2);
6170
6252
env->SetMethod (target, " randomBytes" , RandomBytes);
6253
+ env->SetMethod (target, " randomFill" , RandomBytesBuffer);
6171
6254
env->SetMethod (target, " timingSafeEqual" , TimingSafeEqual);
6172
6255
env->SetMethod (target, " getSSLCiphers" , GetSSLCiphers);
6173
6256
env->SetMethod (target, " getCiphers" , GetCiphers);
0 commit comments