Compare commits

...

4 Commits

Author SHA1 Message Date
Derrick Hammer 9e7cff20ff
*add build 2023-04-04 06:22:33 -04:00
Derrick Hammer 337743ed7f
*prettier format 2023-04-04 06:20:37 -04:00
Derrick Hammer de25aa8863
*add prettier 2023-04-04 06:20:06 -04:00
Derrick Hammer f50bab4814
*add buffer import 2023-04-04 06:19:16 -04:00
58 changed files with 6474 additions and 499 deletions

2353
build/webcrypto.es.js Normal file

File diff suppressed because it is too large Load Diff

2377
build/webcrypto.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,7 @@
"eslint": "^8.36.0", "eslint": "^8.36.0",
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"mocha": "^10.2.0", "mocha": "^10.2.0",
"prettier": "^2.8.7",
"rimraf": "^4.4.0", "rimraf": "^4.4.0",
"rollup": "^3.20.0", "rollup": "^3.20.0",
"rollup-plugin-typescript2": "^0.34.1", "rollup-plugin-typescript2": "^0.34.1",
@ -70,6 +71,7 @@
"dependencies": { "dependencies": {
"@peculiar/asn1-schema": "^2.3.6", "@peculiar/asn1-schema": "^2.3.6",
"@peculiar/json-schema": "^1.1.12", "@peculiar/json-schema": "^1.1.12",
"buffer": "^6.0.3",
"pvtsutils": "^1.3.2", "pvtsutils": "^1.3.2",
"tslib": "^2.5.0", "tslib": "^2.5.0",
"webcrypto-core": "^1.7.7" "webcrypto-core": "^1.7.7"

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import { IJsonConverter } from "@peculiar/json-schema"; import { IJsonConverter } from "@peculiar/json-schema";
import { Convert } from "pvtsutils"; import { Convert } from "pvtsutils";

View File

@ -1,18 +1,23 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { SubtleCrypto } from "./subtle"; import { SubtleCrypto } from "./subtle";
export class Crypto extends core.Crypto { export class Crypto extends core.Crypto {
public subtle = new SubtleCrypto(); public subtle = new SubtleCrypto();
public getRandomValues<T extends ArrayBufferView | null>(array: T): T { public getRandomValues<T extends ArrayBufferView | null>(array: T): T {
if (!ArrayBuffer.isView(array)) { if (!ArrayBuffer.isView(array)) {
throw new TypeError("Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'"); throw new TypeError(
"Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'"
);
} }
const buffer = Buffer.from(array.buffer, array.byteOffset, array.byteLength); const buffer = Buffer.from(
array.buffer,
array.byteOffset,
array.byteLength
);
crypto.randomFillSync(buffer); crypto.randomFillSync(buffer);
return array; return array;
} }
} }

View File

@ -1,8 +1,6 @@
import { CryptoKey } from "./key"; import { CryptoKey } from "./key";
export abstract class AsymmetricKey extends CryptoKey { export abstract class AsymmetricKey extends CryptoKey {
public abstract override type: "public" | "private"; public abstract override type: "public" | "private";
public pem?: string; public pem?: string;
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import { JsonProp, JsonPropTypes } from "@peculiar/json-schema"; import { JsonProp, JsonPropTypes } from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
@ -11,7 +12,12 @@ export class CryptoKey extends core.CryptoKey {
public override type: KeyType = "secret"; public override type: KeyType = "secret";
@JsonProp({ name: "key_ops", type: JsonPropTypes.String, repeated: true, optional: true }) @JsonProp({
name: "key_ops",
type: JsonPropTypes.String,
repeated: true,
optional: true,
})
public override usages: KeyUsage[] = []; public override usages: KeyUsage[] = [];
@JsonProp({ type: JsonPropTypes.String }) @JsonProp({ type: JsonPropTypes.String })

View File

@ -1,8 +1,6 @@
import { CryptoKey } from "./key"; import { CryptoKey } from "./key";
export class SymmetricKey extends CryptoKey { export class SymmetricKey extends CryptoKey {
public override readonly kty = "oct"; public override readonly kty = "oct";
public override readonly type = "secret" as const; public override readonly type = "secret" as const;
} }

View File

@ -4,33 +4,68 @@ import { AesCryptoKey } from "./key";
import { getCryptoKey, setCryptoKey } from "../storage"; import { getCryptoKey, setCryptoKey } from "../storage";
export class AesCbcProvider extends core.AesCbcProvider { export class AesCbcProvider extends core.AesCbcProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await AesCrypto.generateKey( const key = await AesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: algorithm.length, length: algorithm.length,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: Algorithm,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: Algorithm,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await AesCrypto.importKey(
format,
keyData,
{ name: algorithm.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import * as crypto from "crypto"; import * as crypto from "crypto";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { AesCrypto } from "./crypto"; import { AesCrypto } from "./crypto";
@ -90,14 +91,17 @@ function aesCmac(key: Buffer, message: Buffer) {
blockCount = 1; blockCount = 1;
lastBlockCompleteFlag = false; lastBlockCompleteFlag = false;
} else { } else {
lastBlockCompleteFlag = (message.length % blockSize === 0); lastBlockCompleteFlag = message.length % blockSize === 0;
} }
const lastBlockIndex = blockCount - 1; const lastBlockIndex = blockCount - 1;
if (lastBlockCompleteFlag) { if (lastBlockCompleteFlag) {
lastBlock = xor(getMessageBlock(message, lastBlockIndex), subkeys.subkey1); lastBlock = xor(getMessageBlock(message, lastBlockIndex), subkeys.subkey1);
} else { } else {
lastBlock = xor(getPaddedMessageBlock(message, lastBlockIndex), subkeys.subkey2); lastBlock = xor(
getPaddedMessageBlock(message, lastBlockIndex),
subkeys.subkey2
);
} }
let x = zero; let x = zero;
@ -112,35 +116,63 @@ function aesCmac(key: Buffer, message: Buffer) {
} }
export class AesCmacProvider extends core.AesCmacProvider { export class AesCmacProvider extends core.AesCmacProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await AesCrypto.generateKey( const key = await AesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: algorithm.length, length: algorithm.length,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onSign(algorithm: core.AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onSign(
algorithm: core.AesCmacParams,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
const result = aesCmac(getCryptoKey(key).data, Buffer.from(data)); const result = aesCmac(getCryptoKey(key).data, Buffer.from(data));
return new Uint8Array(result).buffer; return new Uint8Array(result).buffer;
} }
public async onVerify(algorithm: core.AesCmacParams, key: AesCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> { public async onVerify(
algorithm: core.AesCmacParams,
key: AesCryptoKey,
signature: ArrayBuffer,
data: ArrayBuffer
): Promise<boolean> {
const signature2 = await this.sign(algorithm, key, data); const signature2 = await this.sign(algorithm, key, data);
return Buffer.from(signature).compare(Buffer.from(signature2)) === 0; return Buffer.from(signature).compare(Buffer.from(signature2)) === 0;
} }
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const res = await AesCrypto.importKey(
format,
keyData,
{ name: algorithm.name },
extractable,
keyUsages
);
return setCryptoKey(res); return setCryptoKey(res);
} }

View File

@ -4,33 +4,68 @@ import { AesCryptoKey } from "./key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class AesCtrProvider extends core.AesCtrProvider { export class AesCtrProvider extends core.AesCtrProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await AesCrypto.generateKey( const key = await AesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: algorithm.length, length: algorithm.length,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: AesCtrParams,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: AesCtrParams,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const res = await AesCrypto.importKey(
format,
keyData,
{ name: algorithm.name },
extractable,
keyUsages
);
return setCryptoKey(res); return setCryptoKey(res);
} }

View File

@ -4,33 +4,68 @@ import { AesCryptoKey } from "./key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class AesEcbProvider extends core.AesEcbProvider { export class AesEcbProvider extends core.AesEcbProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await AesCrypto.generateKey( const key = await AesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: algorithm.length, length: algorithm.length,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: Algorithm,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: Algorithm,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const res = await AesCrypto.importKey(
format,
keyData,
{ name: algorithm.name },
extractable,
keyUsages
);
return setCryptoKey(res); return setCryptoKey(res);
} }

View File

@ -4,33 +4,68 @@ import { AesCryptoKey } from "./key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class AesGcmProvider extends core.AesGcmProvider { export class AesGcmProvider extends core.AesGcmProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await AesCrypto.generateKey( const key = await AesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: algorithm.length, length: algorithm.length,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: AesGcmParams,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: AesGcmParams,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const res = await AesCrypto.importKey(
format,
keyData,
{ name: algorithm.name },
extractable,
keyUsages
);
return setCryptoKey(res); return setCryptoKey(res);
} }

View File

