diff --git a/README.md b/README.md
index cc5349f..4102468 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,8 @@ npm install @peculiar/webcrypto
| PBKDF2 | | | X | | | | X |
| DES-CBC2| X | | X | | X | X | |
| DES-EDE3-CBC2| X | | X | | X | X | |
+| shake1282| | X | | | | | |
+| shake2562| | X | | | | | |
1 Mechanism supports extended list of named curves `P-256`, `P-384`, `P-521`, `K-256`,
`brainpoolP160r1`, `brainpoolP160t1`, `brainpoolP192r1`, `brainpoolP192t1`, `brainpoolP224r1`, `brainpoolP224t1`, `brainpoolP256r1`, `brainpoolP256t1`, `brainpoolP320r1`, `brainpoolP320t1`, `brainpoolP384r1`, `brainpoolP384t1`, `brainpoolP512r1`, and `brainpoolP512t1`
diff --git a/src/mechs/index.ts b/src/mechs/index.ts
index dfbd8bf..238ad11 100644
--- a/src/mechs/index.ts
+++ b/src/mechs/index.ts
@@ -7,3 +7,4 @@ export * from "./sha";
export * from "./pbkdf";
export * from "./hmac";
export * from "./hkdf";
+export * from "./shake";
diff --git a/src/mechs/shake/crypto.ts b/src/mechs/shake/crypto.ts
new file mode 100644
index 0000000..35a6ce9
--- /dev/null
+++ b/src/mechs/shake/crypto.ts
@@ -0,0 +1,11 @@
+import crypto from "crypto";
+
+export class ShakeCrypto {
+
+ public static digest(algorithm: Algorithm, data: ArrayBuffer) {
+ const hash = crypto.createHash(algorithm.name.toLowerCase())
+ .update(Buffer.from(data)).digest();
+ return new Uint8Array(hash).buffer;
+ }
+
+}
diff --git a/src/mechs/shake/index.ts b/src/mechs/shake/index.ts
new file mode 100644
index 0000000..897ba0f
--- /dev/null
+++ b/src/mechs/shake/index.ts
@@ -0,0 +1,3 @@
+export * from "./crypto";
+export * from "./shake128";
+export * from "./shake256";
diff --git a/src/mechs/shake/shake128.ts b/src/mechs/shake/shake128.ts
new file mode 100644
index 0000000..f45fffd
--- /dev/null
+++ b/src/mechs/shake/shake128.ts
@@ -0,0 +1,12 @@
+import * as core from "webcrypto-core";
+import { ShakeCrypto } from "./crypto";
+
+export class Shake128Provider extends core.ProviderCrypto {
+ public name = "shake128";
+ public usages = [];
+
+ public async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise {
+ return ShakeCrypto.digest(algorithm, data);
+ }
+
+}
diff --git a/src/mechs/shake/shake256.ts b/src/mechs/shake/shake256.ts
new file mode 100644
index 0000000..e323256
--- /dev/null
+++ b/src/mechs/shake/shake256.ts
@@ -0,0 +1,12 @@
+import * as core from "webcrypto-core";
+import { ShakeCrypto } from "./crypto";
+
+export class Shake256Provider extends core.ProviderCrypto {
+ public name = "shake256";
+ public usages = [];
+
+ public async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise {
+ return ShakeCrypto.digest(algorithm, data);
+ }
+
+}
diff --git a/src/subtle.ts b/src/subtle.ts
index f9f32b3..a4a91f3 100644
--- a/src/subtle.ts
+++ b/src/subtle.ts
@@ -11,6 +11,7 @@ import {
Pbkdf2Provider,
RsaEsProvider, RsaOaepProvider, RsaPssProvider, RsaSsaProvider,
Sha1Provider, Sha256Provider, Sha384Provider, Sha512Provider,
+ Shake128Provider, Shake256Provider,
} from "./mechs";
export class SubtleCrypto extends core.SubtleCrypto {
@@ -63,6 +64,13 @@ export class SubtleCrypto extends core.SubtleCrypto {
//#endregion
const nodeMajorVersion = /^v(\d+)/.exec(process.version)?.[1];
+ if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 12) {
+ //#region SHAKE
+ this.providers.set(new Shake128Provider());
+ this.providers.set(new Shake256Provider());
+ //#endregion
+ }
+
if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 14) {
//#region EdDSA
this.providers.set(new EdDsaProvider());
diff --git a/test/crypto.ts b/test/crypto.ts
index 69cde13..14ea050 100644
--- a/test/crypto.ts
+++ b/test/crypto.ts
@@ -226,4 +226,22 @@ context("Crypto", () => {
assert.strictEqual(hmacKey.algorithm.name, "HMAC");
});
+ context("shake digest", () => {
+
+ const data = Buffer.from("test data");
+
+ it("shake128", async () => {
+ const hash = await crypto.subtle.digest("shake128", data);
+
+ assert.strictEqual(Buffer.from(hash).toString("hex"), "ae3bdcf04986a8e7ddd99ac948254693");
+ });
+
+ it("shake256", async () => {
+ const hash = await crypto.subtle.digest("shake256", data);
+
+ assert.strictEqual(Buffer.from(hash).toString("hex"), "be15253026b9a85e01ae54b1939284e8e514fbdad2a3bd5c1c0f437e60548e26");
+ });
+
+ });
+
});