Skip to content

Commit 2e01641

Browse files
committed
src: move more crypto to ncrypto
1 parent 6ee806e commit 2e01641

File tree

7 files changed

+192
-73
lines changed

7 files changed

+192
-73
lines changed

deps/ncrypto/ncrypto.cc

+81
Original file line numberDiff line numberDiff line change
@@ -3735,4 +3735,85 @@ bool extractP1363(const Buffer<const unsigned char>& buf,
37353735
BignumPointer::EncodePaddedInto(asn1_sig.s(), dest + n, n) > 0;
37363736
}
37373737

3738+
// ============================================================================
3739+
3740+
HMACCtxPointer::HMACCtxPointer() : ctx_(nullptr) {}
3741+
3742+
HMACCtxPointer::HMACCtxPointer(HMAC_CTX* ctx) : ctx_(ctx) {}
3743+
3744+
HMACCtxPointer::HMACCtxPointer(HMACCtxPointer&& other) noexcept
3745+
: ctx_(other.release()) {}
3746+
3747+
HMACCtxPointer& HMACCtxPointer::operator=(HMACCtxPointer&& other) noexcept {
3748+
ctx_.reset(other.release());
3749+
return *this;
3750+
}
3751+
3752+
HMACCtxPointer::~HMACCtxPointer() {
3753+
reset();
3754+
}
3755+
3756+
void HMACCtxPointer::reset(HMAC_CTX* ctx) {
3757+
ctx_.reset(ctx);
3758+
}
3759+
3760+
HMAC_CTX* HMACCtxPointer::release() {
3761+
return ctx_.release();
3762+
}
3763+
3764+
bool HMACCtxPointer::init(const Buffer<const void>& buf, const EVP_MD* md) {
3765+
if (!ctx_) return false;
3766+
return HMAC_Init_ex(ctx_.get(), buf.data, buf.len, md, nullptr) == 1;
3767+
}
3768+
3769+
bool HMACCtxPointer::update(const Buffer<const void>& buf) {
3770+
if (!ctx_) return false;
3771+
return HMAC_Update(ctx_.get(),
3772+
static_cast<const unsigned char*>(buf.data),
3773+
buf.len) == 1;
3774+
}
3775+
3776+
DataPointer HMACCtxPointer::digest() {
3777+
auto data = DataPointer::Alloc(EVP_MAX_MD_SIZE);
3778+
if (!data) return {};
3779+
Buffer<void> buf = data;
3780+
if (!digestInto(&buf)) return {};
3781+
return data.resize(buf.len);
3782+
}
3783+
3784+
bool HMACCtxPointer::digestInto(Buffer<void>* buf) {
3785+
if (!ctx_) return false;
3786+
3787+
unsigned int len = buf->len;
3788+
if (!HMAC_Final(ctx_.get(), static_cast<unsigned char*>(buf->data), &len)) {
3789+
return false;
3790+
}
3791+
buf->len = len;
3792+
return true;
3793+
}
3794+
3795+
HMACCtxPointer HMACCtxPointer::New() {
3796+
return HMACCtxPointer(HMAC_CTX_new());
3797+
}
3798+
3799+
DataPointer hashDigest(const Buffer<const unsigned char>& buf,
3800+
const EVP_MD* md) {
3801+
if (md == nullptr) return {};
3802+
size_t md_len = EVP_MD_size(md);
3803+
unsigned int result_size;
3804+
auto data = DataPointer::Alloc(md_len);
3805+
if (!data) return {};
3806+
3807+
if (!EVP_Digest(buf.data,
3808+
buf.len,
3809+
reinterpret_cast<unsigned char*>(data.get()),
3810+
&result_size,
3811+
md,
3812+
nullptr)) {
3813+
return {};
3814+
}
3815+
3816+
return data.resize(result_size);
3817+
}
3818+
37383819
} // namespace ncrypto

deps/ncrypto/ncrypto.h