@ -4,34 +4,68 @@ import { AesCryptoKey } from "./key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class AesKwProvider extends core.AesKwProvider { export class AesKwProvider extends core.AesKwProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const res = await AesCrypto.generateKey( const res = await AesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: algorithm.length, length: algorithm.length,
}, },
extractable, extractable,
keyUsages, keyUsages
); );
return setCryptoKey(res); return setCryptoKey(res);
} }
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const res = await AesCrypto.importKey(
format,
keyData,
{ name: algorithm.name },
extractable,
keyUsages
);
return setCryptoKey(res); return setCryptoKey(res);
} }
public override async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onEncrypt(
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: Algorithm,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public override async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDecrypt(
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); algorithm: Algorithm,
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto, { CipherGCM, DecipherGCM } from "crypto"; import crypto, { CipherGCM, DecipherGCM } from "crypto";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
@ -5,10 +6,13 @@ import { AesCryptoKey } from "./key";
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class AesCrypto { export class AesCrypto {
public static AES_KW_IV = Buffer.from("A6A6A6A6A6A6A6A6", "hex"); public static AES_KW_IV = Buffer.from("A6A6A6A6A6A6A6A6", "hex");
public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<AesCryptoKey> { public static async generateKey(
algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<AesCryptoKey> {
const key = new AesCryptoKey(); const key = new AesCryptoKey();
key.algorithm = algorithm; key.algorithm = algorithm;
key.extractable = extractable; key.extractable = extractable;
@ -18,7 +22,10 @@ export class AesCrypto {
return key; return key;
} }
public static async exportKey(format: string, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public static async exportKey(
format: string,
key: AesCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
if (!(key instanceof AesCryptoKey)) { if (!(key instanceof AesCryptoKey)) {
throw new Error("key: Is not AesCryptoKey"); throw new Error("key: Is not AesCryptoKey");
} }
@ -33,7 +40,13 @@ export class AesCrypto {
} }
} }
public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public static async importKey(
format: string,
keyData: JsonWebKey | ArrayBuffer,
algorithm: any,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
let key: AesCryptoKey; let key: AesCryptoKey;
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
@ -66,78 +79,167 @@ export class AesCrypto {
return key; return key;
} }
public static async encrypt(algorithm: Algorithm, key: AesCryptoKey, data: Uint8Array): Promise<ArrayBuffer> { public static async encrypt(
algorithm: Algorithm,
key: AesCryptoKey,
data: Uint8Array
): Promise<ArrayBuffer> {
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "AES-CBC": case "AES-CBC":
return this.encryptAesCBC(algorithm as AesCbcParams, key, Buffer.from(data)); return this.encryptAesCBC(
algorithm as AesCbcParams,
key,
Buffer.from(data)
);
case "AES-CTR": case "AES-CTR":
return this.encryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data)); return this.encryptAesCTR(
algorithm as AesCtrParams,
key,
Buffer.from(data)
);
case "AES-GCM": case "AES-GCM":
return this.encryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data)); return this.encryptAesGCM(
algorithm as AesGcmParams,
key,
Buffer.from(data)
);
case "AES-KW": case "AES-KW":
return this.encryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data)); return this.encryptAesKW(
algorithm as AesKeyAlgorithm,
key,
Buffer.from(data)
);
case "AES-ECB": case "AES-ECB":
return this.encryptAesECB(algorithm as AesKeyAlgorithm, key, Buffer.from(data)); return this.encryptAesECB(
algorithm as AesKeyAlgorithm,
key,
Buffer.from(data)
);
default: default:
throw new core.OperationError("algorithm: Is not recognized"); throw new core.OperationError("algorithm: Is not recognized");
} }
} }
public static async decrypt(algorithm: Algorithm, key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer> { public static async decrypt(
algorithm: Algorithm,
key: CryptoKey,
data: Uint8Array
): Promise<ArrayBuffer> {
if (!(key instanceof AesCryptoKey)) { if (!(key instanceof AesCryptoKey)) {
throw new Error("key: Is not AesCryptoKey"); throw new Error("key: Is not AesCryptoKey");
} }
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "AES-CBC": case "AES-CBC":
return this.decryptAesCBC(algorithm as AesCbcParams, key, Buffer.from(data)); return this.decryptAesCBC(
algorithm as AesCbcParams,
key,
Buffer.from(data)
);
case "AES-CTR": case "AES-CTR":
return this.decryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data)); return this.decryptAesCTR(
algorithm as AesCtrParams,
key,
Buffer.from(data)
);
case "AES-GCM": case "AES-GCM":
return this.decryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data)); return this.decryptAesGCM(
algorithm as AesGcmParams,
key,
Buffer.from(data)
);
case "AES-KW": case "AES-KW":
return this.decryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data)); return this.decryptAesKW(
algorithm as AesKeyAlgorithm,
key,
Buffer.from(data)
);
case "AES-ECB": case "AES-ECB":
return this.decryptAesECB(algorithm as AesKeyAlgorithm, key, Buffer.from(data)); return this.decryptAesECB(
algorithm as AesKeyAlgorithm,
key,
Buffer.from(data)
);
default: default:
throw new core.OperationError("algorithm: Is not recognized"); throw new core.OperationError("algorithm: Is not recognized");
} }
} }
public static async encryptAesCBC(algorithm: AesCbcParams, key: AesCryptoKey, data: Buffer) { public static async encryptAesCBC(
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)); algorithm: AesCbcParams,
key: AesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`aes-${key.algorithm.length}-cbc`,
key.data,
new Uint8Array(algorithm.iv as ArrayBuffer)
);
let enc = cipher.update(data); let enc = cipher.update(data);
enc = Buffer.concat([enc, cipher.final()]); enc = Buffer.concat([enc, cipher.final()]);
const res = new Uint8Array(enc).buffer; const res = new Uint8Array(enc).buffer;
return res; return res;
} }
public static async decryptAesCBC(algorithm: AesCbcParams, key: AesCryptoKey, data: Buffer) { public static async decryptAesCBC(
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)); algorithm: AesCbcParams,
key: AesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`aes-${key.algorithm.length}-cbc`,
key.data,
new Uint8Array(algorithm.iv as ArrayBuffer)
);
let dec = decipher.update(data); let dec = decipher.update(data);
dec = Buffer.concat([dec, decipher.final()]); dec = Buffer.concat([dec, decipher.final()]);
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public static async encryptAesCTR(algorithm: AesCtrParams, key: AesCryptoKey, data: Buffer) { public static async encryptAesCTR(
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ctr`, key.data, Buffer.from(algorithm.counter as ArrayBuffer)); algorithm: AesCtrParams,
key: AesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`aes-${key.algorithm.length}-ctr`,
key.data,
Buffer.from(algorithm.counter as ArrayBuffer)
);
let enc = cipher.update(data); let enc = cipher.update(data);
enc = Buffer.concat([enc, cipher.final()]); enc = Buffer.concat([enc, cipher.final()]);
const res = new Uint8Array(enc).buffer; const res = new Uint8Array(enc).buffer;
return res; return res;
} }
public static async decryptAesCTR(algorithm: AesCtrParams, key: AesCryptoKey, data: Buffer) { public static async decryptAesCTR(
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ctr`, key.data, new Uint8Array(algorithm.counter as ArrayBuffer)); algorithm: AesCtrParams,
key: AesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`aes-${key.algorithm.length}-ctr`,
key.data,
new Uint8Array(algorithm.counter as ArrayBuffer)
);
let dec = decipher.update(data); let dec = decipher.update(data);
dec = Buffer.concat([dec, decipher.final()]); dec = Buffer.concat([dec, decipher.final()]);
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public static async encryptAesGCM(algorithm: AesGcmParams, key: AesCryptoKey, data: Buffer) { public static async encryptAesGCM(
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-gcm`, key.data, Buffer.from(algorithm.iv as ArrayBuffer), { algorithm: AesGcmParams,
authTagLength: (algorithm.tagLength || 128) >> 3, key: AesCryptoKey,
} as any) as CipherGCM; // NodeJs d.ts doesn't support CipherGCMOptions for createCipheriv data: Buffer
) {
const cipher = crypto.createCipheriv(
`aes-${key.algorithm.length}-gcm`,
key.data,
Buffer.from(algorithm.iv as ArrayBuffer),
{
authTagLength: (algorithm.tagLength || 128) >> 3,
} as any
) as CipherGCM; // NodeJs d.ts doesn't support CipherGCMOptions for createCipheriv
if (algorithm.additionalData) { if (algorithm.additionalData) {
cipher.setAAD(Buffer.from(algorithm.additionalData as ArrayBuffer)); cipher.setAAD(Buffer.from(algorithm.additionalData as ArrayBuffer));
} }
@ -147,8 +249,16 @@ export class AesCrypto {
return res; return res;
} }
public static async decryptAesGCM(algorithm: AesGcmParams, key: AesCryptoKey, data: Buffer) { public static async decryptAesGCM(
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-gcm`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)) as DecipherGCM; algorithm: AesGcmParams,
key: AesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`aes-${key.algorithm.length}-gcm`,
key.data,
new Uint8Array(algorithm.iv as ArrayBuffer)
) as DecipherGCM;
const tagLength = (algorithm.tagLength || 128) >> 3; const tagLength = (algorithm.tagLength || 128) >> 3;
const enc = data.slice(0, data.length - tagLength); const enc = data.slice(0, data.length - tagLength);
const tag = data.slice(data.length - tagLength); const tag = data.slice(data.length - tagLength);
@ -161,30 +271,62 @@ export class AesCrypto {
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public static async encryptAesKW(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) { public static async encryptAesKW(
const cipher = crypto.createCipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV); algorithm: Algorithm,
key: AesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`id-aes${key.algorithm.length}-wrap`,
key.data,
this.AES_KW_IV
);
let enc = cipher.update(data); let enc = cipher.update(data);
enc = Buffer.concat([enc, cipher.final()]); enc = Buffer.concat([enc, cipher.final()]);
return new Uint8Array(enc).buffer; return new Uint8Array(enc).buffer;
} }
public static async decryptAesKW(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) { public static async decryptAesKW(
const decipher = crypto.createDecipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV); algorithm: Algorithm,
key: AesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`id-aes${key.algorithm.length}-wrap`,
key.data,
this.AES_KW_IV
);
let dec = decipher.update(data); let dec = decipher.update(data);
dec = Buffer.concat([dec, decipher.final()]); dec = Buffer.concat([dec, decipher.final()]);
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public static async encryptAesECB(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) { public static async encryptAesECB(
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0)); algorithm: Algorithm,
key: AesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`aes-${key.algorithm.length}-ecb`,
key.data,
new Uint8Array(0)
);
let enc = cipher.update(data); let enc = cipher.update(data);
enc = Buffer.concat([enc, cipher.final()]); enc = Buffer.concat([enc, cipher.final()]);
const res = new Uint8Array(enc).buffer; const res = new Uint8Array(enc).buffer;
return res; return res;
} }
public static async decryptAesECB(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) { public static async decryptAesECB(
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0)); algorithm: Algorithm,
key: AesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`aes-${key.algorithm.length}-ecb`,
key.data,
new Uint8Array(0)
);
let dec = decipher.update(data); let dec = decipher.update(data);
dec = Buffer.concat([dec, decipher.final()]); dec = Buffer.concat([dec, decipher.final()]);
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;

View File

