Skip to content

Commit c4eaf7e

Browse files
committed
crypto: implement randomBytes() and pseudoRandomBytes()
1 parent 67706b8 commit c4eaf7e

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

lib/crypto.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ try {
3131
var Verify = binding.Verify;
3232
var DiffieHellman = binding.DiffieHellman;
3333
var PBKDF2 = binding.PBKDF2;
34+
var randomBytes = binding.randomBytes;
35+
var pseudoRandomBytes = binding.pseudoRandomBytes;
3436
var crypto = true;
3537
} catch (e) {
3638

@@ -163,3 +165,9 @@ exports.createDiffieHellman = function(size_or_key, enc) {
163165
}
164166

165167
exports.pbkdf2 = PBKDF2;
168+
169+
exports.randomBytes = randomBytes;
170+
exports.pseudoRandomBytes = pseudoRandomBytes;
171+
172+
exports.rng = randomBytes;
173+
exports.prng = pseudoRandomBytes;

src/node.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@
4545

4646
#include <node_object_wrap.h>
4747

48+
#ifndef offset_of
49+
// g++ in strict mode complains loudly about the system offsetof() macro
50+
// because it uses NULL as the base address.
51+
#define offset_of(type, member) \
52+
((intptr_t) ((char *) &(((type *) 8)->member) - 8))
53+
#endif
54+
55+
#ifndef container_of
56+
#define container_of(ptr, type, member) \
57+
((type *) ((char *) (ptr) - offset_of(type, member)))
58+
#endif
59+
4860
#ifndef ARRAY_SIZE
4961
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
5062
#endif

src/node_crypto.cc

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
40164149
void 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");

src/node_crypto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <openssl/x509.h>
3535
#include <openssl/x509v3.h>
3636
#include <openssl/hmac.h>
37+
#include <openssl/rand.h>
3738

3839
#ifdef OPENSSL_NPN_NEGOTIATED
3940
#include <node_buffer.h>

0 commit comments

Comments
 (0)