Skip to content

Commit dc63a41

Browse files
scovettaMichael Scovetta
authored andcommitted
Expose RAND_poll / RAND_add to user code via crypto module.
The purpose of this patch is to allow Node applications to add additional entropy to OpenSSL's pool. This is useful in environments where a running Node process can be cloned (e.g. VM snapshotting or live migration), resulting in a chance of the cloned process sharing an entropy pool with the original process. The new AddEntropy function works as follows: - If no parameters are passed, it calls RAND_poll. Performance was evaluated at about 140k ops/sec, but this will vary by OS and hardware. - If one parameter is passed, it is expected to be a buffer, which is passed to RAND_add. Performance was evaluated at about 1.8m ops/sec. The AddEntropy function is bound to crypto.addEntropy(). Usage: var crypto = require('crypto'); // Add entropy from system-supplied source crypto.addEntropy(); // Add entropy from a user-supplied source crypto.addEntropy(new Uint8Array([38, 4, 19, 22]));
1 parent 56efb3d commit dc63a41

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

lib/crypto.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ try {
1111
var getCiphers = binding.getCiphers;
1212
var getHashes = binding.getHashes;
1313
var getCurves = binding.getCurves;
14+
var addEntropy = binding.addEntropy;
1415
} catch (e) {
1516
throw new Error('Node.js is not compiled with openssl crypto support');
1617
}
@@ -621,6 +622,8 @@ exports.randomBytes = exports.pseudoRandomBytes = randomBytes;
621622

622623
exports.rng = exports.prng = randomBytes;
623624

625+
exports.addEntropy = addEntropy;
626+
624627
exports.getCiphers = function() {
625628
return filterDuplicates(getCiphers());
626629
};

src/node_crypto.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5354,6 +5354,25 @@ void GetCurves(const FunctionCallbackInfo<Value>& args) {
53545354
}
53555355

53565356

5357+
void AddEntropy(const FunctionCallbackInfo<Value>& args) {
5358+
Environment* env = Environment::GetCurrent(args);
5359+
5360+
if (args.Length() == 0) {
5361+
// Delegate entropy generation to OpenSSL, which will add
5362+
// entropy from system sources
5363+
RAND_poll();
5364+
return;
5365+
}
5366+
// Make sure we got a buffer from the user and use it to
5367+
// seed OpenSSL.
5368+
THROW_AND_RETURN_IF_NOT_BUFFER(args[0]);
5369+
Local<Object> bufObj = args[0]->ToObject();
5370+
const void* buf = Buffer::Data(bufObj);
5371+
size_t bufLength = Buffer::Length(bufObj);
5372+
RAND_seed(buf, bufLength);
5373+
}
5374+
5375+
53575376
void Certificate::Initialize(Environment* env, Local<Object> target) {
53585377
HandleScope scope(env->isolate());
53595378

@@ -5648,6 +5667,7 @@ void InitCrypto(Local<Object> target,
56485667
env->SetMethod(target, "getCiphers", GetCiphers);
56495668
env->SetMethod(target, "getHashes", GetHashes);
56505669
env->SetMethod(target, "getCurves", GetCurves);
5670+
env->SetMethod(target, "addEntropy", AddEntropy);
56515671
env->SetMethod(target, "publicEncrypt",
56525672
PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
56535673
EVP_PKEY_encrypt_init,

test/parallel/test-crypto-random.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ process.setMaxListeners(256);
3737
});
3838
});
3939

40+
// crypto.addEntropy takes nothing or an ArrayBuffer
41+
[-1,
42+
undefined,
43+
null,
44+
false,
45+
true,
46+
{}, [], [1]
47+
].forEach(function(value) {
48+
assert.throws(function() { crypto.addEntropy(value); });
49+
});
50+
4051
// assert that the callback is indeed called
4152
function checkCall(cb, desc) {
4253
var called_ = false;

0 commit comments

Comments
 (0)