crypto: implement randomBytes() and pseudoRandomBytes()
This commit is contained in:
parent
67706b8bb7
commit
c4eaf7e5a9
@ -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
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
|
||||||
|
@ -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");
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user