115 lines
3.8 KiB
C++
115 lines
3.8 KiB
C++
#include "argon2/include/argon2.h"
|
|
|
|
#include <napi.h>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
class HashWorker final : public Napi::AsyncWorker {
|
|
public:
|
|
HashWorker(const Napi::Env &env, const Napi::Buffer<uint8_t> &plain,
|
|
const Napi::Buffer<uint8_t> &salt,
|
|
const Napi::Buffer<uint8_t> &secret,
|
|
const Napi::Buffer<uint8_t> &ad, uint32_t hash_length,
|
|
uint32_t memory_cost, uint32_t time_cost, uint32_t parallelism,
|
|
uint32_t version, uint32_t type)
|
|
: AsyncWorker{env, "argon2:HashWorker"}, deferred{env},
|
|
plain{plain.Data(), plain.ByteLength()},
|
|
salt{salt.Data(), salt.ByteLength()},
|
|
secret{secret.Data(), secret.ByteLength()},
|
|
ad{ad.Data(), ad.ByteLength()}, hash_length{hash_length},
|
|
memory_cost{memory_cost}, time_cost{time_cost},
|
|
parallelism{parallelism}, version{version},
|
|
type{static_cast<argon2_type>(type)} {}
|
|
|
|
auto GetPromise() -> Napi::Promise { return deferred.Promise(); }
|
|
|
|
protected:
|
|
void Execute() override {
|
|
hash.resize(hash_length);
|
|
|
|
argon2_context ctx;
|
|
ctx.out = hash.data();
|
|
ctx.outlen = static_cast<uint32_t>(hash.size());
|
|
ctx.pwd = plain.data();
|
|
ctx.pwdlen = static_cast<uint32_t>(plain.size());
|
|
ctx.salt = salt.data();
|
|
ctx.saltlen = static_cast<uint32_t>(salt.size());
|
|
ctx.secret = secret.empty() ? nullptr : secret.data();
|
|
ctx.secretlen = static_cast<uint32_t>(secret.size());
|
|
ctx.ad = ad.empty() ? nullptr : ad.data();
|
|
ctx.adlen = static_cast<uint32_t>(ad.size());
|
|
ctx.m_cost = memory_cost;
|
|
ctx.t_cost = time_cost;
|
|
ctx.lanes = parallelism;
|
|
ctx.threads = parallelism;
|
|
ctx.allocate_cbk = nullptr;
|
|
ctx.free_cbk = nullptr;
|
|
ctx.flags = ARGON2_FLAG_CLEAR_PASSWORD | ARGON2_FLAG_CLEAR_SECRET;
|
|
ctx.version = version;
|
|
|
|
if (const int result = argon2_ctx(&ctx, type); result != ARGON2_OK) {
|
|
/* LCOV_EXCL_START */
|
|
SetError(argon2_error_message(result));
|
|
/* LCOV_EXCL_STOP */
|
|
}
|
|
}
|
|
|
|
void OnOK() override {
|
|
deferred.Resolve(
|
|
Napi::Buffer<uint8_t>::Copy(Env(), hash.data(), hash.size()));
|
|
}
|
|
|
|
void OnError(const Napi::Error &err) override {
|
|
deferred.Reject(err.Value());
|
|
}
|
|
|
|
private:
|
|
using ustring = std::basic_string<uint8_t>;
|
|
|
|
Napi::Promise::Deferred deferred;
|
|
ustring hash = {};
|
|
|
|
ustring plain;
|
|
ustring salt;
|
|
ustring secret;
|
|
ustring ad;
|
|
|
|
uint32_t hash_length;
|
|
uint32_t memory_cost;
|
|
uint32_t time_cost;
|
|
uint32_t parallelism;
|
|
uint32_t version;
|
|
|
|
argon2_type type;
|
|
};
|
|
|
|
auto Hash(const Napi::CallbackInfo &info) -> Napi::Value {
|
|
NAPI_CHECK(info.Length() == 1, "Hash", "expected 1 argument");
|
|
|
|
const auto &args = info[0].As<Napi::Object>();
|
|
auto *worker = new HashWorker{info.Env(),
|
|
args["password"].As<Napi::Buffer<uint8_t>>(),
|
|
args["salt"].As<Napi::Buffer<uint8_t>>(),
|
|
args["secret"].As<Napi::Buffer<uint8_t>>(),
|
|
args["data"].As<Napi::Buffer<uint8_t>>(),
|
|
args["hashLength"].ToNumber(),
|
|
args["m"].ToNumber(),
|
|
args["t"].ToNumber(),
|
|
args["p"].ToNumber(),
|
|
args["version"].ToNumber(),
|
|
args["type"].ToNumber()};
|
|
|
|
worker->Queue();
|
|
return worker->GetPromise();
|
|
}
|
|
|
|
auto init(Napi::Env env, Napi::Object exports) -> Napi::Object {
|
|
exports["hash"] = Napi::Function::New(env, Hash);
|
|
return exports;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
NODE_API_MODULE(argon2_lib, init)
|