From ce686c03aedd48cf1ba24c729edb8ca41b51e544 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 13 Feb 2020 12:05:18 +0100 Subject: [PATCH] crypto: optimize sign.update() and verify.update() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `StringBytes::InlineDecoder` to decode strings inputs in C++ land instead of decoding them to buffers in JS land before passing them on to the C++ layer. This is what the other update() methods already did. PR-URL: https://github.com/nodejs/node/pull/31767 Reviewed-By: Santiago Gimeno Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: David Carlier Reviewed-By: Tobias Nießen --- lib/internal/crypto/sig.js | 13 ++++++++++--- src/node_crypto.cc | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 27930ce1acf793..7e3b7aa7ff394d 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -9,7 +9,7 @@ const { ERR_INVALID_ARG_TYPE, ERR_INVALID_OPT_VALUE } = require('internal/errors').codes; -const { validateString } = require('internal/validators'); +const { validateEncoding, validateString } = require('internal/validators'); const { Sign: _Sign, Verify: _Verify, @@ -50,8 +50,15 @@ Sign.prototype._write = function _write(chunk, encoding, callback) { Sign.prototype.update = function update(data, encoding) { encoding = encoding || getDefaultEncoding(); - data = getArrayBufferView(data, 'data', encoding); - this[kHandle].update(data); + + if (typeof data === 'string') { + validateEncoding(data, encoding); + } else if (!isArrayBufferView(data)) { + throw new ERR_INVALID_ARG_TYPE( + 'data', ['string', 'Buffer', 'TypedArray', 'DataView'], data); + } + + this[kHandle].update(data, encoding); return this; }; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 34534662312605..c8d914ebfda1c5 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4509,12 +4509,25 @@ void Sign::SignInit(const FunctionCallbackInfo& args) { void Sign::SignUpdate(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Sign* sign; ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder()); Error err; - ArrayBufferViewContents buf(args[0]); - err = sign->Update(buf.data(), buf.length()); + + // Only copy the data if we have to, because it's a string + if (args[0]->IsString()) { + StringBytes::InlineDecoder decoder; + enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8); + + if (decoder.Decode(env, args[0].As(), enc).IsNothing()) + return; + err = sign->Update(decoder.out(), decoder.size()); + } else { + ArrayBufferViewContents buf(args[0]); + err = sign->Update(buf.data(), buf.length()); + } sign->CheckThrow(err); } @@ -4834,12 +4847,25 @@ void Verify::VerifyInit(const FunctionCallbackInfo& args) { void Verify::VerifyUpdate(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Verify* verify; ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder()); Error err; - ArrayBufferViewContents buf(args[0]); - err = verify->Update(buf.data(), buf.length()); + + // Only copy the data if we have to, because it's a string + if (args[0]->IsString()) { + StringBytes::InlineDecoder decoder; + enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8); + + if (decoder.Decode(env, args[0].As(), enc).IsNothing()) + return; + err = verify->Update(decoder.out(), decoder.size()); + } else { + ArrayBufferViewContents buf(args[0]); + err = verify->Update(buf.data(), buf.length()); + } verify->CheckThrow(err); }