Skip to content

Commit

Permalink
Support hash algorithm option.
Browse files Browse the repository at this point in the history
- Add `messageDigestAlgorithm` option to API.
- Add support for SHA-256, SHA-384, and SHA-512 name variations to
  `MessageDigests`.
- Updates tests to handle `hashAlgorithm` option if present.
  • Loading branch information
davidlehn committed Sep 5, 2023
1 parent f52439f commit a39634d
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 10 deletions.
17 changes: 14 additions & 3 deletions lib/MessageDigest-webcrypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@

const {bufferToHex, crypto} = require('./platform');

const algorithmMap = new Map([
['sha256', 'SHA-256'],
['SHA256', 'SHA-256'],
['SHA-256', 'SHA-256'],
['sha384', 'SHA-384'],
['SHA384', 'SHA-384'],
['SHA-384', 'SHA-384'],
['sha512', 'SHA-512'],
['SHA512', 'SHA-512'],
['SHA-512', 'SHA-512'],
]);

module.exports = class MessageDigest {
/**
* Creates a new WebCrypto API MessageDigest.
Expand All @@ -17,11 +29,10 @@ module.exports = class MessageDigest {
if(!(crypto && crypto.subtle)) {
throw new Error('crypto.subtle not found.');
}
if(algorithm === 'sha256') {
this.algorithm = {name: 'SHA-256'};
} else {
if(!algorithmMap.has(algorithm)) {
throw new Error(`Unsupported algorithm "${algorithm}".`);
}
this.algorithm = algorithmMap.get(algorithm);
this._content = '';
}

Expand Down
19 changes: 17 additions & 2 deletions lib/MessageDigest.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
/*
* Copyright (c) 2016-2021 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2016-2023 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

const crypto = require('crypto');

const algorithmMap = new Map([
['sha256', 'sha256'],
['SHA256', 'sha256'],
['SHA-256', 'sha256'],
['sha384', 'sha384'],
['SHA384', 'sha384'],
['SHA-384', 'sha384'],
['sha512', 'sha512'],
['SHA512', 'sha512'],
['SHA-512', 'sha512'],
]);

module.exports = class MessageDigest {
/**
* Creates a new MessageDigest.
*
* @param {string} algorithm - The algorithm to use.
*/
constructor(algorithm) {
this.md = crypto.createHash(algorithm);
if(!algorithmMap.has(algorithm)) {
throw new Error(`Unsupported algorithm "${algorithm}".`);
}
this.md = crypto.createHash(algorithmMap.get(algorithm));
}

update(msg) {
Expand Down
6 changes: 4 additions & 2 deletions lib/URDNA2015.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ const {setImmediate} = require('./platform');

module.exports = class URDNA2015 {
constructor({
createMessageDigest = () => new MessageDigest('sha256'),
createMessageDigest = null,
messageDigestAlgorithm = 'sha256',
canonicalIdMap = new Map(),
maxDeepIterations = Infinity,
signal = AbortSignal.timeout(1000)
} = {}) {
this.name = 'RDFC-1.0';
this.blankNodeInfo = new Map();
this.canonicalIssuer = new IdentifierIssuer('c14n', canonicalIdMap);
this.createMessageDigest = createMessageDigest;
this.createMessageDigest = createMessageDigest ||
(() => new MessageDigest(messageDigestAlgorithm));
this.maxDeepIterations = maxDeepIterations;
this.quads = null;
this.deepIterations = null;
Expand Down
6 changes: 4 additions & 2 deletions lib/URDNA2015Sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ const NQuads = require('./NQuads');

module.exports = class URDNA2015Sync {
constructor({
createMessageDigest = () => new MessageDigest('sha256'),
createMessageDigest = null,
messageDigestAlgorithm = 'sha256',
canonicalIdMap = new Map(),
maxDeepIterations = Infinity,
timeout = 1000
} = {}) {
this.name = 'RDFC-1.0';
this.blankNodeInfo = new Map();
this.canonicalIssuer = new IdentifierIssuer('c14n', canonicalIdMap);
this.createMessageDigest = createMessageDigest;
this.createMessageDigest = createMessageDigest ||
(() => new MessageDigest(messageDigestAlgorithm));
this.maxDeepIterations = maxDeepIterations;
this.timeout = timeout;
this.startTime = Date.now();
Expand Down
8 changes: 8 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ exports._rdfCanonizeNative = function(api) {
* implementation used by the canonize algorithm; note that using a hash
* algorithm (or HMAC algorithm) that differs from the one specified by
* the canonize algorithm will result in different output.
* {string} [messageDigestAlgorithm=sha256] - Message digest algorithm used
* by the default implementation of `createMessageDigest`. Supported
* algorithms are: 'sha256', 'sha384', 'sha512', and the 'SHA###' and
* 'SHA-###' variations.
* {Map} [canonicalIdMap] - An optional Map to be populated by the canonical
* identifier issuer with the bnode identifier mapping generated by the
* canonicalization algorithm.
Expand Down Expand Up @@ -159,6 +163,10 @@ exports.canonize = async function(input, options) {
* implementation used by the canonize algorithm; note that using a hash
* algorithm (or HMAC algorithm) that differs from the one specified by
* the canonize algorithm will result in different output.
* {string} [messageDigestAlgorithm=sha256] - Message digest algorithm used
* by the default implementation of `createMessageDigest`. Supported
* algorithms are: 'sha256', 'sha384', 'sha512', and the 'SHA###' and
* 'SHA-###' variations.
* {Map} [canonicalIdMap] - An optional Map to be populated by the canonical
* identifier issuer with the bnode identifier mapping generated by the
* canonicalization algorithm.
Expand Down
20 changes: 19 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ async function addTest(manifest, test, tests) {
title: description + ` (asynchronous, js, jobs=${jobs})`,
f: makeFn({
test,
adjustParams: params => {
if(test.hashAlgorithm) {
params[1].messageDigestAlgorithm = test.hashAlgorithm;
}
return params;
},
run: ({/*test, testInfo,*/ params}) => {
// skip Promise.all
if(jobs === 1 && fast1) {
Expand Down Expand Up @@ -425,7 +431,7 @@ async function addTest(manifest, test, tests) {
test,
adjustParams: params => {
params[1].createMessageDigest =
() => new WebCryptoMessageDigest('sha256');
() => new WebCryptoMessageDigest(test.hashAlgorithm || 'sha256');
return params;
},
run: ({/*test, testInfo,*/ params}) => {
Expand Down Expand Up @@ -461,6 +467,9 @@ async function addTest(manifest, test, tests) {
f: makeFn({
test,
adjustParams: params => {
if(test.hashAlgorithm) {
params[1].messageDigestAlgorithm = test.hashAlgorithm;
}
params[1].useNative = true;
return params;
},
Expand Down Expand Up @@ -495,6 +504,12 @@ async function addTest(manifest, test, tests) {
title: description + ` (synchronous, js, jobs=${jobs})`,
f: makeFn({
test,
adjustParams: params => {
if(test.hashAlgorithm) {
params[1].messageDigestAlgorithm = test.hashAlgorithm;
}
return params;
},
run: ({/*test, testInfo,*/ params}) => {
// skip Promise.all
if(jobs === 1 && fast1) {
Expand Down Expand Up @@ -529,6 +544,9 @@ async function addTest(manifest, test, tests) {
f: makeFn({
test,
adjustParams: params => {
if(test.hashAlgorithm) {
params[1].messageDigestAlgorithm = test.hashAlgorithm;
}
params[1].useNative = true;
return params;
},
Expand Down

0 comments on commit a39634d

Please sign in to comment.