Browse Source

crypto: implement randomBytes() and pseudoRandomBytes()

v0.7.4-release
Ben Noordhuis 14 years ago
parent
commit
c4eaf7e5a9
  1. 8
      lib/crypto.js
  2. 12
      src/node.h
  3. 135
      src/node_crypto.cc
  4. 1
      src/node_crypto.h

8
lib/crypto.js

@ -31,6 +31,8 @@ try {
var Verify = binding.Verify; var Verify = binding.Verify;
var DiffieHellman = binding.DiffieHellman; var DiffieHellman = binding.DiffieHellman;
var PBKDF2 = binding.PBKDF2; var PBKDF2 = binding.PBKDF2;
var randomBytes = binding.randomBytes;
var pseudoRandomBytes = binding.pseudoRandomBytes;
var crypto = true; var crypto = true;
} catch (e) { } catch (e) {
@ -163,3 +165,9 @@ exports.createDiffieHellman = function(size_or_key, enc) {
} }
exports.pbkdf2 = PBKDF2; exports.pbkdf2 = PBKDF2;
exports.randomBytes = randomBytes;
exports.pseudoRandomBytes = pseudoRandomBytes;
exports.rng = randomBytes;
exports.prng = pseudoRandomBytes;

12
src/node.h

@ -45,6 +45,18 @@
#include <node_object_wrap.h> #include <node_object_wrap.h>
#ifndef offset_of
// g++ in strict mode complains loudly about the system offsetof() macro
// because it uses NULL as the base address.
#define offset_of(type, member) \
((intptr_t) ((char *) &(((type *) 8)->member) - 8))
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offset_of(type, member)))
#endif
#ifndef ARRAY_SIZE #ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) #define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#endif #endif

135
src/node_crypto.cc

@ -4013,6 +4013,139 @@ PBKDF2(const Arguments& args) {
return Undefined(); return Undefined();
} }
typedef int (*RandomBytesGenerator)(unsigned char* buf, int size);
struct RandomBytesRequest {
~RandomBytesRequest();
Persistent<Function> callback_;
unsigned long error_; // openssl error code or zero
uv_work_t work_req_;
size_t size_;
char* data_;
};
RandomBytesRequest::~RandomBytesRequest() {
if (!callback_.IsEmpty()) {
callback_.Dispose();
callback_.Clear();
}
}
void RandomBytesFree(char* data, void* hint) {
delete[] data;
}
template <RandomBytesGenerator generator>
void RandomBytesWork(uv_work_t* work_req) {
RandomBytesRequest* req =
container_of(work_req, RandomBytesRequest, work_req_);
int r = generator(reinterpret_cast<unsigned char*>(req->data_), req->size_);
switch (r) {
case 0:
// RAND_bytes() returns 0 on error, RAND_pseudo_bytes() returns 0
// when the result is not cryptographically strong - the latter
// sucks but is not an error
if (generator == RAND_bytes)
req->error_ = ERR_get_error();
break;
case -1:
// not supported - can this actually happen?
req->error_ = (unsigned long) -1;
break;
}
}
void RandomBytesCheck(RandomBytesRequest* req, Handle<Value> argv[2]) {
HandleScope scope;
if (req->error_) {
char errmsg[256] = "Operation not supported";
if (req->error_ != (unsigned long) -1)
ERR_error_string_n(req->error_, errmsg, sizeof errmsg);
argv[0] = Exception::Error(String::New(errmsg));
argv[1] = Null();
}
else {
// avoids the malloc + memcpy
Buffer* buffer = Buffer::New(req->data_, req->size_, RandomBytesFree, NULL);
argv[0] = Null();
argv[1] = buffer->handle_;
}
}
template <RandomBytesGenerator generator>
void RandomBytesAfter(uv_work_t* work_req) {
RandomBytesRequest* req =
container_of(work_req, RandomBytesRequest, work_req_);
HandleScope scope;
Handle<Value> argv[2];
RandomBytesCheck(req, argv);
TryCatch tc;
req->callback_->Call(Context::GetCurrent()->Global(), 2, argv);
if (tc.HasCaught())
FatalException(tc);
delete req;
}
template <RandomBytesGenerator generator>
Handle<Value> RandomBytes(const Arguments& args) {
HandleScope scope;
// maybe allow a buffer to write to? cuts down on object creation
// when generating random data in a loop
if (!args[0]->IsUint32()) {
Local<String> s = String::New("Argument #1 must be number > 0");
return ThrowException(Exception::TypeError(s));
}
const size_t size = args[0]->Uint32Value();
RandomBytesRequest* req = new RandomBytesRequest();
req->error_ = 0;
req->data_ = new char[size];
req->size_ = size;
if (args[1]->IsFunction()) {
Local<Function> callback_v = Local<Function>(Function::Cast(*args[1]));
req->callback_ = Persistent<Function>::New(callback_v);
uv_queue_work(uv_default_loop(),
&req->work_req_,
RandomBytesWork<generator>,
RandomBytesAfter<generator>);
return Undefined();
}
else {
Handle<Value> argv[2];
RandomBytesWork<generator>(&req->work_req_);
RandomBytesCheck(req, argv);
delete req;
if (!argv[0]->IsNull())
return ThrowException(argv[0]);
else
return argv[1];
}
}
void InitCrypto(Handle<Object> target) { void InitCrypto(Handle<Object> target) {
HandleScope scope; HandleScope scope;
@ -4046,6 +4179,8 @@ void InitCrypto(Handle<Object> target) {
Verify::Initialize(target); Verify::Initialize(target);
NODE_SET_METHOD(target, "PBKDF2", PBKDF2); NODE_SET_METHOD(target, "PBKDF2", PBKDF2);
NODE_SET_METHOD(target, "randomBytes", RandomBytes<RAND_bytes>);
NODE_SET_METHOD(target, "pseudoRandomBytes", RandomBytes<RAND_pseudo_bytes>);
subject_symbol = NODE_PSYMBOL("subject"); subject_symbol = NODE_PSYMBOL("subject");
issuer_symbol = NODE_PSYMBOL("issuer"); issuer_symbol = NODE_PSYMBOL("issuer");

1
src/node_crypto.h

@ -34,6 +34,7 @@
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/x509v3.h> #include <openssl/x509v3.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/rand.h>
#ifdef OPENSSL_NPN_NEGOTIATED #ifdef OPENSSL_NPN_NEGOTIATED
#include <node_buffer.h> #include <node_buffer.h>

Loading…
Cancel
Save