In Node.js I can calculate a hash with a help of the crypto
module:
import crypto from "crypto";
const myHash = await crypto.createHash("SHA3-512").update("myText", "utf8").digest("base64");
Since Node.js is based on V8, I assumed that this code should work on any V8-powered browser (Chrome, Edge, Opera, etc.). But it looks like that it's not the case.
According to the Web Crypto API, crypto.subtle.digest
doesn't support SHA3-512
out-of-box, and to get a proper hash-string I need to proceed a digest()
outcome (ArrayBuffer
) manually, e.g.:
const buf = await crypto.subtle.digest("SHA-512", new TextEncoder("utf-8").encode("myText"));
const myHash = Array.prototype.map.call(new Uint8Array(buf), arrItem => (("00" + arrItem.toString(16)).slice(-2))).join("");
Such «API-inconsistency» is quite surprising, are there any alternatives, allowing to bring the Node.js crypto
module API-experience to the V8-powered clients?
The crypto
module is not implemented by V8; it is provided by the respective embedder (Chrome/Node/...). That means there's no technical reason that would force all embedders to provide the same API. (On the bright side, it also means that it's irrelevant whether a client is built on V8 or another JS engine -- all modern browsers support the same Web Crypto API.) I don't know why Node chose to come up with their own API, maybe because it's been around longer than the Web Crypto API?
Looks like Node 15.0 added an implementation of the Web Crypto API: https://nodejs.org/api/webcrypto.html. So you could use that to make your code work on both server and client.
As an alternative, you could write a small shim to abstract over the differences. Or you can look for existing packages that do that; e.g. a quick search turns up https://www.npmjs.com/package/crypto-browserify (no personal experience, so no particular endorsement).
Regardless of approach, in browsers you'll be limited to the algorithms that the Web Crypto API supports, which currently includes SHA-512 but not SHA3-512.