@@ -4013,6 +4013,139 @@ PBKDF2(const Arguments& args) {
40134013 return Undefined ();
40144014}
40154015
4016+
4017+ typedef int (*RandomBytesGenerator)(unsigned char * buf, int size);
4018+
4019+ struct RandomBytesRequest {
4020+ ~RandomBytesRequest ();
4021+ Persistent<Function> callback_;
4022+ unsigned long error_; // openssl error code or zero
4023+ uv_work_t work_req_;
4024+ size_t size_;
4025+ char * data_;
4026+ };
4027+
4028+
4029+ RandomBytesRequest::~RandomBytesRequest () {
4030+ if (!callback_.IsEmpty ()) {
4031+ callback_.Dispose ();
4032+ callback_.Clear ();
4033+ }
4034+ }
4035+
4036+
4037+ void RandomBytesFree (char * data, void * hint) {
4038+ delete[] data;
4039+ }
4040+
4041+
4042+ template <RandomBytesGenerator generator>
4043+ void RandomBytesWork (uv_work_t * work_req) {
4044+ RandomBytesRequest* req =
4045+ container_of (work_req, RandomBytesRequest, work_req_);
4046+
4047+ int r = generator (reinterpret_cast <unsigned char *>(req->data_ ), req->size_ );
4048+
4049+ switch (r) {
4050+ case 0 :
4051+ // RAND_bytes() returns 0 on error, RAND_pseudo_bytes() returns 0
4052+ // when the result is not cryptographically strong - the latter
4053+ // sucks but is not an error
4054+ if (generator == RAND_bytes)
4055+ req->error_ = ERR_get_error ();
4056+ break ;
4057+
4058+ case -1 :
4059+ // not supported - can this actually happen?
4060+ req->error_ = (unsigned long ) -1 ;
4061+ break ;
4062+ }
4063+ }
4064+
4065+
4066+ void RandomBytesCheck (RandomBytesRequest* req, Handle<Value> argv[2 ]) {
4067+ HandleScope scope;
4068+
4069+ if (req->error_ ) {
4070+ char errmsg[256 ] = " Operation not supported" ;
4071+
4072+ if (req->error_ != (unsigned long ) -1 )
4073+ ERR_error_string_n (req->error_ , errmsg, sizeof errmsg);
4074+
4075+ argv[0 ] = Exception::Error (String::New (errmsg));
4076+ argv[1 ] = Null ();
4077+ }
4078+ else {
4079+ // avoids the malloc + memcpy
4080+ Buffer* buffer = Buffer::New (req->data_ , req->size_ , RandomBytesFree, NULL );
4081+ argv[0 ] = Null ();
4082+ argv[1 ] = buffer->handle_ ;
4083+ }
4084+ }
4085+
4086+
4087+ template <RandomBytesGenerator generator>
4088+ void RandomBytesAfter (uv_work_t * work_req) {
4089+ RandomBytesRequest* req =
4090+ container_of (work_req, RandomBytesRequest, work_req_);
4091+
4092+ HandleScope scope;
4093+ Handle<Value> argv[2 ];
4094+ RandomBytesCheck (req, argv);
4095+
4096+ TryCatch tc;
4097+ req->callback_ ->Call (Context::GetCurrent ()->Global (), 2 , argv);
4098+
4099+ if (tc.HasCaught ())
4100+ FatalException (tc);
4101+
4102+ delete req;
4103+ }
4104+
4105+
4106+ template <RandomBytesGenerator generator>
4107+ Handle<Value> RandomBytes (const Arguments& args) {
4108+ HandleScope scope;
4109+
4110+ // maybe allow a buffer to write to? cuts down on object creation
4111+ // when generating random data in a loop
4112+ if (!args[0 ]->IsUint32 ()) {
4113+ Local<String> s = String::New (" Argument #1 must be number > 0" );
4114+ return ThrowException (Exception::TypeError (s));
4115+ }
4116+
4117+ const size_t size = args[0 ]->Uint32Value ();
4118+
4119+ RandomBytesRequest* req = new RandomBytesRequest ();
4120+ req->error_ = 0 ;
4121+ req->data_ = new char [size];
4122+ req->size_ = size;
4123+
4124+ if (args[1 ]->IsFunction ()) {
4125+ Local<Function> callback_v = Local<Function>(Function::Cast (*args[1 ]));
4126+ req->callback_ = Persistent<Function>::New (callback_v);
4127+
4128+ uv_queue_work (uv_default_loop (),
4129+ &req->work_req_ ,
4130+ RandomBytesWork<generator>,
4131+ RandomBytesAfter<generator>);
4132+
4133+ return Undefined ();
4134+ }
4135+ else {
4136+ Handle<Value> argv[2 ];
4137+ RandomBytesWork<generator>(&req->work_req_ );
4138+ RandomBytesCheck (req, argv);
4139+ delete req;
4140+
4141+ if (!argv[0 ]->IsNull ())
4142+ return ThrowException (argv[0 ]);
4143+ else
4144+ return argv[1 ];
4145+ }
4146+ }
4147+
4148+
40164149void InitCrypto (Handle<Object> target) {
40174150 HandleScope scope;
40184151
@@ -4046,6 +4179,8 @@ void InitCrypto(Handle<Object> target) {
40464179 Verify::Initialize (target);
40474180
40484181 NODE_SET_METHOD (target, " PBKDF2" , PBKDF2);
4182+ NODE_SET_METHOD (target, " randomBytes" , RandomBytes<RAND_bytes>);
4183+ NODE_SET_METHOD (target, " pseudoRandomBytes" , RandomBytes<RAND_pseudo_bytes>);
40494184
40504185 subject_symbol = NODE_PSYMBOL (" subject" );
40514186 issuer_symbol = NODE_PSYMBOL (" issuer" );
0 commit comments