diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2018-05-18 11:05:20 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2018-06-13 15:58:56 +0200 |
commit | c188cc5338cf56d6d30590800bf1db6362a9abc6 (patch) | |
tree | abf90028489ec128bb4b7d89746265a41e9e3c5e /src | |
parent | 371103dae8b97264471e17de1989199ffcd2718e (diff) | |
download | android-node-v8-c188cc5338cf56d6d30590800bf1db6362a9abc6.tar.gz android-node-v8-c188cc5338cf56d6d30590800bf1db6362a9abc6.tar.bz2 android-node-v8-c188cc5338cf56d6d30590800bf1db6362a9abc6.zip |
crypto: refactor pbkdf2() and pbkdf2Sync() methods
Use the scrypt() infrastructure to reimplement pbkdf2() in a simpler
manner.
PR-URL: https://github.com/nodejs/node/pull/20816
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Diffstat (limited to 'src')
-rw-r--r-- | src/env.h | 2 | ||||
-rw-r--r-- | src/node_crypto.cc | 216 |
2 files changed, 71 insertions, 147 deletions
@@ -244,7 +244,6 @@ struct PackageConfig { V(password_string, "password") \ V(path_string, "path") \ V(pending_handle_string, "pendingHandle") \ - V(pbkdf2_error_string, "PBKDF2 Error") \ V(pid_string, "pid") \ V(pipe_string, "pipe") \ V(pipe_target_string, "pipeTarget") \ @@ -337,7 +336,6 @@ struct PackageConfig { V(inspector_console_api_object, v8::Object) \ V(message_port, v8::Object) \ V(message_port_constructor_template, v8::FunctionTemplate) \ - V(pbkdf2_constructor_template, v8::ObjectTemplate) \ V(pipe_constructor_template, v8::FunctionTemplate) \ V(performance_entry_callback, v8::Function) \ V(performance_entry_template, v8::Function) \ diff --git a/src/node_crypto.cc b/src/node_crypto.cc index cf7e7f0ee0..5287865790 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -64,7 +64,6 @@ namespace crypto { using v8::Array; using v8::Boolean; using v8::Context; -using v8::DEFAULT; using v8::DontDelete; using v8::EscapableHandleScope; using v8::Exception; @@ -75,10 +74,12 @@ using v8::HandleScope; using v8::Int32; using v8::Integer; using v8::Isolate; +using v8::Just; using v8::Local; using v8::Maybe; using v8::MaybeLocal; using v8::NewStringType; +using v8::Nothing; using v8::Null; using v8::Object; using v8::ObjectTemplate; @@ -4585,142 +4586,6 @@ inline void CopyBuffer(Local<Value> buf, std::vector<char>* vec) { } -class PBKDF2Request : public AsyncWrap, public ThreadPoolWork { - public: - PBKDF2Request(Environment* env, - Local<Object> object, - const EVP_MD* digest, - MallocedBuffer<char>&& pass, - MallocedBuffer<char>&& salt, - int keylen, - int iteration_count) - : AsyncWrap(env, object, AsyncWrap::PROVIDER_PBKDF2REQUEST), - ThreadPoolWork(env), - digest_(digest), - success_(false), - pass_(std::move(pass)), - salt_(std::move(salt)), - key_(keylen), - iteration_count_(iteration_count) { - } - - size_t self_size() const override { return sizeof(*this); } - - void DoThreadPoolWork() override; - void AfterThreadPoolWork(int status) override; - - void After(Local<Value> (*argv)[2]); - - private: - const EVP_MD* digest_; - bool success_; - MallocedBuffer<char> pass_; - MallocedBuffer<char> salt_; - MallocedBuffer<char> key_; - int iteration_count_; -}; - - -void PBKDF2Request::DoThreadPoolWork() { - success_ = - PKCS5_PBKDF2_HMAC( - pass_.data, pass_.size, - reinterpret_cast<unsigned char*>(salt_.data), salt_.size, - iteration_count_, digest_, - key_.size, - reinterpret_cast<unsigned char*>(key_.data)); - OPENSSL_cleanse(pass_.data, pass_.size); - OPENSSL_cleanse(salt_.data, salt_.size); -} - - -void PBKDF2Request::After(Local<Value> (*argv)[2]) { - if (success_) { - (*argv)[0] = Null(env()->isolate()); - (*argv)[1] = Buffer::New(env(), key_.release(), key_.size) - .ToLocalChecked(); - } else { - (*argv)[0] = Exception::Error(env()->pbkdf2_error_string()); - (*argv)[1] = Undefined(env()->isolate()); - } -} - - -void PBKDF2Request::AfterThreadPoolWork(int status) { - std::unique_ptr<PBKDF2Request> req(this); - if (status == UV_ECANCELED) - return; - CHECK_EQ(status, 0); - - HandleScope handle_scope(env()->isolate()); - Context::Scope context_scope(env()->context()); - Local<Value> argv[2]; - After(&argv); - MakeCallback(env()->ondone_string(), arraysize(argv), argv); -} - - -void PBKDF2(const FunctionCallbackInfo<Value>& args) { - Environment* env = Environment::GetCurrent(args); - - const EVP_MD* digest = nullptr; - int keylen = -1; - int iteration_count = -1; - Local<Object> obj; - - int passlen = Buffer::Length(args[0]); - - MallocedBuffer<char> pass(passlen); - memcpy(pass.data, Buffer::Data(args[0]), passlen); - - int saltlen = Buffer::Length(args[1]); - - MallocedBuffer<char> salt(saltlen); - memcpy(salt.data, Buffer::Data(args[1]), saltlen); - - iteration_count = args[2]->Int32Value(env->context()).FromJust(); - keylen = args[3]->IntegerValue(env->context()).FromJust(); - - if (args[4]->IsString()) { - node::Utf8Value digest_name(env->isolate(), args[4]); - digest = EVP_get_digestbyname(*digest_name); - if (digest == nullptr) { - args.GetReturnValue().Set(-1); - return; - } - } - - if (digest == nullptr) { - digest = EVP_sha1(); - } - - obj = env->pbkdf2_constructor_template()-> - NewInstance(env->context()).ToLocalChecked(); - std::unique_ptr<PBKDF2Request> req( - new PBKDF2Request(env, obj, digest, - std::move(pass), - std::move(salt), - keylen, - iteration_count)); - - if (args[5]->IsFunction()) { - obj->Set(env->context(), env->ondone_string(), args[5]).FromJust(); - - req.release()->ScheduleWork(); - } else { - env->PrintSyncTrace(); - req->DoThreadPoolWork(); - Local<Value> argv[2]; - req->After(&argv); - - if (argv[0]->IsObject()) - env->isolate()->ThrowException(argv[0]); - else - args.GetReturnValue().Set(argv[1]); - } -} - - // Only instantiate within a valid HandleScope. class RandomBytesRequest : public AsyncWrap, public ThreadPoolWork { public: @@ -4926,6 +4791,74 @@ void RandomBytesBuffer(const FunctionCallbackInfo<Value>& args) { } +struct PBKDF2Job : public CryptoJob { + unsigned char* keybuf_data; + size_t keybuf_size; + std::vector<char> pass; + std::vector<char> salt; + uint32_t iteration_count; + const EVP_MD* digest; + Maybe<bool> success; + + inline explicit PBKDF2Job(Environment* env) + : CryptoJob(env), success(Nothing<bool>()) {} + + inline ~PBKDF2Job() override { + Cleanse(); + } + + inline void DoThreadPoolWork() override { + auto salt_data = reinterpret_cast<const unsigned char*>(salt.data()); + const bool ok = + PKCS5_PBKDF2_HMAC(pass.data(), pass.size(), salt_data, salt.size(), + iteration_count, digest, keybuf_size, keybuf_data); + success = Just(ok); + Cleanse(); + } + + inline void AfterThreadPoolWork() override { + Local<Value> arg = ToResult(); + async_wrap->MakeCallback(env->ondone_string(), 1, &arg); + } + + inline Local<Value> ToResult() const { + return Boolean::New(env->isolate(), success.FromJust()); + } + + inline void Cleanse() { + OPENSSL_cleanse(pass.data(), pass.size()); + OPENSSL_cleanse(salt.data(), salt.size()); + pass.clear(); + salt.clear(); + } +}; + + +inline void PBKDF2(const FunctionCallbackInfo<Value>& args) { + auto rv = args.GetReturnValue(); + Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsArrayBufferView()); // keybuf; wrap object retains ref. + CHECK(args[1]->IsArrayBufferView()); // pass + CHECK(args[2]->IsArrayBufferView()); // salt + CHECK(args[3]->IsUint32()); // iteration_count + CHECK(args[4]->IsString()); // digest_name + CHECK(args[5]->IsObject() || args[5]->IsUndefined()); // wrap object + std::unique_ptr<PBKDF2Job> job(new PBKDF2Job(env)); + job->keybuf_data = reinterpret_cast<unsigned char*>(Buffer::Data(args[0])); + job->keybuf_size = Buffer::Length(args[0]); + CopyBuffer(args[1], &job->pass); + CopyBuffer(args[2], &job->salt); + job->iteration_count = args[3].As<Uint32>()->Value(); + Utf8Value digest_name(args.GetIsolate(), args[4]); + job->digest = EVP_get_digestbyname(*digest_name); + if (job->digest == nullptr) return rv.Set(-1); + if (args[5]->IsObject()) return PBKDF2Job::Run(std::move(job), args[5]); + env->PrintSyncTrace(); + job->DoThreadPoolWork(); + rv.Set(job->ToResult()); +} + + #ifndef OPENSSL_NO_SCRYPT struct ScryptJob : public CryptoJob { unsigned char* keybuf_data; @@ -5417,7 +5350,7 @@ void Initialize(Local<Object> target, env->SetMethod(target, "setFipsCrypto", SetFipsCrypto); #endif - env->SetMethod(target, "PBKDF2", PBKDF2); + env->SetMethod(target, "pbkdf2", PBKDF2); env->SetMethod(target, "randomBytes", RandomBytes); env->SetMethod(target, "randomFill", RandomBytesBuffer); env->SetMethod(target, "timingSafeEqual", TimingSafeEqual); @@ -5445,13 +5378,6 @@ void Initialize(Local<Object> target, env->SetMethod(target, "scrypt", Scrypt); #endif // OPENSSL_NO_SCRYPT - Local<FunctionTemplate> pb = FunctionTemplate::New(env->isolate()); - pb->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PBKDF2")); - AsyncWrap::AddWrapMethods(env, pb); - Local<ObjectTemplate> pbt = pb->InstanceTemplate(); - pbt->SetInternalFieldCount(1); - env->set_pbkdf2_constructor_template(pbt); - Local<FunctionTemplate> rb = FunctionTemplate::New(env->isolate()); rb->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "RandomBytes")); AsyncWrap::AddWrapMethods(env, rb); |