@ -4,10 +4,9 @@ import { JsonBase64UrlConverter } from "../../converters";
import { SymmetricKey } from "../../keys"; import { SymmetricKey } from "../../keys";
export class AesCryptoKey extends SymmetricKey { export class AesCryptoKey extends SymmetricKey {
public override algorithm!: AesKeyAlgorithm; public override algorithm!: AesKeyAlgorithm;
@JsonProp({name: "k", converter: JsonBase64UrlConverter}) @JsonProp({ name: "k", converter: JsonBase64UrlConverter })
public override data!: Buffer; public override data!: Buffer;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -34,5 +33,4 @@ export class AesCryptoKey extends SymmetricKey {
public override set alg(value: string) { public override set alg(value: string) {
// nothing, cause set is needed for json-schema, but is not used by module // nothing, cause set is needed for json-schema, but is not used by module
} }
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
@ -6,8 +7,11 @@ import { DesCryptoKey } from "./key";
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class DesCrypto { export class DesCrypto {
public static async generateKey(
public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<DesCryptoKey> { algorithm: AesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<DesCryptoKey> {
const key = new DesCryptoKey(); const key = new DesCryptoKey();
key.algorithm = algorithm; key.algorithm = algorithm;
key.extractable = extractable; key.extractable = extractable;
@ -17,7 +21,10 @@ export class DesCrypto {
return key; return key;
} }
public static async exportKey(format: string, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public static async exportKey(
format: string,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": case "jwk":
return JsonSerializer.toJSON(key); return JsonSerializer.toJSON(key);
@ -28,7 +35,13 @@ export class DesCrypto {
} }
} }
public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public static async importKey(
format: string,
keyData: JsonWebKey | ArrayBuffer,
algorithm: any,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
let key: DesCryptoKey; let key: DesCryptoKey;
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
@ -50,7 +63,11 @@ export class DesCrypto {
return key; return key;
} }
public static async encrypt(algorithm: DesParams, key: DesCryptoKey, data: Uint8Array): Promise<ArrayBuffer> { public static async encrypt(
algorithm: DesParams,
key: DesCryptoKey,
data: Uint8Array
): Promise<ArrayBuffer> {
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "DES-CBC": case "DES-CBC":
return this.encryptDesCBC(algorithm, key, Buffer.from(data)); return this.encryptDesCBC(algorithm, key, Buffer.from(data));
@ -61,7 +78,11 @@ export class DesCrypto {
} }
} }
public static async decrypt(algorithm: DesParams, key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer> { public static async decrypt(
algorithm: DesParams,
key: CryptoKey,
data: Uint8Array
): Promise<ArrayBuffer> {
if (!(key instanceof DesCryptoKey)) { if (!(key instanceof DesCryptoKey)) {
throw new Error("key: Is not DesCryptoKey"); throw new Error("key: Is not DesCryptoKey");
} }
@ -76,34 +97,65 @@ export class DesCrypto {
} }
} }
public static async encryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) { public static async encryptDesCBC(
const cipher = crypto.createCipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)); algorithm: DesParams,
key: DesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`des-cbc`,
key.data,
new Uint8Array(algorithm.iv as ArrayBuffer)
);
let enc = cipher.update(data); let enc = cipher.update(data);
enc = Buffer.concat([enc, cipher.final()]); enc = Buffer.concat([enc, cipher.final()]);
const res = new Uint8Array(enc).buffer; const res = new Uint8Array(enc).buffer;
return res; return res;
} }
public static async decryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) { public static async decryptDesCBC(
const decipher = crypto.createDecipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)); algorithm: DesParams,
key: DesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`des-cbc`,
key.data,
new Uint8Array(algorithm.iv as ArrayBuffer)
);
let dec = decipher.update(data); let dec = decipher.update(data);
dec = Buffer.concat([dec, decipher.final()]); dec = Buffer.concat([dec, decipher.final()]);
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public static async encryptDesEDE3CBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) { public static async encryptDesEDE3CBC(
const cipher = crypto.createCipheriv(`des-ede3-cbc`, key.data, Buffer.from(algorithm.iv as ArrayBuffer)); algorithm: DesParams,
key: DesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`des-ede3-cbc`,
key.data,
Buffer.from(algorithm.iv as ArrayBuffer)
);
let enc = cipher.update(data); let enc = cipher.update(data);
enc = Buffer.concat([enc, cipher.final()]); enc = Buffer.concat([enc, cipher.final()]);
const res = new Uint8Array(enc).buffer; const res = new Uint8Array(enc).buffer;
return res; return res;
} }
public static async decryptDesEDE3CBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) { public static async decryptDesEDE3CBC(
const decipher = crypto.createDecipheriv(`des-ede3-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)); algorithm: DesParams,
key: DesCryptoKey,
data: Buffer
) {
const decipher = crypto.createDecipheriv(
`des-ede3-cbc`,
key.data,
new Uint8Array(algorithm.iv as ArrayBuffer)
);
let dec = decipher.update(data); let dec = decipher.update(data);
dec = Buffer.concat([dec, decipher.final()]); dec = Buffer.concat([dec, decipher.final()]);
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
} }

View File

@ -7,38 +7,73 @@ import { setCryptoKey, getCryptoKey } from "../storage";
export type DesCbcParams = core.DesParams; export type DesCbcParams = core.DesParams;
export class DesCbcProvider extends core.DesProvider { export class DesCbcProvider extends core.DesProvider {
public keySizeBits = 64; public keySizeBits = 64;
public ivSize = 8; public ivSize = 8;
public name = "DES-CBC"; public name = "DES-CBC";
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onGenerateKey(
algorithm: core.DesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await DesCrypto.generateKey( const key = await DesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: this.keySizeBits, length: this.keySizeBits,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); algorithm: DesCbcParams,
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.encrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); algorithm: DesCbcParams,
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.decrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey); return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onImportKey(
const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages); format: KeyFormat,
if (key.data.length !== (this.keySizeBits >> 3)) { keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await DesCrypto.importKey(
format,
keyData,
{ name: this.name, length: this.keySizeBits },
extractable,
keyUsages
);
if (key.data.length !== this.keySizeBits >> 3) {
throw new core.OperationError("keyData: Wrong key size"); throw new core.OperationError("keyData: Wrong key size");
} }
return setCryptoKey(key); return setCryptoKey(key);
@ -50,5 +85,4 @@ export class DesCbcProvider extends core.DesProvider {
throw new TypeError("key: Is not a DesCryptoKey"); throw new TypeError("key: Is not a DesCryptoKey");
} }
} }
} }

View File

@ -7,38 +7,73 @@ import { setCryptoKey, getCryptoKey } from "../storage";
export type DesEde3CbcParams = core.DesParams; export type DesEde3CbcParams = core.DesParams;
export class DesEde3CbcProvider extends core.DesProvider { export class DesEde3CbcProvider extends core.DesProvider {
public keySizeBits = 192; public keySizeBits = 192;
public ivSize = 8; public ivSize = 8;
public name = "DES-EDE3-CBC"; public name = "DES-EDE3-CBC";
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onGenerateKey(
algorithm: core.DesKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await DesCrypto.generateKey( const key = await DesCrypto.generateKey(
{ {
name: this.name, name: this.name,
length: this.keySizeBits, length: this.keySizeBits,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); algorithm: DesEde3CbcParams,
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.encrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); algorithm: DesEde3CbcParams,
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.decrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey); return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey);
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onImportKey(
const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages); format: KeyFormat,
if (key.data.length !== (this.keySizeBits >> 3)) { keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await DesCrypto.importKey(
format,
keyData,
{ name: this.name, length: this.keySizeBits },
extractable,
keyUsages
);
if (key.data.length !== this.keySizeBits >> 3) {
throw new core.OperationError("keyData: Wrong key size"); throw new core.OperationError("keyData: Wrong key size");
} }
return setCryptoKey(key); return setCryptoKey(key);
@ -50,5 +85,4 @@ export class DesEde3CbcProvider extends core.DesProvider {
throw new TypeError("key: Is not a DesCryptoKey"); throw new TypeError("key: Is not a DesCryptoKey");
} }
} }
} }

View File

@ -4,10 +4,9 @@ import { JsonBase64UrlConverter } from "../../converters";
import { SymmetricKey } from "../../keys"; import { SymmetricKey } from "../../keys";
export class DesCryptoKey extends SymmetricKey { export class DesCryptoKey extends SymmetricKey {
public override algorithm!: core.DesKeyAlgorithm; public override algorithm!: core.DesKeyAlgorithm;
@JsonProp({name: "k", converter: JsonBase64UrlConverter}) @JsonProp({ name: "k", converter: JsonBase64UrlConverter })
public override data!: Buffer; public override data!: Buffer;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -26,5 +25,4 @@ export class DesCryptoKey extends SymmetricKey {
public override set alg(value: string) { public override set alg(value: string) {
// nothing, cause set is needed for json-schema, but is not used by module // nothing, cause set is needed for json-schema, but is not used by module
} }
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
@ -10,20 +11,27 @@ import { CryptoKey } from "../../keys";
import { ShaCrypto } from "../sha"; import { ShaCrypto } from "../sha";
export class EcCrypto { export class EcCrypto {
public static publicKeyUsages = ["verify"]; public static publicKeyUsages = ["verify"];
public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"];
public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { public static async generateKey(
algorithm: EcKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const privateKey = new EcPrivateKey(); const privateKey = new EcPrivateKey();
privateKey.algorithm = algorithm; privateKey.algorithm = algorithm;
privateKey.extractable = extractable; privateKey.extractable = extractable;
privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1); privateKey.usages = keyUsages.filter(
(usage) => this.privateKeyUsages.indexOf(usage) !== -1
);
const publicKey = new EcPublicKey(); const publicKey = new EcPublicKey();
publicKey.algorithm = algorithm; publicKey.algorithm = algorithm;
publicKey.extractable = true; publicKey.extractable = true;
publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1); publicKey.usages = keyUsages.filter(
(usage) => this.publicKeyUsages.indexOf(usage) !== -1
);
const keys = crypto.generateKeyPairSync("ec", { const keys = crypto.generateKeyPairSync("ec", {
namedCurve: this.getOpenSSLNamedCurve(algorithm.namedCurve), namedCurve: this.getOpenSSLNamedCurve(algorithm.namedCurve),
@ -48,13 +56,19 @@ export class EcCrypto {
return res; return res;
} }
public static async sign(algorithm: EcdsaParams, key: EcPrivateKey, data: Uint8Array): Promise<ArrayBuffer> { public static async sign(
algorithm: EcdsaParams,
key: EcPrivateKey,
data: Uint8Array
): Promise<ArrayBuffer> {
const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm); const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm);
const signer = crypto.createSign(cryptoAlg); const signer = crypto.createSign(cryptoAlg);
signer.update(Buffer.from(data)); signer.update(Buffer.from(data));
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
@ -63,18 +77,28 @@ export class EcCrypto {
const signature = signer.sign(options); const signature = signer.sign(options);
const ecSignature = AsnParser.parse(signature, core.asn1.EcDsaSignature); const ecSignature = AsnParser.parse(signature, core.asn1.EcDsaSignature);
const signatureRaw = core.EcUtils.encodeSignature(ecSignature, core.EcCurves.get(key.algorithm.namedCurve).size); const signatureRaw = core.EcUtils.encodeSignature(
ecSignature,
core.EcCurves.get(key.algorithm.namedCurve).size
);
return signatureRaw.buffer; return signatureRaw.buffer;
} }
public static async verify(algorithm: EcdsaParams, key: EcPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> { public static async verify(
algorithm: EcdsaParams,
key: EcPublicKey,
signature: Uint8Array,
data: Uint8Array
): Promise<boolean> {
const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm); const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm);
const signer = crypto.createVerify(cryptoAlg); const signer = crypto.createVerify(cryptoAlg);
signer.update(Buffer.from(data)); signer.update(Buffer.from(data));
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
@ -82,7 +106,10 @@ export class EcCrypto {
const ecSignature = new core.asn1.EcDsaSignature(); const ecSignature = new core.asn1.EcDsaSignature();
const namedCurve = core.EcCurves.get(key.algorithm.namedCurve); const namedCurve = core.EcCurves.get(key.algorithm.namedCurve);
const signaturePoint = core.EcUtils.decodeSignature(signature, namedCurve.size); const signaturePoint = core.EcUtils.decodeSignature(
signature,
namedCurve.size
);
ecSignature.r = BufferSourceConverter.toArrayBuffer(signaturePoint.r); ecSignature.r = BufferSourceConverter.toArrayBuffer(signaturePoint.r);
ecSignature.s = BufferSourceConverter.toArrayBuffer(signaturePoint.s); ecSignature.s = BufferSourceConverter.toArrayBuffer(signaturePoint.s);
@ -91,15 +118,30 @@ export class EcCrypto {
return ok; return ok;
} }
public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number | null): Promise<ArrayBuffer> { public static async deriveBits(
const cryptoAlg = this.getOpenSSLNamedCurve((baseKey.algorithm as EcKeyAlgorithm).namedCurve); algorithm: EcdhKeyDeriveParams,
baseKey: CryptoKey,
length: number | null
): Promise<ArrayBuffer> {
const cryptoAlg = this.getOpenSSLNamedCurve(
(baseKey.algorithm as EcKeyAlgorithm).namedCurve
);
const ecdh = crypto.createECDH(cryptoAlg); const ecdh = crypto.createECDH(cryptoAlg);
const asnPrivateKey = AsnParser.parse(baseKey.data, core.asn1.PrivateKeyInfo); const asnPrivateKey = AsnParser.parse(
const asnEcPrivateKey = AsnParser.parse(asnPrivateKey.privateKey, core.asn1.EcPrivateKey); baseKey.data,
core.asn1.PrivateKeyInfo
);
const asnEcPrivateKey = AsnParser.parse(
asnPrivateKey.privateKey,
core.asn1.EcPrivateKey
);
ecdh.setPrivateKey(Buffer.from(asnEcPrivateKey.privateKey)); ecdh.setPrivateKey(Buffer.from(asnEcPrivateKey.privateKey));
const asnPublicKey = AsnParser.parse((algorithm.public as CryptoKey).data, core.asn1.PublicKeyInfo); const asnPublicKey = AsnParser.parse(
(algorithm.public as CryptoKey).data,
core.asn1.PublicKeyInfo
);
const bits = ecdh.computeSecret(Buffer.from(asnPublicKey.publicKey)); const bits = ecdh.computeSecret(Buffer.from(asnPublicKey.publicKey));
if (length === null) { if (length === null) {
@ -109,7 +151,10 @@ export class EcCrypto {
return new Uint8Array(bits).buffer.slice(0, length >> 3); return new Uint8Array(bits).buffer.slice(0, length >> 3);
} }
public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public static async exportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": case "jwk":
return JsonSerializer.toJSON(key); return JsonSerializer.toJSON(key);
@ -117,24 +162,49 @@ export class EcCrypto {
case "spki": case "spki":
return new Uint8Array(key.data).buffer; return new Uint8Array(key.data).buffer;
case "raw": { case "raw": {
const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo); const publicKeyInfo = AsnParser.parse(
key.data,
core.asn1.PublicKeyInfo
);
return publicKeyInfo.publicKey; return publicKeyInfo.publicKey;
} }
default: default:
throw new core.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'"); throw new core.OperationError(
"format: Must be 'jwk', 'raw', pkcs8' or 'spki'"
);
} }
} }
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public static async importKey(
format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": { case "jwk": {
const jwk = keyData as JsonWebKey; const jwk = keyData as JsonWebKey;
if (jwk.d) { if (jwk.d) {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPrivateKey }); const asnKey = JsonParser.fromJSON(keyData, {
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); targetSchema: core.asn1.EcPrivateKey,
});
return this.importPrivateKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} else { } else {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPublicKey }); const asnKey = JsonParser.fromJSON(keyData, {
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); targetSchema: core.asn1.EcPublicKey,
});
return this.importPublicKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} }
} }
case "raw": { case "raw": {
@ -142,43 +212,75 @@ export class EcCrypto {
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
} }
case "spki": { case "spki": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo); const keyInfo = AsnParser.parse(
new Uint8Array(keyData as ArrayBuffer),
core.asn1.PublicKeyInfo
);
const asnKey = new core.asn1.EcPublicKey(keyInfo.publicKey); const asnKey = new core.asn1.EcPublicKey(keyInfo.publicKey);
this.assertKeyParameters(keyInfo.publicKeyAlgorithm.parameters, algorithm.namedCurve); this.assertKeyParameters(
keyInfo.publicKeyAlgorithm.parameters,
algorithm.namedCurve
);
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
} }
case "pkcs8": { case "pkcs8": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo); const keyInfo = AsnParser.parse(
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey); new Uint8Array(keyData as ArrayBuffer),
this.assertKeyParameters(keyInfo.privateKeyAlgorithm.parameters, algorithm.namedCurve); core.asn1.PrivateKeyInfo
);
const asnKey = AsnParser.parse(
keyInfo.privateKey,
core.asn1.EcPrivateKey
);
this.assertKeyParameters(
keyInfo.privateKeyAlgorithm.parameters,
algorithm.namedCurve
);
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
} }
default: default:
throw new core.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"); throw new core.OperationError(
"format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"
);
} }
} }
protected static assertKeyParameters(parameters: ArrayBuffer | null | undefined, namedCurve: string) { protected static assertKeyParameters(
parameters: ArrayBuffer | null | undefined,
namedCurve: string
) {
if (!parameters) { if (!parameters) {
throw new core.CryptoError("Key info doesn't have required parameters"); throw new core.CryptoError("Key info doesn't have required parameters");
} }
let namedCurveIdentifier = ""; let namedCurveIdentifier = "";
try { try {
namedCurveIdentifier = AsnParser.parse(parameters, core.asn1.ObjectIdentifier).value; namedCurveIdentifier = AsnParser.parse(
parameters,
core.asn1.ObjectIdentifier
).value;
} catch (e) { } catch (e) {
throw new core.CryptoError("Cannot read key info parameters"); throw new core.CryptoError("Cannot read key info parameters");
} }
if (getOidByNamedCurve(namedCurve) !== namedCurveIdentifier) { if (getOidByNamedCurve(namedCurve) !== namedCurveIdentifier) {
throw new core.CryptoError("Key info parameter doesn't match to named curve"); throw new core.CryptoError(
"Key info parameter doesn't match to named curve"
);
} }
} }
protected static async importPrivateKey(asnKey: core.asn1.EcPrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) { protected static async importPrivateKey(
asnKey: core.asn1.EcPrivateKey,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
) {
const keyInfo = new core.asn1.PrivateKeyInfo(); const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve))); keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve))
);
keyInfo.privateKey = AsnSerializer.serialize(asnKey); keyInfo.privateKey = AsnSerializer.serialize(asnKey);
const key = new EcPrivateKey(); const key = new EcPrivateKey();
@ -191,11 +293,18 @@ export class EcCrypto {
return key; return key;
} }
protected static async importPublicKey(asnKey: core.asn1.EcPublicKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) { protected static async importPublicKey(
asnKey: core.asn1.EcPublicKey,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
) {
const keyInfo = new core.asn1.PublicKeyInfo(); const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
const namedCurve = getOidByNamedCurve(algorithm.namedCurve); const namedCurve = getOidByNamedCurve(algorithm.namedCurve);
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(namedCurve)); keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
new core.asn1.ObjectIdentifier(namedCurve)
);
keyInfo.publicKey = asnKey.value; keyInfo.publicKey = asnKey.value;
const key = new EcPublicKey(); const key = new EcPublicKey();
@ -222,5 +331,4 @@ export class EcCrypto {
return curve; return curve;
} }
} }
} }

View File

@ -6,17 +6,21 @@ import { CryptoKey } from "../../keys";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class EcdhProvider extends core.EcdhProvider { export class EcdhProvider extends core.EcdhProvider {
public override namedCurves = core.EcCurves.names; public override namedCurves = core.EcCurves.names;
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { public async onGenerateKey(
algorithm: EcKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await EcCrypto.generateKey( const keys = await EcCrypto.generateKey(
{ {
...algorithm, ...algorithm,
name: this.name, name: this.name,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as CryptoKey), privateKey: setCryptoKey(keys.privateKey as CryptoKey),
@ -24,26 +28,53 @@ export class EcdhProvider extends core.EcdhProvider {
}; };
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return EcCrypto.exportKey(format, getCryptoKey(key)); return EcCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onImportKey(
const key = await EcCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await EcCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
super.checkCryptoKey(key, keyUsage); super.checkCryptoKey(key, keyUsage);
const internalKey = getCryptoKey(key); const internalKey = getCryptoKey(key);
if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) { if (
!(
internalKey instanceof EcPrivateKey ||
internalKey instanceof EcPublicKey
)
) {
throw new TypeError("key: Is not EC CryptoKey"); throw new TypeError("key: Is not EC CryptoKey");
} }
} }
public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> { public async onDeriveBits(
const bits = await EcCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length); algorithm: EcdhKeyDeriveParams,
baseKey: CryptoKey,
length: number
): Promise<ArrayBuffer> {
const bits = await EcCrypto.deriveBits(
{ ...algorithm, public: getCryptoKey(algorithm.public) },
getCryptoKey(baseKey),
length
);
return bits; return bits;
} }
} }

View File

@ -5,22 +5,33 @@ import { EcPublicKey } from "./public_key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class EcdsaProvider extends core.EcdsaProvider { export class EcdsaProvider extends core.EcdsaProvider {
public override namedCurves = core.EcCurves.names; public override namedCurves = core.EcCurves.names;
public override hashAlgorithms = [ public override hashAlgorithms = [
"SHA-1", "SHA-256", "SHA-384", "SHA-512", "SHA-1",
"shake128", "shake256", "SHA-256",
"SHA3-256", "SHA3-384", "SHA3-512"]; "SHA-384",
"SHA-512",
"shake128",
"shake256",
"SHA3-256",
"SHA3-384",
"SHA3-512",
];
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { public async onGenerateKey(
algorithm: EcKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await EcCrypto.generateKey( const keys = await EcCrypto.generateKey(
{ {
...algorithm, ...algorithm,
name: this.name, name: this.name,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as EcPrivateKey), privateKey: setCryptoKey(keys.privateKey as EcPrivateKey),
@ -28,29 +39,66 @@ export class EcdsaProvider extends core.EcdsaProvider {
}; };
} }
public async onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onSign(
return EcCrypto.sign(algorithm, getCryptoKey(key) as EcPrivateKey, new Uint8Array(data)); algorithm: EcdsaParams,
key: EcPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return EcCrypto.sign(
algorithm,
getCryptoKey(key) as EcPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> { public async onVerify(
return EcCrypto.verify(algorithm, getCryptoKey(key) as EcPublicKey, new Uint8Array(signature), new Uint8Array(data)); algorithm: EcdsaParams,
key: EcPublicKey,
signature: ArrayBuffer,
data: ArrayBuffer
): Promise<boolean> {
return EcCrypto.verify(
algorithm,
getCryptoKey(key) as EcPublicKey,
new Uint8Array(signature),
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return EcCrypto.exportKey(format, getCryptoKey(key)); return EcCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await EcCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
super.checkCryptoKey(key, keyUsage); super.checkCryptoKey(key, keyUsage);
const internalKey = getCryptoKey(key); const internalKey = getCryptoKey(key);
if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) { if (
!(
internalKey instanceof EcPrivateKey ||
internalKey instanceof EcPublicKey
)
) {
throw new TypeError("key: Is not EC CryptoKey"); throw new TypeError("key: Is not EC CryptoKey");
} }
} }
} }

View File

@ -15,40 +15,42 @@ const namedOIDs: { [key: string]: string } = {
"K-256": "1.3.132.0.10", "K-256": "1.3.132.0.10",
// brainpool // brainpool
"brainpoolP160r1": "1.3.36.3.3.2.8.1.1.1", brainpoolP160r1: "1.3.36.3.3.2.8.1.1.1",
"1.3.36.3.3.2.8.1.1.1": "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1": "brainpoolP160r1",
"brainpoolP160t1": "1.3.36.3.3.2.8.1.1.2", brainpoolP160t1: "1.3.36.3.3.2.8.1.1.2",
"1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1", "1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1",
"brainpoolP192r1": "1.3.36.3.3.2.8.1.1.3", brainpoolP192r1: "1.3.36.3.3.2.8.1.1.3",
"1.3.36.3.3.2.8.1.1.3": "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3": "brainpoolP192r1",
"brainpoolP192t1": "1.3.36.3.3.2.8.1.1.4", brainpoolP192t1: "1.3.36.3.3.2.8.1.1.4",
"1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1", "1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1",
"brainpoolP224r1": "1.3.36.3.3.2.8.1.1.5", brainpoolP224r1: "1.3.36.3.3.2.8.1.1.5",
"1.3.36.3.3.2.8.1.1.5": "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5": "brainpoolP224r1",
"brainpoolP224t1": "1.3.36.3.3.2.8.1.1.6", brainpoolP224t1: "1.3.36.3.3.2.8.1.1.6",
"1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1", "1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1",
"brainpoolP256r1": "1.3.36.3.3.2.8.1.1.7", brainpoolP256r1: "1.3.36.3.3.2.8.1.1.7",
"1.3.36.3.3.2.8.1.1.7": "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7": "brainpoolP256r1",
"brainpoolP256t1": "1.3.36.3.3.2.8.1.1.8", brainpoolP256t1: "1.3.36.3.3.2.8.1.1.8",
"1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1", "1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1",
"brainpoolP320r1": "1.3.36.3.3.2.8.1.1.9", brainpoolP320r1: "1.3.36.3.3.2.8.1.1.9",
"1.3.36.3.3.2.8.1.1.9": "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9": "brainpoolP320r1",
"brainpoolP320t1": "1.3.36.3.3.2.8.1.1.10", brainpoolP320t1: "1.3.36.3.3.2.8.1.1.10",
"1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1", "1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1",
"brainpoolP384r1": "1.3.36.3.3.2.8.1.1.11", brainpoolP384r1: "1.3.36.3.3.2.8.1.1.11",
"1.3.36.3.3.2.8.1.1.11": "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11": "brainpoolP384r1",
"brainpoolP384t1": "1.3.36.3.3.2.8.1.1.12", brainpoolP384t1: "1.3.36.3.3.2.8.1.1.12",
"1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1", "1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1",
"brainpoolP512r1": "1.3.36.3.3.2.8.1.1.13", brainpoolP512r1: "1.3.36.3.3.2.8.1.1.13",
"1.3.36.3.3.2.8.1.1.13": "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13": "brainpoolP512r1",
"brainpoolP512t1": "1.3.36.3.3.2.8.1.1.14", brainpoolP512t1: "1.3.36.3.3.2.8.1.1.14",
"1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1", "1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1",
}; };
export function getNamedCurveByOid(oid: string) { export function getNamedCurveByOid(oid: string) {
const namedCurve = namedOIDs[oid]; const namedCurve = namedOIDs[oid];
if (!namedCurve) { if (!namedCurve) {
throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`); throw new core.OperationError(
`Cannot convert OID(${oid}) to WebCrypto named curve`
);
} }
return namedCurve; return namedCurve;
} }
@ -56,7 +58,9 @@ export function getNamedCurveByOid(oid: string) {
export function getOidByNamedCurve(namedCurve: string) { export function getOidByNamedCurve(namedCurve: string) {
const oid = namedOIDs[namedCurve]; const oid = namedOIDs[namedCurve];
if (!oid) { if (!oid) {
throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); throw new core.OperationError(
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
);
} }
return oid; return oid;
} }

