Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4634,16 +4634,20 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
}

unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len;

EVP_DigestFinal_ex(hash->mdctx_.get(), md_value, &md_len);
if (hash->md_len_ == 0) {
// Some hash algorithms such as SHA3 do not support calling
// EVP_DigestFinal_ex more than once, however, Hash._flush
// and Hash.digest can both be used to retrieve the digest,
// so we need to cache it.
// See https://github.com/nodejs/node/issues/28245.
EVP_DigestFinal_ex(hash->mdctx_.get(), hash->md_value_, &hash->md_len_);
}

Local<Value> error;
MaybeLocal<Value> rc =
StringBytes::Encode(env->isolate(),
reinterpret_cast<const char*>(md_value),
md_len,
reinterpret_cast<const char*>(hash->md_value_),
hash->md_len_,
encoding,
&error);
if (rc.IsEmpty()) {
Expand Down
9 changes: 8 additions & 1 deletion src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,12 +595,19 @@ class Hash : public BaseObject {

Hash(Environment* env, v8::Local<v8::Object> wrap)
: BaseObject(env, wrap),
mdctx_(nullptr) {
mdctx_(nullptr),
md_len_(0) {
MakeWeak();
}

~Hash() override {
OPENSSL_cleanse(md_value_, md_len_);
}

private:
EVPMDPointer mdctx_;
unsigned char md_value_[EVP_MAX_MD_SIZE];
unsigned int md_len_;
};

class SignBase : public BaseObject {
Expand Down
10 changes: 8 additions & 2 deletions test/parallel/test-crypto-hash-stream-pipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ const crypto = require('crypto');

const stream = require('stream');
const s = new stream.PassThrough();
const h = crypto.createHash('sha1');
const expect = '15987e60950cf22655b9323bc1e281f9c4aff47e';
const h = crypto.createHash('sha3-512');
const expect = '36a38a2a35e698974d4e5791a3f05b05' +
'198235381e864f91a0e8cd6a26b677ec' +
'dcde8e2b069bd7355fabd68abd6fc801' +
'19659f25e92f8efc961ee3a7c815c758';

s.pipe(h).on('data', common.mustCall(function(c) {
assert.strictEqual(c, expect);
// Calling digest() after piping into a stream with SHA3 should not cause
// a segmentation fault, see https://github.com/nodejs/node/issues/28245.
assert.strictEqual(h.digest('hex'), expect);
})).setEncoding('hex');

s.end('aoeu');