feat: implement SHA3 256/384/512
This commit is contained in:
parent
75d4f9a453
commit
8b1347df43
|
@ -4,6 +4,7 @@ import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
|||
import {BufferSourceConverter} from "pvtsutils";
|
||||
import * as core from "webcrypto-core";
|
||||
import { CryptoKey } from "../../keys";
|
||||
import { ShaCrypto } from "../sha";
|
||||
import { getOidByNamedCurve } from "./helper";
|
||||
import { EcPrivateKey } from "./private_key";
|
||||
import { EcPublicKey } from "./public_key";
|
||||
|
@ -48,7 +49,7 @@ export class EcCrypto {
|
|||
}
|
||||
|
||||
public static async sign(algorithm: EcdsaParams, key: EcPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
const cryptoAlg = (algorithm.hash as Algorithm).name.replace("-", "");
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm);
|
||||
const signer = crypto.createSign(cryptoAlg);
|
||||
signer.update(Buffer.from(data));
|
||||
|
||||
|
@ -68,7 +69,7 @@ export class EcCrypto {
|
|||
}
|
||||
|
||||
public static async verify(algorithm: EcdsaParams, key: EcPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
|
||||
const cryptoAlg = (algorithm.hash as Algorithm).name.replace("-", "");
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm);
|
||||
const signer = crypto.createVerify(cryptoAlg);
|
||||
signer.update(Buffer.from(data));
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@ export class EcdsaProvider extends core.EcdsaProvider {
|
|||
|
||||
public override namedCurves = core.EcCurves.names;
|
||||
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
"shake128", "shake256",
|
||||
"SHA3-256", "SHA3-384", "SHA3-512"];
|
||||
|
||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await EcCrypto.generateKey(
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import crypto from "crypto";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
import { ShaCrypto } from "../sha";
|
||||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
import { HmacCryptoKey } from "./key";
|
||||
|
||||
|
@ -22,16 +23,16 @@ export class HmacProvider extends core.HmacProvider {
|
|||
}
|
||||
|
||||
public override async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const hash = key.algorithm.hash.name.replace("-", "");
|
||||
const hmac = crypto.createHmac(hash, getCryptoKey(key).data)
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash);
|
||||
const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data)
|
||||
.update(Buffer.from(data)).digest();
|
||||
|
||||
return new Uint8Array(hmac).buffer;
|
||||
}
|
||||
|
||||
public override async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
const hash = key.algorithm.hash.name.replace("-", "");
|
||||
const hmac = crypto.createHmac(hash, getCryptoKey(key).data)
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash);
|
||||
const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data)
|
||||
.update(Buffer.from(data)).digest();
|
||||
|
||||
return hmac.compare(Buffer.from(signature)) === 0;
|
||||
|
|
|
@ -181,6 +181,12 @@ export class RsaCrypto {
|
|||
return "RSA-SHA384";
|
||||
case "SHA-512":
|
||||
return "RSA-SHA512";
|
||||
case "SHA3-256":
|
||||
return "RSA-SHA3-256";
|
||||
case "SHA3-384":
|
||||
return "RSA-SHA3-384";
|
||||
case "SHA3-512":
|
||||
return "RSA-SHA3-512";
|
||||
default:
|
||||
throw new core.OperationError("algorithm.hash: Is not recognized");
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ import { RsaPublicKey } from "./public_key";
|
|||
|
||||
export class RsaPssProvider extends core.RsaPssProvider {
|
||||
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
"shake128", "shake256",
|
||||
"SHA3-256", "SHA3-384", "SHA3-512"];
|
||||
|
||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await RsaCrypto.generateKey(
|
||||
{
|
||||
|
|
|
@ -6,6 +6,11 @@ import { RsaPublicKey } from "./public_key";
|
|||
|
||||
export class RsaSsaProvider extends core.RsaSsaProvider {
|
||||
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
"shake128", "shake256",
|
||||
"SHA3-256", "SHA3-384", "SHA3-512"];
|
||||
|
||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<globalThis.CryptoKeyPair> {
|
||||
const keys = await RsaCrypto.generateKey(
|
||||
{
|
||||
|
|
|
@ -12,18 +12,48 @@ export class ShaCrypto {
|
|||
case "SHA-1":
|
||||
return 160;
|
||||
case "SHA-256":
|
||||
case "SHA3-256":
|
||||
return 256;
|
||||
case "SHA-384":
|
||||
case "SHA3-384":
|
||||
return 384;
|
||||
case "SHA-512":
|
||||
case "SHA3-512":
|
||||
return 512;
|
||||
default:
|
||||
throw new Error("Unrecognized name");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns NodeJS Crypto algorithm name from WebCrypto algorithm
|
||||
* @param algorithm WebCRypto algorithm
|
||||
* @throws Throws Error if an unrecognized name
|
||||
*/
|
||||
public static getAlgorithmName(algorithm: Algorithm): string {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "SHA-1":
|
||||
return "sha1";
|
||||
case "SHA-256":
|
||||
return "sha256";
|
||||
case "SHA-384":
|
||||
return "sha384";
|
||||
case "SHA-512":
|
||||
return "sha512";
|
||||
case "SHA3-256":
|
||||
return "sha3-256";
|
||||
case "SHA3-384":
|
||||
return "sha3-384";
|
||||
case "SHA3-512":
|
||||
return "sha3-512";
|
||||
default:
|
||||
throw new Error("Unrecognized name");
|
||||
}
|
||||
}
|
||||
|
||||
public static digest(algorithm: Algorithm, data: ArrayBuffer) {
|
||||
const hash = crypto.createHash(algorithm.name.replace("-", ""))
|
||||
const hashAlg = this.getAlgorithmName(algorithm);
|
||||
const hash = crypto.createHash(hashAlg)
|
||||
.update(Buffer.from(data)).digest();
|
||||
return new Uint8Array(hash).buffer;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
export * from "./crypto";
|
||||
export * from "./sha_1";
|
||||
export * from "./sha_256";
|
||||
export * from "./sha_384";
|
||||
export * from "./sha_512";
|
||||
export * from "./sha3_256";
|
||||
export * from "./sha3_384";
|
||||
export * from "./sha3_512";
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import * as core from "webcrypto-core";
|
||||
import { ShaCrypto } from "./crypto";
|
||||
|
||||
export class Sha3256Provider extends core.ProviderCrypto {
|
||||
public name = "SHA3-256";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import * as core from "webcrypto-core";
|
||||
import { ShaCrypto } from "./crypto";
|
||||
|
||||
export class Sha3384Provider extends core.ProviderCrypto {
|
||||
public name = "SHA3-384";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import * as core from "webcrypto-core";
|
||||
import { ShaCrypto } from "./crypto";
|
||||
|
||||
export class Sha3512Provider extends core.ProviderCrypto {
|
||||
public name = "SHA3-512";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import * as crypto from "crypto";
|
||||
import * as process from "process";
|
||||
import * as core from "webcrypto-core";
|
||||
import {
|
||||
|
@ -12,6 +13,7 @@ import {
|
|||
RsaEsProvider, RsaOaepProvider, RsaPssProvider, RsaSsaProvider,
|
||||
Sha1Provider, Sha256Provider, Sha384Provider, Sha512Provider,
|
||||
Shake128Provider, Shake256Provider,
|
||||
Sha3256Provider, Sha3384Provider, Sha3512Provider,
|
||||
} from "./mechs";
|
||||
|
||||
export class SubtleCrypto extends core.SubtleCrypto {
|
||||
|
@ -71,6 +73,17 @@ export class SubtleCrypto extends core.SubtleCrypto {
|
|||
//#endregion
|
||||
}
|
||||
|
||||
const hashes = crypto.getHashes();
|
||||
if (hashes.includes("sha3-256")) {
|
||||
this.providers.set(new Sha3256Provider());
|
||||
}
|
||||
if (hashes.includes("sha3-384")) {
|
||||
this.providers.set(new Sha3384Provider());
|
||||
}
|
||||
if (hashes.includes("sha3-512")) {
|
||||
this.providers.set(new Sha3512Provider());
|
||||
}
|
||||
|
||||
if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 14) {
|
||||
//#region EdDSA
|
||||
this.providers.set(new EdDsaProvider());
|
||||
|
|
|
@ -264,4 +264,20 @@ context("Crypto", () => {
|
|||
|
||||
});
|
||||
|
||||
context("SHA3", () => {
|
||||
const data = new Uint8Array(10);
|
||||
it("SHA3-256", async () => {
|
||||
const digest = await crypto.subtle.digest("SHA3-256", data);
|
||||
assert.strictEqual(Convert.ToHex(digest), "0cd5285ba8524fe42ac8f0076de9135d056132a9996213ae1c0f1420c908418b");
|
||||
});
|
||||
it("SHA3-384", async () => {
|
||||
const digest = await crypto.subtle.digest("SHA3-384", data);
|
||||
assert.strictEqual(Convert.ToHex(digest), "f54cecb8c160015f87b9e51edd087e10479d60479a42ff7e907ddf129fd7cb2782eb5624c43b453a24cffd8cbe42d0ec");
|
||||
});
|
||||
it("SHA3-512", async () => {
|
||||
const digest = await crypto.subtle.digest("SHA3-512", data);
|
||||
assert.strictEqual(Convert.ToHex(digest), "e12f775adfb4e440b74af7b670849a44b7efd1612a97a3a201080cb31944f1f2d9f0eae6b7c0cdb602f6ff0ba181add9997fd06e43f992df577aa52153ca0d27");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Reference in New Issue