View File

@ -1,5 +1,10 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema"; import {
IJsonConvertible,
JsonParser,
JsonSerializer,
} from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { getOidByNamedCurve } from "./helper"; import { getOidByNamedCurve } from "./helper";
import { AsymmetricKey } from "../../keys"; import { AsymmetricKey } from "../../keys";
@ -28,20 +33,23 @@ export class EcPrivateKey extends AsymmetricKey implements IJsonConvertible {
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
if (!json.crv) { if (!json.crv) {
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); throw new core.OperationError(
`Cannot get named curve from JWK. Property 'crv' is required`
);
} }
const keyInfo = new core.asn1.PrivateKeyInfo(); const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize( keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv)), new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv))
); );
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPrivateKey }); const key = JsonParser.fromJSON(json, {
targetSchema: core.asn1.EcPrivateKey,
});
keyInfo.privateKey = AsnSerializer.serialize(key); keyInfo.privateKey = AsnSerializer.serialize(key);
this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
return this; return this;
} }
} }

View File

@ -1,11 +1,15 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema"; import {
IJsonConvertible,
JsonParser,
JsonSerializer,
} from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { getOidByNamedCurve } from "./helper"; import { getOidByNamedCurve } from "./helper";
import { AsymmetricKey } from "../../keys/asymmetric"; import { AsymmetricKey } from "../../keys/asymmetric";
export class EcPublicKey extends AsymmetricKey implements IJsonConvertible { export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
public readonly type = "public" as const; public readonly type = "public" as const;
public override algorithm!: EcKeyAlgorithm; public override algorithm!: EcKeyAlgorithm;
@ -29,15 +33,19 @@ export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
if (!json.crv) { if (!json.crv) {
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); throw new core.OperationError(
`Cannot get named curve from JWK. Property 'crv' is required`
);
} }
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPublicKey }); const key = JsonParser.fromJSON(json, {
targetSchema: core.asn1.EcPublicKey,
});
const keyInfo = new core.asn1.PublicKeyInfo(); const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize( keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv)), new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv))
); );
keyInfo.publicKey = (AsnSerializer.toASN(key) as any).valueHex; keyInfo.publicKey = (AsnSerializer.toASN(key) as any).valueHex;

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import { AsnParser } from "@peculiar/asn1-schema"; import { AsnParser } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
@ -8,20 +9,27 @@ import { EdPublicKey } from "./public_key";
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class EdCrypto { export class EdCrypto {
public static publicKeyUsages = ["verify"]; public static publicKeyUsages = ["verify"];
public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"];
public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { public static async generateKey(
algorithm: EcKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const privateKey = new EdPrivateKey(); const privateKey = new EdPrivateKey();
privateKey.algorithm = algorithm; privateKey.algorithm = algorithm;
privateKey.extractable = extractable; privateKey.extractable = extractable;
privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1); privateKey.usages = keyUsages.filter(
(usage) => this.privateKeyUsages.indexOf(usage) !== -1
);
const publicKey = new EdPublicKey(); const publicKey = new EdPublicKey();
publicKey.algorithm = algorithm; publicKey.algorithm = algorithm;
publicKey.extractable = true; publicKey.extractable = true;
publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1); publicKey.usages = keyUsages.filter(
(usage) => this.publicKeyUsages.indexOf(usage) !== -1
);
const type = algorithm.namedCurve.toLowerCase() as "x448"; // "x448" | "ed448" | "x25519" | "ed25519" const type = algorithm.namedCurve.toLowerCase() as "x448"; // "x448" | "ed448" | "x25519" | "ed25519"
const keys = crypto.generateKeyPairSync(type, { const keys = crypto.generateKeyPairSync(type, {
@ -46,9 +54,15 @@ export class EdCrypto {
return res; return res;
} }
public static async sign(algorithm: Algorithm, key: EdPrivateKey, data: Uint8Array): Promise<ArrayBuffer> { public static async sign(
algorithm: Algorithm,
key: EdPrivateKey,
data: Uint8Array
): Promise<ArrayBuffer> {
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
@ -58,18 +72,34 @@ export class EdCrypto {
return core.BufferSourceConverter.toArrayBuffer(signature); return core.BufferSourceConverter.toArrayBuffer(signature);
} }
public static async verify(algorithm: EcdsaParams, key: EdPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> { public static async verify(
algorithm: EcdsaParams,
key: EdPublicKey,
signature: Uint8Array,
data: Uint8Array
): Promise<boolean> {
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
}; };
const ok = crypto.verify(null, Buffer.from(data), options, Buffer.from(signature)); const ok = crypto.verify(
null,
Buffer.from(data),
options,
Buffer.from(signature)
);
return ok; return ok;
} }
public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> { public static async deriveBits(
algorithm: EcdhKeyDeriveParams,
baseKey: CryptoKey,
length: number
): Promise<ArrayBuffer> {
const publicKey = crypto.createPublicKey({ const publicKey = crypto.createPublicKey({
key: (algorithm.public as CryptoKey).data, key: (algorithm.public as CryptoKey).data,
format: "der", format: "der",
@ -88,7 +118,10 @@ export class EdCrypto {
return new Uint8Array(bits).buffer.slice(0, length >> 3); return new Uint8Array(bits).buffer.slice(0, length >> 3);
} }
public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public static async exportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": case "jwk":
return JsonSerializer.toJSON(key); return JsonSerializer.toJSON(key);
@ -96,60 +129,114 @@ export class EdCrypto {
case "spki": case "spki":
return new Uint8Array(key.data).buffer; return new Uint8Array(key.data).buffer;
case "raw": { case "raw": {
const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo); const publicKeyInfo = AsnParser.parse(
key.data,
core.asn1.PublicKeyInfo
);
return publicKeyInfo.publicKey; return publicKeyInfo.publicKey;
} }
default: default:
throw new core.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'"); throw new core.OperationError(
"format: Must be 'jwk', 'raw', pkcs8' or 'spki'"
);
} }
} }
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public static async importKey(
format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": { case "jwk": {
const jwk = keyData as JsonWebKey; const jwk = keyData as JsonWebKey;
if (jwk.d) { if (jwk.d) {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.CurvePrivateKey }); const asnKey = JsonParser.fromJSON(keyData, {
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); targetSchema: core.asn1.CurvePrivateKey,
});
return this.importPrivateKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} else { } else {
if (!jwk.x) { if (!jwk.x) {
throw new TypeError("keyData: Cannot get required 'x' filed"); throw new TypeError("keyData: Cannot get required 'x' filed");
} }
return this.importPublicKey(Convert.FromBase64Url(jwk.x), algorithm, extractable, keyUsages); return this.importPublicKey(
Convert.FromBase64Url(jwk.x),
algorithm,
extractable,
keyUsages
);
} }
} }
case "raw": { case "raw": {
return this.importPublicKey(keyData as ArrayBuffer, algorithm, extractable, keyUsages); return this.importPublicKey(
keyData as ArrayBuffer,
algorithm,
extractable,
keyUsages
);
} }
case "spki": { case "spki": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo); const keyInfo = AsnParser.parse(
return this.importPublicKey(keyInfo.publicKey, algorithm, extractable, keyUsages); new Uint8Array(keyData as ArrayBuffer),
core.asn1.PublicKeyInfo
);
return this.importPublicKey(
keyInfo.publicKey,
algorithm,
extractable,
keyUsages
);
} }
case "pkcs8": { case "pkcs8": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo); const keyInfo = AsnParser.parse(
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.CurvePrivateKey); new Uint8Array(keyData as ArrayBuffer),
core.asn1.PrivateKeyInfo
);
const asnKey = AsnParser.parse(
keyInfo.privateKey,
core.asn1.CurvePrivateKey
);
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
} }
default: default:
throw new core.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"); throw new core.OperationError(
"format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"
);
} }
} }
protected static importPrivateKey(asnKey: core.asn1.CurvePrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) { protected static importPrivateKey(
asnKey: core.asn1.CurvePrivateKey,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
) {
const key = new EdPrivateKey(); const key = new EdPrivateKey();
key.fromJSON({ key.fromJSON({
crv: algorithm.namedCurve, crv: algorithm.namedCurve,
d: Convert.ToBase64Url(asnKey.d), d: Convert.ToBase64Url(asnKey.d),
}); });
key.algorithm = Object.assign({}, algorithm) as EcKeyAlgorithm; key.algorithm = Object.assign({}, algorithm) as EcKeyAlgorithm;
key.extractable = extractable; key.extractable = extractable;
key.usages = keyUsages; key.usages = keyUsages;
return key; return key;
} }
protected static async importPublicKey(asnKey: ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) { protected static async importPublicKey(
asnKey: ArrayBuffer,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
) {
const key = new EdPublicKey(); const key = new EdPublicKey();
key.fromJSON({ key.fromJSON({
crv: algorithm.namedCurve, crv: algorithm.namedCurve,
@ -162,5 +249,4 @@ export class EdCrypto {
return key; return key;
} }
} }

View File

@ -4,15 +4,19 @@ import { CryptoKey } from "../../keys";
import { getCryptoKey, setCryptoKey } from "../storage"; import { getCryptoKey, setCryptoKey } from "../storage";
export class EcdhEsProvider extends core.EcdhEsProvider { export class EcdhEsProvider extends core.EcdhEsProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { algorithm: EcKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await EdCrypto.generateKey( const keys = await EdCrypto.generateKey(
{ {
name: this.name, name: this.name,
namedCurve: algorithm.namedCurve.toUpperCase(), namedCurve: algorithm.namedCurve.toUpperCase(),
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as CryptoKey), privateKey: setCryptoKey(keys.privateKey as CryptoKey),
@ -20,18 +24,40 @@ export class EcdhEsProvider extends core.EcdhEsProvider {
}; };
} }
public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: core.CryptoKey, length: number): Promise<ArrayBuffer> { public async onDeriveBits(
const bits = await EdCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length); algorithm: EcdhKeyDeriveParams,
baseKey: core.CryptoKey,
length: number
): Promise<ArrayBuffer> {
const bits = await EdCrypto.deriveBits(
{ ...algorithm, public: getCryptoKey(algorithm.public) },
getCryptoKey(baseKey),
length
);
return bits; return bits;
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<ArrayBuffer | JsonWebKey> {
return EdCrypto.exportKey(format, getCryptoKey(key)); return EdCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: ArrayBuffer | JsonWebKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onImportKey(
const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); format: KeyFormat,
keyData: ArrayBuffer | JsonWebKey,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await EdCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
}
}

View File

@ -6,15 +6,19 @@ import { CryptoKey } from "../../keys";
import { getCryptoKey, setCryptoKey } from "../storage"; import { getCryptoKey, setCryptoKey } from "../storage";
export class EdDsaProvider extends core.EdDsaProvider { export class EdDsaProvider extends core.EdDsaProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { algorithm: EcKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await EdCrypto.generateKey( const keys = await EdCrypto.generateKey(
{ {
name: this.name, name: this.name,
namedCurve: algorithm.namedCurve.replace(/^ed/i, "Ed"), namedCurve: algorithm.namedCurve.replace(/^ed/i, "Ed"),
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as CryptoKey), privateKey: setCryptoKey(keys.privateKey as CryptoKey),
@ -22,21 +26,53 @@ export class EdDsaProvider extends core.EdDsaProvider {
}; };
} }
public async onSign(algorithm: EcdsaParams, key: CryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onSign(
return EdCrypto.sign(algorithm, getCryptoKey(key) as EdPrivateKey, new Uint8Array(data)); algorithm: EcdsaParams,
key: CryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return EdCrypto.sign(
algorithm,
getCryptoKey(key) as EdPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify(algorithm: EcdsaParams, key: CryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> { public async onVerify(
return EdCrypto.verify(algorithm, getCryptoKey(key) as EdPublicKey, new Uint8Array(signature), new Uint8Array(data)); algorithm: EcdsaParams,
key: CryptoKey,
signature: ArrayBuffer,
data: ArrayBuffer
): Promise<boolean> {
return EdCrypto.verify(
algorithm,
getCryptoKey(key) as EdPublicKey,
new Uint8Array(signature),
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<ArrayBuffer | JsonWebKey> {
return EdCrypto.exportKey(format, getCryptoKey(key)); return EdCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: ArrayBuffer | JsonWebKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> { public async onImportKey(
const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); format: KeyFormat,
keyData: ArrayBuffer | JsonWebKey,
algorithm: EcKeyImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<core.CryptoKey> {
const key = await EdCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
}
}

View File

@ -3,22 +3,24 @@ import * as core from "webcrypto-core";
const edOIDs: { [key: string]: string } = { const edOIDs: { [key: string]: string } = {
// Ed448 // Ed448
[core.asn1.idEd448]: "Ed448", [core.asn1.idEd448]: "Ed448",
"ed448": core.asn1.idEd448, ed448: core.asn1.idEd448,
// X448 // X448
[core.asn1.idX448]: "X448", [core.asn1.idX448]: "X448",
"x448": core.asn1.idX448, x448: core.asn1.idX448,
// Ed25519 // Ed25519
[core.asn1.idEd25519]: "Ed25519", [core.asn1.idEd25519]: "Ed25519",
"ed25519": core.asn1.idEd25519, ed25519: core.asn1.idEd25519,
// X25519 // X25519
[core.asn1.idX25519]: "X25519", [core.asn1.idX25519]: "X25519",
"x25519": core.asn1.idX25519, x25519: core.asn1.idX25519,
}; };
export function getNamedCurveByOid(oid: string) { export function getNamedCurveByOid(oid: string) {
const namedCurve = edOIDs[oid]; const namedCurve = edOIDs[oid];
if (!namedCurve) { if (!namedCurve) {
throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`); throw new core.OperationError(
`Cannot convert OID(${oid}) to WebCrypto named curve`
);
} }
return namedCurve; return namedCurve;
} }
@ -26,7 +28,9 @@ export function getNamedCurveByOid(oid: string) {
export function getOidByNamedCurve(namedCurve: string) { export function getOidByNamedCurve(namedCurve: string) {
const oid = edOIDs[namedCurve.toLowerCase()]; const oid = edOIDs[namedCurve.toLowerCase()];
if (!oid) { if (!oid) {
throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); throw new core.OperationError(
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
);
} }
return oid; return oid;
} }

View File

@ -1,5 +1,10 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema"; import {
IJsonConvertible,
JsonParser,
JsonSerializer,
} from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { getOidByNamedCurve } from "./helper"; import { getOidByNamedCurve } from "./helper";
import { AsymmetricKey } from "../../keys"; import { AsymmetricKey } from "../../keys";
@ -28,17 +33,20 @@ export class EdPrivateKey extends AsymmetricKey implements IJsonConvertible {
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
if (!json.crv) { if (!json.crv) {
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); throw new core.OperationError(
`Cannot get named curve from JWK. Property 'crv' is required`
);
} }
const keyInfo = new core.asn1.PrivateKeyInfo(); const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = getOidByNamedCurve(json.crv); keyInfo.privateKeyAlgorithm.algorithm = getOidByNamedCurve(json.crv);
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.CurvePrivateKey }); const key = JsonParser.fromJSON(json, {
targetSchema: core.asn1.CurvePrivateKey,
});
keyInfo.privateKey = AsnSerializer.serialize(key); keyInfo.privateKey = AsnSerializer.serialize(key);
this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
return this; return this;
} }
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible } from "@peculiar/json-schema"; import { IJsonConvertible } from "@peculiar/json-schema";
import { Convert } from "pvtsutils"; import { Convert } from "pvtsutils";
@ -6,7 +7,6 @@ import { getOidByNamedCurve } from "./helper";
import { AsymmetricKey } from "../../keys/asymmetric"; import { AsymmetricKey } from "../../keys/asymmetric";
export class EdPublicKey extends AsymmetricKey implements IJsonConvertible { export class EdPublicKey extends AsymmetricKey implements IJsonConvertible {
public readonly type = "public" as const; public readonly type = "public" as const;
public override algorithm!: EcKeyAlgorithm; public override algorithm!: EcKeyAlgorithm;
@ -26,16 +26,20 @@ export class EdPublicKey extends AsymmetricKey implements IJsonConvertible {
}; };
return Object.assign(json, { return Object.assign(json, {
x: Convert.ToBase64Url(key) x: Convert.ToBase64Url(key),
}); });
} }
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
if (!json.crv) { if (!json.crv) {
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); throw new core.OperationError(
`Cannot get named curve from JWK. Property 'crv' is required`
);
} }
if (!json.x) { if (!json.x) {
throw new core.OperationError(`Cannot get property from JWK. Property 'x' is required`); throw new core.OperationError(
`Cannot get property from JWK. Property 'x' is required`
);
} }
const keyInfo = new core.asn1.PublicKeyInfo(); const keyInfo = new core.asn1.PublicKeyInfo();

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { BufferSourceConverter, CryptoKey } from "webcrypto-core"; import { BufferSourceConverter, CryptoKey } from "webcrypto-core";
@ -5,10 +6,15 @@ import { HkdfCryptoKey } from "./key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class HkdfProvider extends core.HkdfProvider { export class HkdfProvider extends core.HkdfProvider {
public async onImportKey(
public async onImportKey(format: KeyFormat, keyData: ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { format: KeyFormat,
keyData: ArrayBuffer,
algorithm: HmacImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
if (format.toLowerCase() !== "raw") { if (format.toLowerCase() !== "raw") {
throw new core.OperationError("Operation not supported"); throw new core.OperationError("Operation not supported");
} }
const key: HkdfCryptoKey = new HkdfCryptoKey(); const key: HkdfCryptoKey = new HkdfCryptoKey();
@ -19,24 +25,30 @@ export class HkdfProvider extends core.HkdfProvider {
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onDeriveBits(params: HkdfParams, baseKey: HkdfCryptoKey, length: number): Promise<ArrayBuffer> { public async onDeriveBits(
params: HkdfParams,
baseKey: HkdfCryptoKey,
length: number
): Promise<ArrayBuffer> {
const hash = (params.hash as Algorithm).name.replace("-", ""); const hash = (params.hash as Algorithm).name.replace("-", "");
const hashLength = crypto.createHash(hash).digest().length; const hashLength = crypto.createHash(hash).digest().length;
const byteLength = length / 8; const byteLength = length / 8;
const info = BufferSourceConverter.toUint8Array(params.info); const info = BufferSourceConverter.toUint8Array(params.info);
const PRK = crypto.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt)) const PRK = crypto
.update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data)) .createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
.digest(); .update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data))
.digest();
const blocks = [Buffer.alloc(0)]; const blocks = [Buffer.alloc(0)];
const blockCount = Math.ceil(byteLength / hashLength) + 1; // Includes empty buffer const blockCount = Math.ceil(byteLength / hashLength) + 1; // Includes empty buffer
for (let i = 1; i < blockCount; ++i) { for (let i = 1; i < blockCount; ++i) {
blocks.push( blocks.push(
crypto.createHmac(hash, PRK) crypto
.update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])])) .createHmac(hash, PRK)
.digest(), .update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])]))
.digest()
); );
} }
@ -49,5 +61,4 @@ export class HkdfProvider extends core.HkdfProvider {
throw new TypeError("key: Is not HKDF CryptoKey"); throw new TypeError("key: Is not HKDF CryptoKey");
} }
} }
} }

View File

@ -1,7 +1,6 @@
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class HkdfCryptoKey extends CryptoKey { export class HkdfCryptoKey extends CryptoKey {
public override data!: Buffer; public override data!: Buffer;
public override algorithm!: KeyAlgorithm; public override algorithm!: KeyAlgorithm;

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
@ -6,12 +7,19 @@ import { ShaCrypto } from "../sha";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class HmacProvider extends core.HmacProvider { export class HmacProvider extends core.HmacProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { algorithm: HmacKeyGenParams,
const length = (algorithm.length || this.getDefaultLength((algorithm.hash as Algorithm).name)) >> 3 << 3; extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const length =
((algorithm.length ||
this.getDefaultLength((algorithm.hash as Algorithm).name)) >>
3) <<
3;
const key = new HmacCryptoKey(); const key = new HmacCryptoKey();
key.algorithm = { key.algorithm = {
...algorithm as any, ...(algorithm as any),
length, length,
name: this.name, name: this.name,
}; };
@ -22,23 +30,42 @@ export class HmacProvider extends core.HmacProvider {
return setCryptoKey(key); return setCryptoKey(key);
} }
public override async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onSign(
algorithm: Algorithm,
key: HmacCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash); const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash);
const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data) const hmac = crypto
.update(Buffer.from(data)).digest(); .createHmac(cryptoAlg, getCryptoKey(key).data)
.update(Buffer.from(data))
.digest();
return new Uint8Array(hmac).buffer; return new Uint8Array(hmac).buffer;
} }
public override async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> { public override async onVerify(
algorithm: Algorithm,
key: HmacCryptoKey,
signature: ArrayBuffer,
data: ArrayBuffer
): Promise<boolean> {
const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash); const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash);
const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data) const hmac = crypto
.update(Buffer.from(data)).digest(); .createHmac(cryptoAlg, getCryptoKey(key).data)
.update(Buffer.from(data))
.digest();
return hmac.compare(Buffer.from(signature)) === 0; return hmac.compare(Buffer.from(signature)) === 0;
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: HmacImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
let key: HmacCryptoKey; let key: HmacCryptoKey;
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
@ -64,7 +91,10 @@ export class HmacProvider extends core.HmacProvider {
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: HmacCryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": case "jwk":
return JsonSerializer.toJSON(getCryptoKey(key)); return JsonSerializer.toJSON(getCryptoKey(key));
@ -81,5 +111,4 @@ export class HmacProvider extends core.HmacProvider {
throw new TypeError("key: Is not HMAC CryptoKey"); throw new TypeError("key: Is not HMAC CryptoKey");
} }
} }
} }

View File

@ -3,7 +3,6 @@ import { JsonBase64UrlConverter } from "../../converters";
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class HmacCryptoKey extends CryptoKey { export class HmacCryptoKey extends CryptoKey {
@JsonProp({ name: "k", converter: JsonBase64UrlConverter }) @JsonProp({ name: "k", converter: JsonBase64UrlConverter })
public override data!: Buffer; public override data!: Buffer;
@ -19,5 +18,4 @@ export class HmacCryptoKey extends CryptoKey {
protected override set alg(value: string) { protected override set alg(value: string) {
// nothing, cause set is needed for json-schema, but is not used by module // nothing, cause set is needed for json-schema, but is not used by module
} }
} }

View File

@ -1,4 +1,3 @@
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class PbkdfCryptoKey extends CryptoKey { export class PbkdfCryptoKey extends CryptoKey {}
}

View File

@ -1,25 +1,42 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { PbkdfCryptoKey } from "./key"; import { PbkdfCryptoKey } from "./key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class Pbkdf2Provider extends core.Pbkdf2Provider { export class Pbkdf2Provider extends core.Pbkdf2Provider {
public async onDeriveBits(
public async onDeriveBits(algorithm: Pbkdf2Params, baseKey: PbkdfCryptoKey, length: number): Promise<ArrayBuffer> { algorithm: Pbkdf2Params,
baseKey: PbkdfCryptoKey,
length: number
): Promise<ArrayBuffer> {
return new Promise<ArrayBuffer>((resolve, reject) => { return new Promise<ArrayBuffer>((resolve, reject) => {
const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt); const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt);
const hash = (algorithm.hash as Algorithm).name.replace("-", ""); const hash = (algorithm.hash as Algorithm).name.replace("-", "");
crypto.pbkdf2(getCryptoKey(baseKey).data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => { crypto.pbkdf2(
if (err) { getCryptoKey(baseKey).data,
reject(err); Buffer.from(salt),
} else { algorithm.iterations,
resolve(new Uint8Array(derivedBits).buffer); length >> 3,
hash,
(err, derivedBits) => {
if (err) {
reject(err);
} else {
resolve(new Uint8Array(derivedBits).buffer);
}
} }
}); );
}); });
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: Algorithm,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
if (format === "raw") { if (format === "raw") {
const key = new PbkdfCryptoKey(); const key = new PbkdfCryptoKey();
key.data = Buffer.from(keyData as ArrayBuffer); key.data = Buffer.from(keyData as ArrayBuffer);
@ -37,5 +54,4 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider {
throw new TypeError("key: Is not PBKDF CryptoKey"); throw new TypeError("key: Is not PBKDF CryptoKey");
} }
} }
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
@ -14,20 +15,27 @@ interface INodeCryptoSignOptions {
} }
export class RsaCrypto { export class RsaCrypto {
public static publicKeyUsages = ["verify", "encrypt", "wrapKey"]; public static publicKeyUsages = ["verify", "encrypt", "wrapKey"];
public static privateKeyUsages = ["sign", "decrypt", "unwrapKey"]; public static privateKeyUsages = ["sign", "decrypt", "unwrapKey"];
public static async generateKey(algorithm: RsaHashedKeyGenParams | RsaKeyGenParams, extractable: boolean, keyUsages: string[]): Promise<CryptoKeyPair> { public static async generateKey(
algorithm: RsaHashedKeyGenParams | RsaKeyGenParams,
extractable: boolean,
keyUsages: string[]
): Promise<CryptoKeyPair> {
const privateKey = new RsaPrivateKey(); const privateKey = new RsaPrivateKey();
privateKey.algorithm = algorithm as RsaHashedKeyAlgorithm; privateKey.algorithm = algorithm as RsaHashedKeyAlgorithm;
privateKey.extractable = extractable; privateKey.extractable = extractable;
privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1) as KeyUsage[]; privateKey.usages = keyUsages.filter(
(usage) => this.privateKeyUsages.indexOf(usage) !== -1
) as KeyUsage[];
const publicKey = new RsaPublicKey(); const publicKey = new RsaPublicKey();
publicKey.algorithm = algorithm as RsaHashedKeyAlgorithm; publicKey.algorithm = algorithm as RsaHashedKeyAlgorithm;
publicKey.extractable = true; publicKey.extractable = true;
publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1) as KeyUsage[]; publicKey.usages = keyUsages.filter(
(usage) => this.publicKeyUsages.indexOf(usage) !== -1
) as KeyUsage[];
const publicExponent = Buffer.concat([ const publicExponent = Buffer.concat([
Buffer.alloc(4 - algorithm.publicExponent.byteLength, 0), Buffer.alloc(4 - algorithm.publicExponent.byteLength, 0),
@ -58,7 +66,10 @@ export class RsaCrypto {
return res; return res;
} }
public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public static async exportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": case "jwk":
return JsonSerializer.toJSON(key); return JsonSerializer.toJSON(key);
@ -66,38 +77,78 @@ export class RsaCrypto {
case "spki": case "spki":
return new Uint8Array(key.data).buffer; return new Uint8Array(key.data).buffer;
default: default:
throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); throw new core.OperationError(
"format: Must be 'jwk', 'pkcs8' or 'spki'"
);
} }
} }
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public static async importKey(
format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
switch (format.toLowerCase()) { switch (format.toLowerCase()) {
case "jwk": { case "jwk": {
const jwk = keyData as JsonWebKey; const jwk = keyData as JsonWebKey;
if (jwk.d) { if (jwk.d) {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPrivateKey }); const asnKey = JsonParser.fromJSON(keyData, {
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); targetSchema: core.asn1.RsaPrivateKey,
});
return this.importPrivateKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} else { } else {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPublicKey }); const asnKey = JsonParser.fromJSON(keyData, {
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); targetSchema: core.asn1.RsaPublicKey,
});
return this.importPublicKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} }
} }
case "spki": { case "spki": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo); const keyInfo = AsnParser.parse(
const asnKey = AsnParser.parse(keyInfo.publicKey, core.asn1.RsaPublicKey); new Uint8Array(keyData as ArrayBuffer),
core.asn1.PublicKeyInfo
);
const asnKey = AsnParser.parse(
keyInfo.publicKey,
core.asn1.RsaPublicKey
);
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
} }
case "pkcs8": { case "pkcs8": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo); const keyInfo = AsnParser.parse(
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.RsaPrivateKey); new Uint8Array(keyData as ArrayBuffer),
core.asn1.PrivateKeyInfo
);
const asnKey = AsnParser.parse(
keyInfo.privateKey,
core.asn1.RsaPrivateKey
);
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
} }
default: default:
throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); throw new core.OperationError(
"format: Must be 'jwk', 'pkcs8' or 'spki'"
);
} }
} }
public static async sign(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array): Promise<ArrayBuffer> { public static async sign(
algorithm: Algorithm,
key: RsaPrivateKey,
data: Uint8Array
): Promise<ArrayBuffer> {
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "RSA-PSS": case "RSA-PSS":
case "RSASSA-PKCS1-V1_5": case "RSASSA-PKCS1-V1_5":
@ -107,7 +158,12 @@ export class RsaCrypto {
} }
} }
public static async verify(algorithm: Algorithm, key: RsaPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> { public static async verify(
algorithm: Algorithm,
key: RsaPublicKey,
signature: Uint8Array,
data: Uint8Array
): Promise<boolean> {
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "RSA-PSS": case "RSA-PSS":
case "RSASSA-PKCS1-V1_5": case "RSASSA-PKCS1-V1_5":
@ -117,7 +173,11 @@ export class RsaCrypto {
} }
} }
public static async encrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array): Promise<ArrayBuffer> { public static async encrypt(
algorithm: RsaOaepParams,
key: RsaPublicKey,
data: Uint8Array
): Promise<ArrayBuffer> {
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "RSA-OAEP": case "RSA-OAEP":
return this.encryptOAEP(algorithm, key, data); return this.encryptOAEP(algorithm, key, data);
@ -126,7 +186,11 @@ export class RsaCrypto {
} }
} }
public static async decrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array): Promise<ArrayBuffer> { public static async decrypt(
algorithm: RsaOaepParams,
key: RsaPrivateKey,
data: Uint8Array
): Promise<ArrayBuffer> {
switch (algorithm.name.toUpperCase()) { switch (algorithm.name.toUpperCase()) {
case "RSA-OAEP": case "RSA-OAEP":
return this.decryptOAEP(algorithm, key, data); return this.decryptOAEP(algorithm, key, data);
@ -135,7 +199,12 @@ export class RsaCrypto {
} }
} }
protected static importPrivateKey(asnKey: core.asn1.RsaPrivateKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) { protected static importPrivateKey(
asnKey: core.asn1.RsaPrivateKey,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
) {
const keyInfo = new core.asn1.PrivateKeyInfo(); const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.privateKeyAlgorithm.parameters = null; keyInfo.privateKeyAlgorithm.parameters = null;
@ -153,7 +222,12 @@ export class RsaCrypto {
return key; return key;
} }
protected static importPublicKey(asnKey: core.asn1.RsaPublicKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) { protected static importPublicKey(
asnKey: core.asn1.RsaPublicKey,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
) {
const keyInfo = new core.asn1.PublicKeyInfo(); const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.publicKeyAlgorithm.parameters = null; keyInfo.publicKeyAlgorithm.parameters = null;
@ -192,13 +266,19 @@ export class RsaCrypto {
} }
} }
protected static signRsa(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array) { protected static signRsa(
algorithm: Algorithm,
key: RsaPrivateKey,
data: Uint8Array
) {
const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); const cryptoAlg = this.getCryptoAlgorithm(key.algorithm);
const signer = crypto.createSign(cryptoAlg); const signer = crypto.createSign(cryptoAlg);
signer.update(Buffer.from(data)); signer.update(Buffer.from(data));
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
const options: INodeCryptoSignOptions = { const options: INodeCryptoSignOptions = {
key: key.pem, key: key.pem,
@ -212,13 +292,20 @@ export class RsaCrypto {
return new Uint8Array(signature).buffer; return new Uint8Array(signature).buffer;
} }
protected static verifySSA(algorithm: Algorithm, key: RsaPublicKey, data: Uint8Array, signature: Uint8Array) { protected static verifySSA(
algorithm: Algorithm,
key: RsaPublicKey,
data: Uint8Array,
signature: Uint8Array
) {
const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); const cryptoAlg = this.getCryptoAlgorithm(key.algorithm);
const signer = crypto.createVerify(cryptoAlg); const signer = crypto.createVerify(cryptoAlg);
signer.update(Buffer.from(data)); signer.update(Buffer.from(data));
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const options: INodeCryptoSignOptions = { const options: INodeCryptoSignOptions = {
key: key.pem, key: key.pem,
@ -232,9 +319,15 @@ export class RsaCrypto {
return ok; return ok;
} }
protected static encryptOAEP(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array) { protected static encryptOAEP(
algorithm: RsaOaepParams,
key: RsaPublicKey,
data: Uint8Array
) {
const options: crypto.RsaPublicKey = { const options: crypto.RsaPublicKey = {
key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`, key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
"base64"
)}\n-----END PUBLIC KEY-----`,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
}; };
if (algorithm.label) { if (algorithm.label) {
@ -244,9 +337,15 @@ export class RsaCrypto {
return new Uint8Array(crypto.publicEncrypt(options, data)).buffer; return new Uint8Array(crypto.publicEncrypt(options, data)).buffer;
} }
protected static decryptOAEP(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array) { protected static decryptOAEP(
algorithm: RsaOaepParams,
key: RsaPrivateKey,
data: Uint8Array
) {
const options: crypto.RsaPrivateKey = { const options: crypto.RsaPrivateKey = {
key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`, key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
"base64"
)}\n-----END PRIVATE KEY-----`,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
}; };
if (algorithm.label) { if (algorithm.label) {
@ -255,5 +354,4 @@ export class RsaCrypto {
return new Uint8Array(crypto.privateDecrypt(options, data)).buffer; return new Uint8Array(crypto.privateDecrypt(options, data)).buffer;
} }
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
@ -27,7 +28,9 @@ export class RsaPrivateKey extends AsymmetricKey {
} }
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPrivateKey }); const key = JsonParser.fromJSON(json, {
targetSchema: core.asn1.RsaPrivateKey,
});
const keyInfo = new core.asn1.PrivateKeyInfo(); const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
@ -36,5 +39,4 @@ export class RsaPrivateKey extends AsymmetricKey {
this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
} }
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
@ -27,7 +28,9 @@ export class RsaPublicKey extends AsymmetricKey {
} }
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPublicKey }); const key = JsonParser.fromJSON(json, {
targetSchema: core.asn1.RsaPublicKey,
});
const keyInfo = new core.asn1.PublicKeyInfo(); const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";

View File

@ -7,21 +7,25 @@ import { RsaPublicKey } from "./public_key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class RsaEsProvider extends core.ProviderCrypto { export class RsaEsProvider extends core.ProviderCrypto {
public name = "RSAES-PKCS1-v1_5"; public name = "RSAES-PKCS1-v1_5";
public usages = { public usages = {
publicKey: ["encrypt", "wrapKey"] as core.KeyUsages, publicKey: ["encrypt", "wrapKey"] as core.KeyUsages,
privateKey: ["decrypt", "unwrapKey"] as core.KeyUsages, privateKey: ["decrypt", "unwrapKey"] as core.KeyUsages,
}; };
public override async onGenerateKey(algorithm: RsaKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { public override async onGenerateKey(
algorithm: RsaKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await RsaCrypto.generateKey( const keys = await RsaCrypto.generateKey(
{ {
...algorithm, ...algorithm,
name: this.name, name: this.name,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
@ -32,7 +36,12 @@ export class RsaEsProvider extends core.ProviderCrypto {
public override checkGenerateKeyParams(algorithm: RsaKeyGenParams) { public override checkGenerateKeyParams(algorithm: RsaKeyGenParams) {
// public exponent // public exponent
this.checkRequiredProperty(algorithm, "publicExponent"); this.checkRequiredProperty(algorithm, "publicExponent");
if (!(algorithm.publicExponent && algorithm.publicExponent instanceof Uint8Array)) { if (
!(
algorithm.publicExponent &&
algorithm.publicExponent instanceof Uint8Array
)
) {
throw new TypeError("publicExponent: Missing or not a Uint8Array"); throw new TypeError("publicExponent: Missing or not a Uint8Array");
} }
const publicExponent = Convert.ToBase64(algorithm.publicExponent); const publicExponent = Convert.ToBase64(algorithm.publicExponent);
@ -52,31 +61,59 @@ export class RsaEsProvider extends core.ProviderCrypto {
} }
} }
public override async onEncrypt(algorithm: Algorithm, key: RsaPublicKey, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onEncrypt(
algorithm: Algorithm,
key: RsaPublicKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
const options = this.toCryptoOptions(key); const options = this.toCryptoOptions(key);
const enc = crypto.publicEncrypt(options, new Uint8Array(data)); const enc = crypto.publicEncrypt(options, new Uint8Array(data));
return new Uint8Array(enc).buffer; return new Uint8Array(enc).buffer;
} }
public override async onDecrypt(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDecrypt(
algorithm: Algorithm,
key: RsaPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
const options = this.toCryptoOptions(key); const options = this.toCryptoOptions(key);
const dec = crypto.privateDecrypt(options, new Uint8Array(data)); const dec = crypto.privateDecrypt(options, new Uint8Array(data));
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public override async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public override async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public override async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public override async onImportKey(
const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await RsaCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
super.checkCryptoKey(key, keyUsage); super.checkCryptoKey(key, keyUsage);
const internalKey = getCryptoKey(key); const internalKey = getCryptoKey(key);
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { if (
!(
internalKey instanceof RsaPrivateKey ||
internalKey instanceof RsaPublicKey
)
) {
throw new TypeError("key: Is not RSA CryptoKey"); throw new TypeError("key: Is not RSA CryptoKey");
} }
} }
@ -86,7 +123,9 @@ export class RsaEsProvider extends core.ProviderCrypto {
private toCryptoOptions(key: RsaPrivateKey | RsaPublicKey) { private toCryptoOptions(key: RsaPrivateKey | RsaPublicKey) {
const type = key.type.toUpperCase(); const type = key.type.toUpperCase();
return { return {
key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`, key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString(
"base64"
)}\n-----END ${type} KEY-----`,
padding: crypto.constants.RSA_PKCS1_PADDING, padding: crypto.constants.RSA_PKCS1_PADDING,
}; };
} }

View File

@ -1,3 +1,4 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { RsaCrypto } from "./crypto"; import { RsaCrypto } from "./crypto";
@ -14,23 +15,31 @@ import { setCryptoKey, getCryptoKey } from "../storage";
*/ */
export class RsaOaepProvider extends core.RsaOaepProvider { export class RsaOaepProvider extends core.RsaOaepProvider {
public async onGenerateKey(
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { algorithm: RsaHashedKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await RsaCrypto.generateKey( const keys = await RsaCrypto.generateKey(
{ {
...algorithm, ...algorithm,
name: this.name, name: this.name,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
}; };
} }
public async onEncrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onEncrypt(
algorithm: RsaOaepParams,
key: RsaPublicKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
const internalKey = getCryptoKey(key) as RsaPublicKey; const internalKey = getCryptoKey(key) as RsaPublicKey;
const dataView = new Uint8Array(data); const dataView = new Uint8Array(data);
const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3);
@ -48,37 +57,59 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
dataBlock.set(dataView, hashSize + psLength + 1); dataBlock.set(dataView, hashSize + psLength + 1);
const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", "")) const labelHash = crypto
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0))) .createHash(internalKey.algorithm.hash.name.replace("-", ""))
.update(
core.BufferSourceConverter.toUint8Array(
algorithm.label || new Uint8Array(0)
)
)
.digest(); .digest();
dataBlock.set(labelHash, 0); dataBlock.set(labelHash, 0);
dataBlock[hashSize + psLength] = 1; dataBlock[hashSize + psLength] = 1;
crypto.randomFillSync(seed); crypto.randomFillSync(seed);
const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length); const dataBlockMask = this.mgf1(
internalKey.algorithm.hash,
seed,
dataBlock.length
);
for (let i = 0; i < dataBlock.length; i++) { for (let i = 0; i < dataBlock.length; i++) {
dataBlock[i] ^= dataBlockMask[i]; dataBlock[i] ^= dataBlockMask[i];
} }
const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length); const seedMask = this.mgf1(
internalKey.algorithm.hash,
dataBlock,
seed.length
);
for (let i = 0; i < seed.length; i++) { for (let i = 0; i < seed.length; i++) {
seed[i] ^= seedMask[i]; seed[i] ^= seedMask[i];
} }
if (!internalKey.pem) { if (!internalKey.pem) {
internalKey.pem = `-----BEGIN PUBLIC KEY-----\n${internalKey.data.toString("base64")}\n-----END PUBLIC KEY-----`; internalKey.pem = `-----BEGIN PUBLIC KEY-----\n${internalKey.data.toString(
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const pkcs0 = crypto.publicEncrypt({ const pkcs0 = crypto.publicEncrypt(
key: internalKey.pem, {
padding: crypto.constants.RSA_NO_PADDING, key: internalKey.pem,
}, Buffer.from(message)); padding: crypto.constants.RSA_NO_PADDING,
},
Buffer.from(message)
);
return new Uint8Array(pkcs0).buffer; return new Uint8Array(pkcs0).buffer;
} }
public async onDecrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onDecrypt(
algorithm: RsaOaepParams,
key: RsaPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
const internalKey = getCryptoKey(key) as RsaPrivateKey; const internalKey = getCryptoKey(key) as RsaPrivateKey;
const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3);
const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3;
@ -89,13 +120,18 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
} }
if (!internalKey.pem) { if (!internalKey.pem) {
internalKey.pem = `-----BEGIN PRIVATE KEY-----\n${internalKey.data.toString("base64")}\n-----END PRIVATE KEY-----`; internalKey.pem = `-----BEGIN PRIVATE KEY-----\n${internalKey.data.toString(
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
let pkcs0 = crypto.privateDecrypt({ let pkcs0 = crypto.privateDecrypt(
key: internalKey.pem, {
padding: crypto.constants.RSA_NO_PADDING, key: internalKey.pem,
}, Buffer.from(data)); padding: crypto.constants.RSA_NO_PADDING,
},
Buffer.from(data)
);
const z = pkcs0[0]; const z = pkcs0[0];
const seed = pkcs0.subarray(1, hashSize + 1); const seed = pkcs0.subarray(1, hashSize + 1);
const dataBlock = pkcs0.subarray(hashSize + 1); const dataBlock = pkcs0.subarray(hashSize + 1);
@ -104,18 +140,31 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
throw new Error("Decryption failed"); throw new Error("Decryption failed");
} }
const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length); const seedMask = this.mgf1(
internalKey.algorithm.hash,
dataBlock,
seed.length
);
for (let i = 0; i < seed.length; i++) { for (let i = 0; i < seed.length; i++) {
seed[i] ^= seedMask[i]; seed[i] ^= seedMask[i];
} }
const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length); const dataBlockMask = this.mgf1(
internalKey.algorithm.hash,
seed,
dataBlock.length
);
for (let i = 0; i < dataBlock.length; i++) { for (let i = 0; i < dataBlock.length; i++) {
dataBlock[i] ^= dataBlockMask[i]; dataBlock[i] ^= dataBlockMask[i];
} }
const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", "")) const labelHash = crypto
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0))) .createHash(internalKey.algorithm.hash.name.replace("-", ""))
.update(
core.BufferSourceConverter.toUint8Array(
algorithm.label || new Uint8Array(0)
)
)
.digest(); .digest();
for (let i = 0; i < hashSize; i++) { for (let i = 0; i < hashSize; i++) {
if (labelHash[i] !== dataBlock[i]) { if (labelHash[i] !== dataBlock[i]) {
@ -142,19 +191,39 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
return new Uint8Array(pkcs0).buffer; return new Uint8Array(pkcs0).buffer;
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await RsaCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
super.checkCryptoKey(key, keyUsage); super.checkCryptoKey(key, keyUsage);
const internalKey = getCryptoKey(key); const internalKey = getCryptoKey(key);
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { if (
!(
internalKey instanceof RsaPrivateKey ||
internalKey instanceof RsaPublicKey
)
) {
throw new TypeError("key: Is not RSA CryptoKey"); throw new TypeError("key: Is not RSA CryptoKey");
} }
} }
@ -178,7 +247,8 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
const submask = mask.subarray(i * hashSize); const submask = mask.subarray(i * hashSize);
let chunk = crypto.createHash(algorithm.name.replace("-", "")) let chunk = crypto
.createHash(algorithm.name.replace("-", ""))
.update(seed) .update(seed)
.update(counter) .update(counter)
.digest() as Uint8Array; .digest() as Uint8Array;
@ -191,5 +261,4 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
return mask; return mask;
} }
} }

View File

@ -5,50 +5,98 @@ import { RsaPublicKey } from "./public_key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class RsaPssProvider extends core.RsaPssProvider { export class RsaPssProvider extends core.RsaPssProvider {
public override hashAlgorithms = [ public override hashAlgorithms = [
"SHA-1", "SHA-256", "SHA-384", "SHA-512", "SHA-1",
"shake128", "shake256", "SHA-256",
"SHA3-256", "SHA3-384", "SHA3-512"]; "SHA-384",
"SHA-512",
"shake128",
"shake256",
"SHA3-256",
"SHA3-384",
"SHA3-512",
];
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> { public async onGenerateKey(
algorithm: RsaHashedKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKeyPair> {
const keys = await RsaCrypto.generateKey( const keys = await RsaCrypto.generateKey(
{ {
...algorithm, ...algorithm,
name: this.name, name: this.name,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
}; };
} }
public async onSign(algorithm: RsaPssParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onSign(
return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data)); algorithm: RsaPssParams,
key: RsaPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return RsaCrypto.sign(
algorithm,
getCryptoKey(key) as RsaPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify(algorithm: RsaPssParams, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> { public async onVerify(
return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data)); algorithm: RsaPssParams,
key: RsaPublicKey,
signature: ArrayBuffer,
data: ArrayBuffer
): Promise<boolean> {
return RsaCrypto.verify(
algorithm,
getCryptoKey(key) as RsaPublicKey,
new Uint8Array(signature),
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await RsaCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
super.checkCryptoKey(key, keyUsage); super.checkCryptoKey(key, keyUsage);
const internalKey = getCryptoKey(key); const internalKey = getCryptoKey(key);
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { if (
!(
internalKey instanceof RsaPrivateKey ||
internalKey instanceof RsaPublicKey
)
) {
throw new TypeError("key: Is not RSA CryptoKey"); throw new TypeError("key: Is not RSA CryptoKey");
} }
} }
} }

View File

@ -5,50 +5,98 @@ import { RsaPublicKey } from "./public_key";
import { setCryptoKey, getCryptoKey } from "../storage"; import { setCryptoKey, getCryptoKey } from "../storage";
export class RsaSsaProvider extends core.RsaSsaProvider { export class RsaSsaProvider extends core.RsaSsaProvider {
public override hashAlgorithms = [ public override hashAlgorithms = [
"SHA-1", "SHA-256", "SHA-384", "SHA-512", "SHA-1",
"shake128", "shake256", "SHA-256",
"SHA3-256", "SHA3-384", "SHA3-512"]; "SHA-384",
"SHA-512",
"shake128",
"shake256",
"SHA3-256",
"SHA3-384",
"SHA3-512",
];
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<globalThis.CryptoKeyPair> { public async onGenerateKey(
algorithm: RsaHashedKeyGenParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<globalThis.CryptoKeyPair> {
const keys = await RsaCrypto.generateKey( const keys = await RsaCrypto.generateKey(
{ {
...algorithm, ...algorithm,
name: this.name, name: this.name,
}, },
extractable, extractable,
keyUsages); keyUsages
);
return { return {
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
}; };
} }
public async onSign(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> { public async onSign(
return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data)); algorithm: Algorithm,
key: RsaPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return RsaCrypto.sign(
algorithm,
getCryptoKey(key) as RsaPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify(algorithm: Algorithm, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> { public async onVerify(
return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data)); algorithm: Algorithm,
key: RsaPublicKey,
signature: ArrayBuffer,
data: ArrayBuffer
): Promise<boolean> {
return RsaCrypto.verify(
algorithm,
getCryptoKey(key) as RsaPublicKey,
new Uint8Array(signature),
new Uint8Array(data)
);
} }
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> { public async onExportKey(
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> { public async onImportKey(
const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages); format: KeyFormat,
keyData: JsonWebKey | ArrayBuffer,
algorithm: RsaHashedImportParams,
extractable: boolean,
keyUsages: KeyUsage[]
): Promise<CryptoKey> {
const key = await RsaCrypto.importKey(
format,
keyData,
{ ...algorithm, name: this.name },
extractable,
keyUsages
);
return setCryptoKey(key); return setCryptoKey(key);
} }
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
super.checkCryptoKey(key, keyUsage); super.checkCryptoKey(key, keyUsage);
const internalKey = getCryptoKey(key); const internalKey = getCryptoKey(key);
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { if (
!(
internalKey instanceof RsaPrivateKey ||
internalKey instanceof RsaPublicKey
)
) {
throw new TypeError("key: Is not RSA CryptoKey"); throw new TypeError("key: Is not RSA CryptoKey");
} }
} }
} }

View File

@ -1,7 +1,7 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
export class ShaCrypto { export class ShaCrypto {
/** /**
* Returns size of the hash algorithm in bits * Returns size of the hash algorithm in bits
* @param algorithm Hash algorithm * @param algorithm Hash algorithm
@ -53,9 +53,7 @@ export class ShaCrypto {
public static digest(algorithm: Algorithm, data: ArrayBuffer) { public static digest(algorithm: Algorithm, data: ArrayBuffer) {
const hashAlg = this.getAlgorithmName(algorithm); const hashAlg = this.getAlgorithmName(algorithm);
const hash = crypto.createHash(hashAlg) const hash = crypto.createHash(hashAlg).update(Buffer.from(data)).digest();
.update(Buffer.from(data)).digest();
return new Uint8Array(hash).buffer; return new Uint8Array(hash).buffer;
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha3256Provider extends core.ProviderCrypto {
public name = "SHA3-256"; public name = "SHA3-256";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha3384Provider extends core.ProviderCrypto {
public name = "SHA3-384"; public name = "SHA3-384";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha3512Provider extends core.ProviderCrypto {
public name = "SHA3-512"; public name = "SHA3-512";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha1Provider extends core.ProviderCrypto {
public name = "SHA-1"; public name = "SHA-1";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha256Provider extends core.ProviderCrypto {
public name = "SHA-256"; public name = "SHA-256";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha384Provider extends core.ProviderCrypto {
public name = "SHA-384"; public name = "SHA-384";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -5,8 +5,10 @@ export class Sha512Provider extends core.ProviderCrypto {
public name = "SHA-512"; public name = "SHA-512";
public usages = []; public usages = [];
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> { public override async onDigest(
algorithm: Algorithm,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShaCrypto.digest(algorithm, data); return ShaCrypto.digest(algorithm, data);
} }
} }

View File

@ -1,13 +1,19 @@
import { Buffer } from "buffer";
import crypto from "crypto"; import crypto from "crypto";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
export class ShakeCrypto { export class ShakeCrypto {
public static digest(
public static digest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer) { algorithm: Required<core.ShakeParams>,
const hash = crypto.createHash(algorithm.name.toLowerCase(), {outputLength: algorithm.length}) data: ArrayBuffer
.update(Buffer.from(data)).digest(); ) {
const hash = crypto
.createHash(algorithm.name.toLowerCase(), {
outputLength: algorithm.length,
})
.update(Buffer.from(data))
.digest();
return new Uint8Array(hash).buffer; return new Uint8Array(hash).buffer;
} }
} }

View File

@ -2,9 +2,10 @@ import * as core from "webcrypto-core";
import { ShakeCrypto } from "./crypto"; import { ShakeCrypto } from "./crypto";
export class Shake128Provider extends core.Shake128Provider { export class Shake128Provider extends core.Shake128Provider {
public override async onDigest(
public override async onDigest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer): Promise<ArrayBuffer> { algorithm: Required<core.ShakeParams>,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShakeCrypto.digest(algorithm, data); return ShakeCrypto.digest(algorithm, data);
} }
} }

View File

@ -2,9 +2,10 @@ import * as core from "webcrypto-core";
import { ShakeCrypto } from "./crypto"; import { ShakeCrypto } from "./crypto";
export class Shake256Provider extends core.Shake256Provider { export class Shake256Provider extends core.Shake256Provider {
public override async onDigest(
public override async onDigest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer): Promise<ArrayBuffer> { algorithm: Required<core.ShakeParams>,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShakeCrypto.digest(algorithm, data); return ShakeCrypto.digest(algorithm, data);
} }
} }

View File

@ -12,7 +12,12 @@ export function getCryptoKey(key: core.CryptoKey) {
} }
export function setCryptoKey(value: InternalCryptoKey) { export function setCryptoKey(value: InternalCryptoKey) {
const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages); const key = core.CryptoKey.create(
value.algorithm,
value.type,
value.extractable,
value.usages
);
Object.freeze(key); Object.freeze(key);
keyStorage.set(key, value); keyStorage.set(key, value);

View File

@ -2,18 +2,34 @@ import * as crypto from "crypto";
import * as process from "process"; import * as process from "process";
import * as core from "webcrypto-core"; import * as core from "webcrypto-core";
import { import {
AesCbcProvider, AesCmacProvider, AesCtrProvider, AesEcbProvider, AesGcmProvider, AesKwProvider, AesCbcProvider,
AesCmacProvider,
AesCtrProvider,
AesEcbProvider,
AesGcmProvider,
AesKwProvider,
DesCbcProvider, DesCbcProvider,
DesEde3CbcProvider, EcdhProvider, DesEde3CbcProvider,
EcdsaProvider, HkdfProvider, EcdhProvider,
EcdsaProvider,
HkdfProvider,
EdDsaProvider, EdDsaProvider,
EcdhEsProvider, EcdhEsProvider,
HmacProvider, HmacProvider,
Pbkdf2Provider, Pbkdf2Provider,
RsaEsProvider, RsaOaepProvider, RsaPssProvider, RsaSsaProvider, RsaEsProvider,
Sha1Provider, Sha256Provider, Sha384Provider, Sha512Provider, RsaOaepProvider,
Shake128Provider, Shake256Provider, RsaPssProvider,
Sha3256Provider, Sha3384Provider, Sha3512Provider, RsaSsaProvider,
Sha1Provider,
Sha256Provider,
Sha384Provider,
Sha512Provider,
Shake128Provider,
Shake256Provider,
Sha3256Provider,
Sha3384Provider,
Sha3512Provider,
} from "./mechs"; } from "./mechs";
export class SubtleCrypto extends core.SubtleCrypto { export class SubtleCrypto extends core.SubtleCrypto {