Permalink
Browse files

crypto: add sync interface to crypto.pbkdf2()

Fixes #3766.
  • Loading branch information...
1 parent febffc1 commit 73469bc08043d20696f976deda46f0de1f7be8e9 @bnoordhuis committed Jul 25, 2012
Showing with 95 additions and 100 deletions.
  1. +67 −61 src/node_crypto.cc
  2. +28 −39 test/simple/test-crypto.js
View
@@ -4192,7 +4192,9 @@ class DiffieHellman : public ObjectWrap {
DH* dh;
};
+
struct pbkdf2_req {
+ uv_work_t work_req;
int err;
char* pass;
size_t passlen;
@@ -4204,71 +4206,75 @@ struct pbkdf2_req {
Persistent<Function> callback;
};
-void
-EIO_PBKDF2(uv_work_t* req) {
- pbkdf2_req* request = (pbkdf2_req*)req->data;
- request->err = PKCS5_PBKDF2_HMAC_SHA1(
- request->pass,
- request->passlen,
- (unsigned char*)request->salt,
- request->saltlen,
- request->iter,
- request->keylen,
- (unsigned char*)request->key);
- memset(request->pass, 0, request->passlen);
- memset(request->salt, 0, request->saltlen);
+
+void EIO_PBKDF2(pbkdf2_req* req) {
+ req->err = PKCS5_PBKDF2_HMAC_SHA1(
+ req->pass,
+ req->passlen,
+ (unsigned char*)req->salt,
+ req->saltlen,
+ req->iter,
+ req->keylen,
+ (unsigned char*)req->key);
+ memset(req->pass, 0, req->passlen);
+ memset(req->salt, 0, req->saltlen);
}
-void
-EIO_PBKDF2After(uv_work_t* req) {
- HandleScope scope;
- pbkdf2_req* request = (pbkdf2_req*)req->data;
- delete req;
+void EIO_PBKDF2(uv_work_t* work_req) {
+ pbkdf2_req* req = container_of(work_req, pbkdf2_req, work_req);
+ EIO_PBKDF2(req);
+}
- Local<Value> argv[2];
- if (request->err) {
+
+void EIO_PBKDF2After(pbkdf2_req* req, Local<Value> argv[2]) {
+ if (req->err) {
argv[0] = Local<Value>::New(Undefined());
- argv[1] = Encode(request->key, request->keylen, BINARY);
- memset(request->key, 0, request->keylen);
+ argv[1] = Encode(req->key, req->keylen, BINARY);
+ memset(req->key, 0, req->keylen);
} else {
argv[0] = Exception::Error(String::New("PBKDF2 error"));
argv[1] = Local<Value>::New(Undefined());
}
- // XXX There should be an object connected to this that
- // we can attach a domain onto.
- MakeCallback(Context::GetCurrent()->Global(),
- request->callback,
- ARRAY_SIZE(argv), argv);
+ delete[] req->pass;
+ delete[] req->salt;
+ delete[] req->key;
+ delete req;
+}
+
- delete[] request->pass;
- delete[] request->salt;
- delete[] request->key;
- request->callback.Dispose();
+void EIO_PBKDF2After(uv_work_t* work_req) {
+ pbkdf2_req* req = container_of(work_req, pbkdf2_req, work_req);
- delete request;
+ HandleScope scope;
+ Local<Value> argv[2];
+ Persistent<Function> cb = req->callback;
+ EIO_PBKDF2After(req, argv);
+
+ // XXX There should be an object connected to this that
+ // we can attach a domain onto.
+ MakeCallback(Context::GetCurrent()->Global(), cb, ARRAY_SIZE(argv), argv);
+ cb.Dispose();
}
-Handle<Value>
-PBKDF2(const Arguments& args) {
+
+Handle<Value> PBKDF2(const Arguments& args) {
HandleScope scope;
const char* type_error = NULL;
char* pass = NULL;
char* salt = NULL;
- char* key = NULL;
ssize_t passlen = -1;
ssize_t saltlen = -1;
ssize_t keylen = -1;
ssize_t pass_written = -1;
ssize_t salt_written = -1;
ssize_t iter = -1;
Local<Function> callback;
- pbkdf2_req* request = NULL;
- uv_work_t* req = NULL;
+ pbkdf2_req* req = NULL;
- if (args.Length() != 5) {
+ if (args.Length() != 4 && args.Length() != 5) {
type_error = "Bad parameter";
goto err;
}
@@ -4317,33 +4323,33 @@ PBKDF2(const Arguments& args) {
goto err;
}
- key = new char[keylen];
+ req = new pbkdf2_req;
+ req->err = 0;
+ req->pass = pass;
+ req->passlen = passlen;
+ req->salt = salt;
+ req->saltlen = saltlen;
+ req->iter = iter;
+ req->key = new char[keylen];
+ req->keylen = keylen;
- if (!args[4]->IsFunction()) {
- type_error = "Callback not a function";
- goto err;
+ if (args[4]->IsFunction()) {
+ callback = Local<Function>::Cast(args[4]);
+ req->callback = Persistent<Function>::New(callback);
+ uv_queue_work(uv_default_loop(),
+ &req->work_req,
+ EIO_PBKDF2,
+ EIO_PBKDF2After);
+ return Undefined();
+ } else {
+ Local<Value> argv[2];
+ EIO_PBKDF2(req);
+ EIO_PBKDF2After(req, argv);
+ if (argv[0]->IsObject()) return ThrowException(argv[0]);
+ return scope.Close(argv[1]);
}
- callback = Local<Function>::Cast(args[4]);
-
- request = new pbkdf2_req;
- request->err = 0;
- request->pass = pass;
- request->passlen = passlen;
- request->salt = salt;
- request->saltlen = saltlen;
- request->iter = iter;
- request->key = key;
- request->keylen = keylen;
- request->callback = Persistent<Function>::New(callback);
-
- req = new uv_work_t();
- req->data = request;
- uv_queue_work(uv_default_loop(), req, EIO_PBKDF2, EIO_PBKDF2After);
- return Undefined();
-
err:
- delete[] key;
delete[] salt;
delete[] pass;
return ThrowException(Exception::TypeError(String::New(type_error)));
View
@@ -618,46 +618,35 @@ assert.strictEqual(rsaVerify.verify(rsaPubPem, rsaSignature, 'hex'), true);
//
// Test PBKDF2 with RFC 6070 test vectors (except #4)
//
-crypto.pbkdf2('password', 'salt', 1, 20, function(err, result) {
- assert.equal(result,
- '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' +
- '\xaf\x60\x12\x06\x2f\xe0\x37\xa6',
- 'pbkdf1 test vector 1');
-});
+function testPBKDF2(password, salt, iterations, keylen, expected) {
+ var actual = crypto.pbkdf2(password, salt, iterations, keylen);
+ assert.equal(actual, expected);
-crypto.pbkdf2('password', 'salt', 2, 20, function(err, result) {
- assert.equal(result,
- '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' +
- '\xce\x1d\x41\xf0\xd8\xde\x89\x57',
- 'pbkdf1 test vector 2');
-});
+ crypto.pbkdf2(password, salt, iterations, keylen, function(err, actual) {
+ assert.equal(actual, expected);
+ });
+}
-crypto.pbkdf2('password', 'salt', 4096, 20, function(err, result) {
- assert.equal(result,
- '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' +
- '\xf7\x21\xd0\x65\xa4\x29\xc1',
- 'pbkdf1 test vector 3');
-});
-crypto.pbkdf2(
- 'passwordPASSWORDpassword',
- 'saltSALTsaltSALTsaltSALTsaltSALTsalt',
- 4096,
- 25, function(err, result) {
- assert.equal(result,
- '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' +
- '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38',
- 'pbkdf1 test vector 5');
- });
-
-crypto.pbkdf2('pass\0word', 'sa\0lt', 4096, 16, function(err, result) {
- assert.equal(result,
- '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' +
- '\x25\xe0\xc3',
- 'pbkdf1 test vector 6');
-});
+testPBKDF2('password', 'salt', 1, 20,
+ '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' +
+ '\xaf\x60\x12\x06\x2f\xe0\x37\xa6');
-// Error path should not leak memory (check with valgrind).
-assert.throws(function() {
- crypto.pbkdf2('password', 'salt', 1, 20, null);
-});
+testPBKDF2('password', 'salt', 2, 20,
+ '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' +
+ '\xce\x1d\x41\xf0\xd8\xde\x89\x57');
+
+testPBKDF2('password', 'salt', 4096, 20,
+ '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' +
+ '\xf7\x21\xd0\x65\xa4\x29\xc1');
+
+testPBKDF2('passwordPASSWORDpassword',
+ 'saltSALTsaltSALTsaltSALTsaltSALTsalt',
+ 4096,
+ 25,
+ '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' +
+ '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38');
+
+testPBKDF2('pass\0word', 'sa\0lt', 4096, 16,
+ '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' +
+ '\x25\xe0\xc3');

0 comments on commit 73469bc

Please sign in to comment.