Skip to content

Commit

Permalink
crypto: optimize sign.update() and verify.update()
Browse files Browse the repository at this point in the history
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: #31767
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: David Carlier <devnexen@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
  • Loading branch information
bnoordhuis authored and addaleax committed Mar 11, 2020
1 parent d09e1da commit 3b9a403
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
13 changes: 10 additions & 3 deletions lib/internal/crypto/sig.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
};

Expand Down
34 changes: 30 additions & 4 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4509,12 +4509,25 @@ void Sign::SignInit(const FunctionCallbackInfo<Value>& args) {


void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Sign* sign;
ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder());

Error err;
ArrayBufferViewContents<char> 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<String>(), enc).IsNothing())
return;
err = sign->Update(decoder.out(), decoder.size());
} else {
ArrayBufferViewContents<char> buf(args[0]);
err = sign->Update(buf.data(), buf.length());
}

sign->CheckThrow(err);
}
Expand Down Expand Up @@ -4834,12 +4847,25 @@ void Verify::VerifyInit(const FunctionCallbackInfo<Value>& args) {


void Verify::VerifyUpdate(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Verify* verify;
ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder());

Error err;
ArrayBufferViewContents<char> 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<String>(), enc).IsNothing())
return;
err = verify->Update(decoder.out(), decoder.size());
} else {
ArrayBufferViewContents<char> buf(args[0]);
err = verify->Update(buf.data(), buf.length());
}

verify->CheckThrow(err);
}
Expand Down

0 comments on commit 3b9a403

Please sign in to comment.