+30-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ struct FunctionDeleter {
201201
template <typename T, void (*function)(T*)>
202202
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
203203

204-
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
205204
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
206205
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
207206
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
@@ -239,6 +238,9 @@ struct Buffer {
239238
size_t len = 0;
240239
};
241240

241+
DataPointer hashDigest(const Buffer<const unsigned char>& data,
242+
const EVP_MD* md);
243+
242244
class Cipher final {
243245
public:
244246
Cipher() = default;
@@ -1185,6 +1187,33 @@ class EVPMDCtxPointer final {
11851187
DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free> ctx_;
11861188
};
11871189

1190+
class HMACCtxPointer final {
1191+
public:
1192+
HMACCtxPointer();
1193+
explicit HMACCtxPointer(HMAC_CTX* ctx);
1194+
HMACCtxPointer(HMACCtxPointer&& other) noexcept;
1195+
HMACCtxPointer& operator=(HMACCtxPointer&& other) noexcept;
1196+
NCRYPTO_DISALLOW_COPY(HMACCtxPointer)
1197+
~HMACCtxPointer();
1198+
1199+
inline bool operator==(std::nullptr_t) noexcept { return ctx_ == nullptr; }
1200+
inline operator bool() const { return ctx_ != nullptr; }
1201+
inline HMAC_CTX* get() const { return ctx_.get(); }
1202+
inline operator HMAC_CTX*() const { return ctx_.get(); }
1203+
void reset(HMAC_CTX* ctx = nullptr);
1204+
HMAC_CTX* release();
1205+
1206+
bool init(const Buffer<const void>& buf, const EVP_MD* md);
1207+
bool update(const Buffer<const void>& buf);
1208+
DataPointer digest();
1209+
bool digestInto(Buffer<void>* buf);
1210+
1211+
static HMACCtxPointer New();
1212+
1213+
private:
1214+
DeleteFnPtr<HMAC_CTX, HMAC_CTX_free> ctx_;
1215+
};
1216+
11881217
#ifndef OPENSSL_NO_ENGINE
11891218
class EnginePointer final {
11901219
public:

src/crypto/crypto_hash.cc

+36-39
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace node {
1313

14+
using ncrypto::DataPointer;
1415
using ncrypto::EVPMDCtxPointer;
1516
using ncrypto::MarkPopErrorOnReturn;
1617
using v8::Context;
@@ -220,7 +221,7 @@ void Hash::OneShotDigest(const FunctionCallbackInfo<Value>& args) {
220221
CHECK(args[5]->IsUint32() || args[5]->IsUndefined()); // outputEncodingId
221222

222223
const EVP_MD* md = GetDigestImplementation(env, args[0], args[1], args[2]);
223-
if (md == nullptr) {
224+
if (md == nullptr) [[unlikely]] {
224225
Utf8Value method(isolate, args[0]);
225226
std::string message =
226227
"Digest method " + method.ToString() + " is not supported";
@@ -229,41 +230,36 @@ void Hash::OneShotDigest(const FunctionCallbackInfo<Value>& args) {
229230

230231
enum encoding output_enc = ParseEncoding(isolate, args[4], args[5], HEX);
231232

232-
int md_len = EVP_MD_size(md);
233-
unsigned int result_size;
234-
ByteSource::Builder output(md_len);
235-
int success;
236-
// On smaller inputs, EVP_Digest() can be slower than the
237-
// deprecated helpers e.g SHA256_XXX. The speedup may not
238-
// be worth using deprecated APIs, however, so we use
239-
// EVP_Digest(), unless there's a better alternative
240-
// in the future.
241-
// https://github.com/openssl/openssl/issues/19612
242-
if (args[3]->IsString()) {
243-
Utf8Value utf8(isolate, args[3]);
244-
success = EVP_Digest(utf8.out(),
245-
utf8.length(),
246-
output.data<unsigned char>(),
247-
&result_size,
248-
md,
249-
nullptr);
250-
} else {
233+
DataPointer output = ([&] {
234+
if (args[3]->IsString()) {
235+
Utf8Value utf8(isolate, args[3]);
236+
ncrypto::Buffer<const unsigned char> buf{
237+
.data = reinterpret_cast<const unsigned char*>(utf8.out()),
238+
.len = utf8.length(),
239+
};
240+
return ncrypto::hashDigest(buf, md);
241+
}
242+
251243
ArrayBufferViewContents<unsigned char> input(args[3]);
252-
success = EVP_Digest(input.data(),
253-
input.length(),
254-
output.data<unsigned char>(),
255-
&result_size,
256-
md,
257-
nullptr);
258-
}
259-
if (!success) {
244+
ncrypto::Buffer<const unsigned char> buf{
245+
.data = reinterpret_cast<const unsigned char*>(input.data()),
246+
.len = input.length(),
247+
};
248+
return ncrypto::hashDigest(buf, md);
249+
})();
250+
251+
if (!output) [[unlikely]] {
260252
return ThrowCryptoError(env, ERR_get_error());
261253
}
262254

263255
Local<Value> error;
264-
MaybeLocal<Value> rc = StringBytes::Encode(
265-
env->isolate(), output.data<char>(), md_len, output_enc, &error);
266-
if (rc.IsEmpty()) {
256+
MaybeLocal<Value> rc =
257+
StringBytes::Encode(env->isolate(),
258+
static_cast<const char*>(output.get()),
259+
output.size(),
260+
output_enc,
261+
&error);
262+
if (rc.IsEmpty()) [[unlikely]] {
267263
CHECK(!error.IsEmpty());
268264
env->isolate()->ThrowException(error);
269265
return;
@@ -339,7 +335,7 @@ void Hash::New(const FunctionCallbackInfo<Value>& args) {
339335

340336
bool Hash::HashInit(const EVP_MD* md, Maybe<unsigned int> xof_md_len) {
341337
mdctx_ = EVPMDCtxPointer::New();
342-
if (!mdctx_.digestInit(md)) {
338+
if (!mdctx_.digestInit(md)) [[unlikely]] {
343339
mdctx_.reset();
344340
return false;
345341
}
@@ -348,7 +344,7 @@ bool Hash::HashInit(const EVP_MD* md, Maybe<unsigned int> xof_md_len) {
348344
if (xof_md_len.IsJust() && xof_md_len.FromJust() != md_len_) {
349345
// This is a little hack to cause createHash to fail when an incorrect
350346
// hashSize option was passed for a non-XOF hash function.
351-
if (!mdctx_.hasXofFlag()) {
347+
if (!mdctx_.hasXofFlag()) [[unlikely]] {
352348
EVPerr(EVP_F_EVP_DIGESTFINALXOF, EVP_R_NOT_XOF_OR_INVALID_LENGTH);
353349
mdctx_.reset();
354350
return false;
@@ -406,7 +402,7 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
406402
// so we need to cache it.
407403
// See https://github.com/nodejs/node/issues/28245.
408404
auto data = hash->mdctx_.digestFinal(len);
409-
if (!data) {
405+
if (!data) [[unlikely]] {
410406
return ThrowCryptoError(env, ERR_get_error());
411407
}
412408

@@ -416,7 +412,7 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
416412
Local<Value> error;
417413
MaybeLocal<Value> rc = StringBytes::Encode(
418414
env->isolate(), hash->digest_.data<char>(), len, encoding, &error);
419-
if (rc.IsEmpty()) {
415+
if (rc.IsEmpty()) [[unlikely]] {
420416
CHECK(!error.IsEmpty());
421417
env->isolate()->ThrowException(error);
422418
return;
@@ -482,7 +478,7 @@ Maybe<void> HashTraits::AdditionalConfig(
482478
static_cast<uint32_t>(args[offset + 2]
483479
.As<Uint32>()->Value()) / CHAR_BIT;
484480
if (params->length != expected) {
485-
if ((EVP_MD_flags(params->digest) & EVP_MD_FLAG_XOF) == 0) {
481+
if ((EVP_MD_flags(params->digest) & EVP_MD_FLAG_XOF) == 0) [[unlikely]] {
486482
THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Digest method not supported");
487483
return Nothing<void>();
488484
}
@@ -505,7 +501,8 @@ bool HashTraits::DeriveBits(
505501

506502
if (params.length > 0) [[likely]] {
507503
auto data = ctx.digestFinal(params.length);
508-
if (!data) return false;
504+
if (!data) [[unlikely]]
505+
return false;
509506

510507
*out = ByteSource::Allocated(data.release());
511508
}
@@ -535,7 +532,7 @@ void InternalVerifyIntegrity(const v8::FunctionCallbackInfo<v8::Value>& args) {
535532
digest,
536533
&digest_size,
537534
md_type,
538-
nullptr) != 1) {
535+
nullptr) != 1) [[unlikely]] {
539536
return ThrowCryptoError(
540537
env, ERR_get_error(), "Digest method not supported");
541538
}
@@ -549,7 +546,7 @@ void InternalVerifyIntegrity(const v8::FunctionCallbackInfo<v8::Value>& args) {
549546
digest_size,
550547
BASE64,
551548
&error);
552-
if (rc.IsEmpty()) {
549+
if (rc.IsEmpty()) [[unlikely]] {
553550
CHECK(!error.IsEmpty());
554551
env->isolate()->ThrowException(error);
555552
return;

src/crypto/crypto_hkdf.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Maybe<void> HKDFTraits::AdditionalConfig(
5555

5656
Utf8Value hash(env->isolate(), args[offset]);
5757
params->digest = ncrypto::getDigestByName(hash.ToStringView());
58-
if (params->digest == nullptr) {
58+
if (params->digest == nullptr) [[unlikely]] {
5959
THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *hash);
6060
return Nothing<void>();
6161
}
@@ -88,7 +88,7 @@ Maybe<void> HKDFTraits::AdditionalConfig(
8888
// HKDF-Expand computes up to 255 HMAC blocks, each having as many bits as the
8989
// output of the hash function. 255 is a hard limit because HKDF appends an
9090
// 8-bit counter to each HMAC'd message, starting at 1.
91-
if (!ncrypto::checkHkdfLength(params->digest, params->length)) {
91+
if (!ncrypto::checkHkdfLength(params->digest, params->length)) [[unlikely]] {
9292
THROW_ERR_CRYPTO_INVALID_KEYLEN(env);
9393
return Nothing<void>();
9494
}

0 commit comments

Comments
 (0)