GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — crypto: add Hash.prototype.copy() method · nodejs/node@497b59b

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • doc/api
    • crypto.md
  • lib/internal/crypto
    • hash.js
  • src
    • node_crypto.cc
    • node_crypto.h
  • test/parallel
    • test-crypto-hash.js
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/crypto.md‎

Copy file name to clipboardExpand all lines: doc/api/crypto.md
+37Lines changed: 37 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,43 @@ console.log(hash.digest('hex'));
10411041
// 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
10421042
```
10431043

1044+
### `hash.copy([options])`
1045+
<!-- YAML
1046+
added:
1047+
- version: REPLACEME
1048+
pr-url: https://github.com/nodejs/node/pull/29910
1049+
-->
1050+
1051+
* `options` {Object} [`stream.transform` options][]
1052+
* Returns: {Hash}
1053+
1054+
Creates a new `Hash` object that contains a deep copy of the internal state
1055+
of the current `Hash` object.
1056+
1057+
The optional `options` argument controls stream behavior. For XOF hash
1058+
functions such as `'shake256'`, the `outputLength` option can be used to
1059+
specify the desired output length in bytes.
1060+
1061+
An error is thrown when an attempt is made to copy the `Hash` object after
1062+
its [`hash.digest()`][] method has been called.
1063+
1064+
```js
1065+
// Calculate a rolling hash.
1066+
const crypto = require('crypto');
1067+
const hash = crypto.createHash('sha256');
1068+
1069+
hash.update('one');
1070+
console.log(hash.copy().digest('hex'));
1071+
1072+
hash.update('two');
1073+
console.log(hash.copy().digest('hex'));
1074+
1075+
hash.update('three');
1076+
console.log(hash.copy().digest('hex'));
1077+
1078+
// Etc.
1079+
```
1080+
10441081
### `hash.digest([encoding])`
10451082
<!-- YAML
10461083
added: v0.1.92
Collapse file

‎lib/internal/crypto/hash.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/hash.js
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ const kFinalized = Symbol('kFinalized');
3636
function Hash(algorithm, options) {
3737
if (!(this instanceof Hash))
3838
return new Hash(algorithm, options);
39-
validateString(algorithm, 'algorithm');
39+
if (!(algorithm instanceof _Hash))
40+
validateString(algorithm, 'algorithm');
4041
const xofLen = typeof options === 'object' && options !== null ?
4142
options.outputLength : undefined;
4243
if (xofLen !== undefined)
@@ -51,6 +52,14 @@ function Hash(algorithm, options) {
5152
Object.setPrototypeOf(Hash.prototype, LazyTransform.prototype);
5253
Object.setPrototypeOf(Hash, LazyTransform);
5354

55+
Hash.prototype.copy = function copy(options) {
56+
const state = this[kState];
57+
if (state[kFinalized])
58+
throw new ERR_CRYPTO_HASH_FINALIZED();
59+
60+
return new Hash(this[kHandle], options);
61+
};
62+
5463
Hash.prototype._transform = function _transform(chunk, encoding, callback) {
5564
this[kHandle].update(chunk, encoding);
5665
callback();
Collapse file

‎src/node_crypto.cc‎

Copy file name to clipboardExpand all lines: src/node_crypto.cc
+17-6Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4718,7 +4718,16 @@ void Hash::Initialize(Environment* env, Local<Object> target) {
47184718
void Hash::New(const FunctionCallbackInfo<Value>& args) {
47194719
Environment* env = Environment::GetCurrent(args);
47204720

4721-
const node::Utf8Value hash_type(env->isolate(), args[0]);
4721+
const Hash* orig = nullptr;
4722+
const EVP_MD* md = nullptr;
4723+
4724+
if (args[0]->IsObject()) {
4725+
ASSIGN_OR_RETURN_UNWRAP(&orig, args[0].As<Object>());
4726+
md = EVP_MD_CTX_md(orig->mdctx_.get());
4727+
} else {
4728+
const node::Utf8Value hash_type(env->isolate(), args[0]);
4729+
md = EVP_get_digestbyname(*hash_type);
4730+
}
47224731

47234732
Maybe<unsigned int> xof_md_len = Nothing<unsigned int>();
47244733
if (!args[1]->IsUndefined()) {
@@ -4727,17 +4736,19 @@ void Hash::New(const FunctionCallbackInfo<Value>& args) {
47274736
}
47284737

47294738
Hash* hash = new Hash(env, args.This());
4730-
if (!hash->HashInit(*hash_type, xof_md_len)) {
4739+
if (md == nullptr || !hash->HashInit(md, xof_md_len)) {
47314740
return ThrowCryptoError(env, ERR_get_error(),
47324741
"Digest method not supported");
47334742
}
4743+
4744+
if (orig != nullptr &&
4745+
0 >= EVP_MD_CTX_copy(hash->mdctx_.get(), orig->mdctx_.get())) {
4746+
return ThrowCryptoError(env, ERR_get_error(), "Digest copy error");
4747+
}
47344748
}
47354749

47364750

4737-
bool Hash::HashInit(const char* hash_type, Maybe<unsigned int> xof_md_len) {
4738-
const EVP_MD* md = EVP_get_digestbyname(hash_type);
4739-
if (md == nullptr)
4740-
return false;
4751+
bool Hash::HashInit(const EVP_MD* md, Maybe<unsigned int> xof_md_len) {
47414752
mdctx_.reset(EVP_MD_CTX_new());
47424753
if (!mdctx_ || EVP_DigestInit_ex(mdctx_.get(), md, nullptr) <= 0) {
47434754
mdctx_.reset();
Collapse file

‎src/node_crypto.h‎

Copy file name to clipboardExpand all lines: src/node_crypto.h
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ class Hash : public BaseObject {
591591
SET_MEMORY_INFO_NAME(Hash)
592592
SET_SELF_SIZE(Hash)
593593

594-
bool HashInit(const char* hash_type, v8::Maybe<unsigned int> xof_md_len);
594+
bool HashInit(const EVP_MD* md, v8::Maybe<unsigned int> xof_md_len);
595595
bool HashUpdate(const char* data, int len);
596596

597597
protected:
Collapse file

‎test/parallel/test-crypto-hash.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-crypto-hash.js
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,27 @@ common.expectsError(
192192
assert.strictEqual(crypto.createHash('shake256').digest('hex'),
193193
'46b9dd2b0ba88d13233b3feb743eeb24' +
194194
'3fcd52ea62b81b82b50c27646ed5762f');
195+
assert.strictEqual(crypto.createHash('shake256', { outputLength: 0 })
196+
.copy() // Default outputLength.
197+
.digest('hex'),
198+
'46b9dd2b0ba88d13233b3feb743eeb24' +
199+
'3fcd52ea62b81b82b50c27646ed5762f');
195200

196201
// Short outputLengths.
197202
assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 })
198203
.digest('hex'),
199204
'');
205+
assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 })
206+
.copy({ outputLength: 0 })
207+
.digest('hex'),
208+
'');
200209
assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 })
201210
.digest('hex'),
202211
'7f9c2ba4e8');
212+
assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 })
213+
.copy({ outputLength: 5 })
214+
.digest('hex'),
215+
'7f9c2ba4e8');
203216
assert.strictEqual(crypto.createHash('shake128', { outputLength: 15 })
204217
.digest('hex'),
205218
'7f9c2ba4e88f827d61604550760585');
@@ -249,3 +262,19 @@ common.expectsError(
249262
{ code: 'ERR_OUT_OF_RANGE' });
250263
}
251264
}
265+
266+
{
267+
const h = crypto.createHash('sha512');
268+
h.digest();
269+
common.expectsError(() => h.copy(), { code: 'ERR_CRYPTO_HASH_FINALIZED' });
270+
common.expectsError(() => h.digest(), { code: 'ERR_CRYPTO_HASH_FINALIZED' });
271+
}
272+
273+
{
274+
const a = crypto.createHash('sha512').update('abc');
275+
const b = a.copy();
276+
const c = b.copy().update('def');
277+
const d = crypto.createHash('sha512').update('abcdef');
278+
assert.strictEqual(a.digest('hex'), b.digest('hex'));
279+
assert.strictEqual(c.digest('hex'), d.digest('hex'));
280+
}

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.