crypto: PBKDF2 function from OpenSSL
This commit is contained in:
parent
01b64fc36b
commit
04122ad2d3
@ -233,3 +233,8 @@ or `'base64'`.
|
||||
|
||||
Sets the Diffie-Hellman private key. Key encoding can be `'binary'`, `'hex'`, or `'base64'`.
|
||||
|
||||
### pbkdf2(password, salt, iterations, keylen, callback)
|
||||
|
||||
Asynchronous PBKDF2 applies pseudorandom function HMAC-SHA1 to derive
|
||||
a key of given length from the given password, salt and iterations.
|
||||
The callback gets two arguments `(err, derivedKey)`.
|
||||
|
@ -30,6 +30,7 @@ try {
|
||||
var Sign = binding.Sign;
|
||||
var Verify = binding.Verify;
|
||||
var DiffieHellman = binding.DiffieHellman;
|
||||
var PBKDF2 = binding.PBKDF2;
|
||||
var crypto = true;
|
||||
} catch (e) {
|
||||
|
||||
@ -160,3 +161,5 @@ exports.createDiffieHellman = function(size_or_key, enc) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports.pbkdf2 = PBKDF2;
|
||||
|
@ -3752,6 +3752,123 @@ class DiffieHellman : public ObjectWrap {
|
||||
DH* dh;
|
||||
};
|
||||
|
||||
struct pbkdf2_req {
|
||||
int err;
|
||||
char* pass;
|
||||
size_t passlen;
|
||||
char* salt;
|
||||
size_t saltlen;
|
||||
size_t iter;
|
||||
char* key;
|
||||
size_t keylen;
|
||||
Persistent<Function> callback;
|
||||
};
|
||||
|
||||
void
|
||||
EIO_PBKDF2(eio_req* 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);
|
||||
}
|
||||
|
||||
int
|
||||
EIO_PBKDF2After(eio_req* req) {
|
||||
HandleScope scope;
|
||||
|
||||
ev_unref(EV_DEFAULT_UC);
|
||||
|
||||
pbkdf2_req* request = (pbkdf2_req*)req->data;
|
||||
Handle<Value> argv[2];
|
||||
if (request->err) {
|
||||
argv[0] = Undefined();
|
||||
argv[1] = Encode(request->key, request->keylen, BINARY);
|
||||
memset(request->key, 0, request->keylen);
|
||||
} else {
|
||||
argv[0] = Exception::Error(String::New("PBKDF2 error"));
|
||||
argv[1] = Undefined();
|
||||
}
|
||||
|
||||
TryCatch try_catch;
|
||||
|
||||
request->callback->Call(Context::GetCurrent()->Global(), 2, argv);
|
||||
|
||||
if (try_catch.HasCaught())
|
||||
FatalException(try_catch);
|
||||
|
||||
delete[] request->pass;
|
||||
delete[] request->salt;
|
||||
delete[] request->key;
|
||||
request->callback.Dispose();
|
||||
|
||||
delete request;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
PBKDF2(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
if (args.Length() != 5)
|
||||
return ThrowException(Exception::TypeError(String::New("Bad parameter")));
|
||||
|
||||
ASSERT_IS_STRING_OR_BUFFER(args[0]);
|
||||
ssize_t passlen = DecodeBytes(args[0], BINARY);
|
||||
if (passlen < 0)
|
||||
return ThrowException(Exception::TypeError(String::New("Bad password")));
|
||||
char* pass = new char[passlen];
|
||||
ssize_t pass_written = DecodeWrite(pass, passlen, args[0], BINARY);
|
||||
assert(pass_written == passlen);
|
||||
|
||||
ASSERT_IS_STRING_OR_BUFFER(args[1]);
|
||||
ssize_t saltlen = DecodeBytes(args[1], BINARY);
|
||||
if (saltlen < 0)
|
||||
return ThrowException(Exception::TypeError(String::New("Bad salt")));
|
||||
char* salt = new char[saltlen];
|
||||
ssize_t salt_written = DecodeWrite(salt, saltlen, args[1], BINARY);
|
||||
assert(salt_written == saltlen);
|
||||
|
||||
if (!args[2]->IsNumber())
|
||||
return ThrowException(Exception::TypeError(String::New("Iterations not a number")));
|
||||
ssize_t iter = args[2]->Int32Value();
|
||||
if (iter < 0)
|
||||
return ThrowException(Exception::TypeError(String::New("Bad iterations")));
|
||||
|
||||
if (!args[3]->IsNumber())
|
||||
return ThrowException(Exception::TypeError(String::New("Key length not a number")));
|
||||
ssize_t keylen = args[3]->Int32Value();
|
||||
if (keylen < 0)
|
||||
return ThrowException(Exception::TypeError(String::New("Bad key length")));
|
||||
char* key = new char[keylen];
|
||||
|
||||
if (!args[4]->IsFunction())
|
||||
return ThrowException(Exception::TypeError(String::New("Callback not a function")));
|
||||
Local<Function> callback = Local<Function>::Cast(args[4]);
|
||||
|
||||
pbkdf2_req* 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);
|
||||
|
||||
eio_custom(EIO_PBKDF2, EIO_PRI_DEFAULT, EIO_PBKDF2After, request);
|
||||
ev_ref(EV_DEFAULT_UC);
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
void InitCrypto(Handle<Object> target) {
|
||||
HandleScope scope;
|
||||
@ -3785,6 +3902,8 @@ void InitCrypto(Handle<Object> target) {
|
||||
Sign::Initialize(target);
|
||||
Verify::Initialize(target);
|
||||
|
||||
NODE_SET_METHOD(target, "PBKDF2", PBKDF2);
|
||||
|
||||
subject_symbol = NODE_PSYMBOL("subject");
|
||||
issuer_symbol = NODE_PSYMBOL("issuer");
|
||||
valid_from_symbol = NODE_PSYMBOL("valid_from");
|
||||
|
@ -388,3 +388,25 @@ assert.equal(rsaSignature, '5c50e3145c4e2497aadb0eabc83b342d0b0021ece0d4c4a064b7
|
||||
|
||||
rsaVerify.update(rsaPubPem);
|
||||
assert.equal(rsaVerify.verify(rsaPubPem, rsaSignature, 'hex'), 1);
|
||||
|
||||
// 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');
|
||||
});
|
||||
|
||||
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', 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');
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user