mirror of https://github.com/nodejs/node.git
crypto: make timingSafeEqual faster for Uint8Array
Add a fast API that V8 can use if the user supplies Uint8Arrays (including Buffers) to timingSafeEqual. PR-URL: https://github.com/nodejs/node/pull/52341 Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: Daniel Lemire <daniel@lemire.me> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
9ef724bc81
commit
08609b5222
|
@ -0,0 +1,22 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common.js');
|
||||
const assert = require('node:assert');
|
||||
const { randomBytes, timingSafeEqual } = require('node:crypto');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e5],
|
||||
bufferSize: [10, 100, 200, 2_100, 22_023],
|
||||
});
|
||||
|
||||
function main({ n, bufferSize }) {
|
||||
const bufs = [randomBytes(bufferSize), randomBytes(bufferSize)];
|
||||
bench.start();
|
||||
let count = 0;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const ret = timingSafeEqual(bufs[i % 2], bufs[1]);
|
||||
if (ret) count++;
|
||||
}
|
||||
bench.end(n);
|
||||
assert.strictEqual(count, Math.floor(n / 2));
|
||||
}
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
namespace node {
|
||||
|
||||
using v8::FastApiCallbackOptions;
|
||||
using v8::FastApiTypedArray;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::Local;
|
||||
using v8::Object;
|
||||
|
@ -46,12 +48,32 @@ void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) {
|
|||
CRYPTO_memcmp(buf1.data(), buf2.data(), buf1.size()) == 0);
|
||||
}
|
||||
|
||||
bool FastTimingSafeEqual(Local<Value> receiver,
|
||||
const FastApiTypedArray<uint8_t>& a,
|
||||
const FastApiTypedArray<uint8_t>& b,
|
||||
// NOLINTNEXTLINE(runtime/references)
|
||||
FastApiCallbackOptions& options) {
|
||||
uint8_t* data_a;
|
||||
uint8_t* data_b;
|
||||
if (a.length() != b.length() || !a.getStorageIfAligned(&data_a) ||
|
||||
!b.getStorageIfAligned(&data_b)) {
|
||||
options.fallback = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return CRYPTO_memcmp(data_a, data_b, a.length()) == 0;
|
||||
}
|
||||
|
||||
static v8::CFunction fast_equal(v8::CFunction::Make(FastTimingSafeEqual));
|
||||
|
||||
void Initialize(Environment* env, Local<Object> target) {
|
||||
SetMethodNoSideEffect(
|
||||
env->context(), target, "timingSafeEqual", TimingSafeEqual);
|
||||
SetFastMethodNoSideEffect(
|
||||
env->context(), target, "timingSafeEqual", TimingSafeEqual, &fast_equal);
|
||||
}
|
||||
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
registry->Register(TimingSafeEqual);
|
||||
registry->Register(FastTimingSafeEqual);
|
||||
registry->Register(fast_equal.GetTypeInfo());
|
||||
}
|
||||
} // namespace Timing
|
||||
|
||||
|
|
|
@ -27,6 +27,11 @@ using CFunctionCallbackWithStrings =
|
|||
bool (*)(v8::Local<v8::Value>,
|
||||
const v8::FastOneByteString& input,
|
||||
const v8::FastOneByteString& base);
|
||||
using CFunctionCallbackWithTwoUint8ArraysFallback =
|
||||
bool (*)(v8::Local<v8::Value>,
|
||||
const v8::FastApiTypedArray<uint8_t>&,
|
||||
const v8::FastApiTypedArray<uint8_t>&,
|
||||
v8::FastApiCallbackOptions&);
|
||||
using CFunctionWithUint32 = uint32_t (*)(v8::Local<v8::Value>,
|
||||
const uint32_t input);
|
||||
using CFunctionWithDoubleReturnDouble = double (*)(v8::Local<v8::Value>,
|
||||
|
@ -51,6 +56,7 @@ class ExternalReferenceRegistry {
|
|||
V(CFunctionCallbackWithBool) \
|
||||
V(CFunctionCallbackWithString) \
|
||||
V(CFunctionCallbackWithStrings) \
|
||||
V(CFunctionCallbackWithTwoUint8ArraysFallback) \
|
||||
V(CFunctionWithUint32) \
|
||||
V(CFunctionWithDoubleReturnDouble) \
|
||||
V(CFunctionWithInt64Fallback) \
|
||||
|
|
Loading…
Reference in New Issue