Compare commits

..

No commits in common. "9e7cff20ff3a74c13d976d9cc1afcfc1e21c6020" and "49f7b850325720a3b6275c4639b6d85ca1fa96e9" have entirely different histories.

58 changed files with 501 additions and 6476 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,6 @@
"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",
@ -71,7 +70,6 @@
"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,4 +1,3 @@
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,23 +1,18 @@
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( throw new TypeError("Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'");
"Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'"
);
} }
const buffer = Buffer.from( const buffer = Buffer.from(array.buffer, array.byteOffset, array.byteLength);
array.buffer,
array.byteOffset,
array.byteLength
);
crypto.randomFillSync(buffer); crypto.randomFillSync(buffer);
return array; return array;
} }
} }

View File

@ -1,6 +1,8 @@
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,4 +1,3 @@
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";
@ -12,12 +11,7 @@ export class CryptoKey extends core.CryptoKey {
public override type: KeyType = "secret"; public override type: KeyType = "secret";
@JsonProp({ @JsonProp({ name: "key_ops", type: JsonPropTypes.String, repeated: true, optional: true })
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,6 +1,8 @@
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,68 +4,33 @@ 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(
algorithm: AesKeyGenParams, public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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( public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt( public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
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,4 +1,3 @@
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";
@ -91,17 +90,14 @@ 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( lastBlock = xor(getPaddedMessageBlock(message, lastBlockIndex), subkeys.subkey2);
getPaddedMessageBlock(message, lastBlockIndex),
subkeys.subkey2
);
} }
let x = zero; let x = zero;
@ -116,63 +112,35 @@ function aesCmac(key: Buffer, message: Buffer) {
} }
export class AesCmacProvider extends core.AesCmacProvider { export class AesCmacProvider extends core.AesCmacProvider {
public async onGenerateKey(
algorithm: AesKeyGenParams, public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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( public async onSign(algorithm: core.AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
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( public async onVerify(algorithm: core.AesCmacParams, key: AesCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
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( public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
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,68 +4,33 @@ 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(
algorithm: AesKeyGenParams, public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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( public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: AesCtrParams, return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt( public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: AesCtrParams, return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
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,68 +4,33 @@ 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(
algorithm: AesKeyGenParams, public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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( public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt( public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
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,68 +4,33 @@ 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(
algorithm: AesKeyGenParams, public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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( public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: AesGcmParams, return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt( public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: AesGcmParams, return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.decrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
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,68 +4,34 @@ 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(
algorithm: AesKeyGenParams, public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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( public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
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( public override async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
key: AesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return AesCrypto.encrypt(
algorithm,
getCryptoKey(key) as AesCryptoKey,
new Uint8Array(data)
);
} }
public override async onDecrypt( public override async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
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,4 +1,3 @@
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";
@ -6,13 +5,10 @@ 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( public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<AesCryptoKey> {
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;
@ -22,10 +18,7 @@ export class AesCrypto {
return key; return key;
} }
public static async exportKey( public static async exportKey(format: string, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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");
} }
@ -40,13 +33,7 @@ export class AesCrypto {
} }
} }
public static async importKey( public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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()) {
@ -79,167 +66,78 @@ export class AesCrypto {
return key; return key;
} }
public static async encrypt( public static async encrypt(algorithm: Algorithm, key: AesCryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
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( return this.encryptAesCBC(algorithm as AesCbcParams, key, Buffer.from(data));
algorithm as AesCbcParams,
key,
Buffer.from(data)
);
case "AES-CTR": case "AES-CTR":
return this.encryptAesCTR( return this.encryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data));
algorithm as AesCtrParams,
key,
Buffer.from(data)
);
case "AES-GCM": case "AES-GCM":
return this.encryptAesGCM( return this.encryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data));
algorithm as AesGcmParams,
key,
Buffer.from(data)
);
case "AES-KW": case "AES-KW":
return this.encryptAesKW( return this.encryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
algorithm as AesKeyAlgorithm,
key,
Buffer.from(data)
);
case "AES-ECB": case "AES-ECB":
return this.encryptAesECB( return this.encryptAesECB(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
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( public static async decrypt(algorithm: Algorithm, key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
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( return this.decryptAesCBC(algorithm as AesCbcParams, key, Buffer.from(data));
algorithm as AesCbcParams,
key,
Buffer.from(data)
);
case "AES-CTR": case "AES-CTR":
return this.decryptAesCTR( return this.decryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data));
algorithm as AesCtrParams,
key,
Buffer.from(data)
);
case "AES-GCM": case "AES-GCM":
return this.decryptAesGCM( return this.decryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data));
algorithm as AesGcmParams,
key,
Buffer.from(data)
);
case "AES-KW": case "AES-KW":
return this.decryptAesKW( return this.decryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
algorithm as AesKeyAlgorithm,
key,
Buffer.from(data)
);
case "AES-ECB": case "AES-ECB":
return this.decryptAesECB( return this.decryptAesECB(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
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( public static async encryptAesCBC(algorithm: AesCbcParams, key: AesCryptoKey, data: Buffer) {
algorithm: AesCbcParams, const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
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( public static async decryptAesCBC(algorithm: AesCbcParams, key: AesCryptoKey, data: Buffer) {
algorithm: AesCbcParams, const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
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( public static async encryptAesCTR(algorithm: AesCtrParams, key: AesCryptoKey, data: Buffer) {
algorithm: AesCtrParams, const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ctr`, key.data, Buffer.from(algorithm.counter as ArrayBuffer));
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( public static async decryptAesCTR(algorithm: AesCtrParams, key: AesCryptoKey, data: Buffer) {
algorithm: AesCtrParams, const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ctr`, key.data, new Uint8Array(algorithm.counter as ArrayBuffer));
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( public static async encryptAesGCM(algorithm: AesGcmParams, key: AesCryptoKey, data: Buffer) {
algorithm: AesGcmParams, const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-gcm`, key.data, Buffer.from(algorithm.iv as ArrayBuffer), {
key: AesCryptoKey,
data: Buffer
) {
const cipher = crypto.createCipheriv(
`aes-${key.algorithm.length}-gcm`,
key.data,
Buffer.from(algorithm.iv as ArrayBuffer),
{
authTagLength: (algorithm.tagLength || 128) >> 3, authTagLength: (algorithm.tagLength || 128) >> 3,
} as any } as any) as CipherGCM; // NodeJs d.ts doesn't support CipherGCMOptions for createCipheriv
) 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));
} }
@ -249,16 +147,8 @@ export class AesCrypto {
return res; return res;
} }
public static async decryptAesGCM( public static async decryptAesGCM(algorithm: AesGcmParams, key: AesCryptoKey, data: Buffer) {
algorithm: AesGcmParams, const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-gcm`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)) as DecipherGCM;
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);
@ -271,62 +161,30 @@ export class AesCrypto {
return new Uint8Array(dec).buffer; return new Uint8Array(dec).buffer;
} }
public static async encryptAesKW( public static async encryptAesKW(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
algorithm: Algorithm, const cipher = crypto.createCipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV);
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( public static async decryptAesKW(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
algorithm: Algorithm, const decipher = crypto.createDecipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV);
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( public static async encryptAesECB(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
algorithm: Algorithm, const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0));
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( public static async decryptAesECB(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
algorithm: Algorithm, const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0));
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,6 +4,7 @@ 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})
@ -33,4 +34,5 @@ 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,4 +1,3 @@
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";
@ -7,11 +6,8 @@ import { DesCryptoKey } from "./key";
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class DesCrypto { export class DesCrypto {
public static async generateKey(
algorithm: AesKeyGenParams, public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<DesCryptoKey> {
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;
@ -21,10 +17,7 @@ export class DesCrypto {
return key; return key;
} }
public static async exportKey( public static async exportKey(format: string, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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);
@ -35,13 +28,7 @@ export class DesCrypto {
} }
} }
public static async importKey( public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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()) {
@ -63,11 +50,7 @@ export class DesCrypto {
return key; return key;
} }
public static async encrypt( public static async encrypt(algorithm: DesParams, key: DesCryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
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));
@ -78,11 +61,7 @@ export class DesCrypto {
} }
} }
public static async decrypt( public static async decrypt(algorithm: DesParams, key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
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");
} }
@ -97,65 +76,34 @@ export class DesCrypto {
} }
} }
public static async encryptDesCBC( public static async encryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
algorithm: DesParams, const cipher = crypto.createCipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
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( public static async decryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
algorithm: DesParams, const decipher = crypto.createDecipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
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( public static async encryptDesEDE3CBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
algorithm: DesParams, const cipher = crypto.createCipheriv(`des-ede3-cbc`, key.data, Buffer.from(algorithm.iv as ArrayBuffer));
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( public static async decryptDesEDE3CBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
algorithm: DesParams, const decipher = crypto.createDecipheriv(`des-ede3-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
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,73 +7,38 @@ 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( public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
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( public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: DesCbcParams, return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.encrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt( public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: DesCbcParams, return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.decrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
format: KeyFormat, const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages);
keyData: JsonWebKey | ArrayBuffer, if (key.data.length !== (this.keySizeBits >> 3)) {
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);
@ -85,4 +50,5 @@ 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,73 +7,38 @@ 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( public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
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( public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: DesEde3CbcParams, return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.encrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onDecrypt( public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: DesEde3CbcParams, return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
key: DesCryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return DesCrypto.decrypt(
algorithm,
getCryptoKey(key) as DesCryptoKey,
new Uint8Array(data)
);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
format: KeyFormat, const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages);
keyData: JsonWebKey | ArrayBuffer, if (key.data.length !== (this.keySizeBits >> 3)) {
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);
@ -85,4 +50,5 @@ 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,6 +4,7 @@ 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})
@ -25,4 +26,5 @@ 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,4 +1,3 @@
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";
@ -11,27 +10,20 @@ 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( public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
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( privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1);
(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( publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1);
(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),
@ -56,19 +48,13 @@ export class EcCrypto {
return res; return res;
} }
public static async sign( public static async sign(algorithm: EcdsaParams, key: EcPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
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( key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
@ -77,28 +63,18 @@ 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( const signatureRaw = core.EcUtils.encodeSignature(ecSignature, core.EcCurves.get(key.algorithm.namedCurve).size);
ecSignature,
core.EcCurves.get(key.algorithm.namedCurve).size
);
return signatureRaw.buffer; return signatureRaw.buffer;
} }
public static async verify( public static async verify(algorithm: EcdsaParams, key: EcPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
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( key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
@ -106,10 +82,7 @@ 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( const signaturePoint = core.EcUtils.decodeSignature(signature, namedCurve.size);
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);
@ -118,30 +91,15 @@ export class EcCrypto {
return ok; return ok;
} }
public static async deriveBits( public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number | null): Promise<ArrayBuffer> {
algorithm: EcdhKeyDeriveParams, const cryptoAlg = this.getOpenSSLNamedCurve((baseKey.algorithm as EcKeyAlgorithm).namedCurve);
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( const asnPrivateKey = AsnParser.parse(baseKey.data, core.asn1.PrivateKeyInfo);
baseKey.data, const asnEcPrivateKey = AsnParser.parse(asnPrivateKey.privateKey, core.asn1.EcPrivateKey);
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( const asnPublicKey = AsnParser.parse((algorithm.public as CryptoKey).data, core.asn1.PublicKeyInfo);
(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) {
@ -151,10 +109,7 @@ 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( public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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);
@ -162,49 +117,24 @@ 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( const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo);
key.data,
core.asn1.PublicKeyInfo
);
return publicKeyInfo.publicKey; return publicKeyInfo.publicKey;
} }
default: default:
throw new core.OperationError( throw new core.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'");
"format: Must be 'jwk', 'raw', pkcs8' or 'spki'"
);
} }
} }
public static async importKey( public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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, { const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPrivateKey });
targetSchema: core.asn1.EcPrivateKey, return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
});
return this.importPrivateKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} else { } else {
const asnKey = JsonParser.fromJSON(keyData, { const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPublicKey });
targetSchema: core.asn1.EcPublicKey, return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
});
return this.importPublicKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} }
} }
case "raw": { case "raw": {
@ -212,75 +142,43 @@ 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( const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
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( this.assertKeyParameters(keyInfo.publicKeyAlgorithm.parameters, algorithm.namedCurve);
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( const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
new Uint8Array(keyData as ArrayBuffer), const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey);
core.asn1.PrivateKeyInfo this.assertKeyParameters(keyInfo.privateKeyAlgorithm.parameters, algorithm.namedCurve);
);
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( throw new core.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'");
"format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"
);
} }
} }
protected static assertKeyParameters( protected static assertKeyParameters(parameters: ArrayBuffer | null | undefined, namedCurve: string) {
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( namedCurveIdentifier = AsnParser.parse(parameters, core.asn1.ObjectIdentifier).value;
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( throw new core.CryptoError("Key info parameter doesn't match to named curve");
"Key info parameter doesn't match to named curve"
);
} }
} }
protected static async importPrivateKey( protected static async importPrivateKey(asnKey: core.asn1.EcPrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
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( keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve)));
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();
@ -293,18 +191,11 @@ export class EcCrypto {
return key; return key;
} }
protected static async importPublicKey( protected static async importPublicKey(asnKey: core.asn1.EcPublicKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
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( keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(namedCurve));
new core.asn1.ObjectIdentifier(namedCurve)
);
keyInfo.publicKey = asnKey.value; keyInfo.publicKey = asnKey.value;
const key = new EcPublicKey(); const key = new EcPublicKey();
@ -331,4 +222,5 @@ export class EcCrypto {
return curve; return curve;
} }
} }
} }

View File

@ -6,21 +6,17 @@ 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( public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
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),
@ -28,53 +24,26 @@ export class EcdhProvider extends core.EcdhProvider {
}; };
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return EcCrypto.exportKey(format, getCryptoKey(key)); return EcCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
format: KeyFormat, const key = await EcCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
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 ( if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) {
!(
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( public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> {
algorithm: EcdhKeyDeriveParams, const bits = await EcCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length);
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,33 +5,22 @@ 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-1", "SHA-256", "SHA-384", "SHA-512",
"SHA-256", "shake128", "shake256",
"SHA-384", "SHA3-256", "SHA3-384", "SHA3-512"];
"SHA-512",
"shake128",
"shake256",
"SHA3-256",
"SHA3-384",
"SHA3-512",
];
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 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),
@ -39,66 +28,29 @@ export class EcdsaProvider extends core.EcdsaProvider {
}; };
} }
public async onSign( public async onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: EcdsaParams, return EcCrypto.sign(algorithm, getCryptoKey(key) as EcPrivateKey, new Uint8Array(data));
key: EcPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return EcCrypto.sign(
algorithm,
getCryptoKey(key) as EcPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify( public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
algorithm: EcdsaParams, return EcCrypto.verify(algorithm, getCryptoKey(key) as EcPublicKey, new Uint8Array(signature), new Uint8Array(data));
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( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return EcCrypto.exportKey(format, getCryptoKey(key)); return EcCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
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 ( if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) {
!(
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,42 +15,40 @@ 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( throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`);
`Cannot convert OID(${oid}) to WebCrypto named curve`
);
} }
return namedCurve; return namedCurve;
} }
@ -58,9 +56,7 @@ 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( throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`);
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
);
} }
return oid; return oid;
} }

View File

@ -1,10 +1,5 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
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";
@ -33,23 +28,20 @@ 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( throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
`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, { const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPrivateKey });
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,15 +1,11 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
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;
@ -33,19 +29,15 @@ 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( throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
`Cannot get named curve from JWK. Property 'crv' is required`
);
} }
const key = JsonParser.fromJSON(json, { const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPublicKey });
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,4 +1,3 @@
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";
@ -9,27 +8,20 @@ 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( public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
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( privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1);
(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( publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1);
(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, {
@ -54,15 +46,9 @@ export class EdCrypto {
return res; return res;
} }
public static async sign( public static async sign(algorithm: Algorithm, key: EdPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
algorithm: Algorithm,
key: EdPrivateKey,
data: Uint8Array
): Promise<ArrayBuffer> {
if (!key.pem) { if (!key.pem) {
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString( key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
@ -72,34 +58,18 @@ export class EdCrypto {
return core.BufferSourceConverter.toArrayBuffer(signature); return core.BufferSourceConverter.toArrayBuffer(signature);
} }
public static async verify( public static async verify(algorithm: EcdsaParams, key: EdPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
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( key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const options = { const options = {
key: key.pem, key: key.pem,
}; };
const ok = crypto.verify( const ok = crypto.verify(null, Buffer.from(data), options, Buffer.from(signature));
null,
Buffer.from(data),
options,
Buffer.from(signature)
);
return ok; return ok;
} }
public static async deriveBits( public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> {
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",
@ -118,10 +88,7 @@ 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( public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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);
@ -129,95 +96,46 @@ 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( const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo);
key.data,
core.asn1.PublicKeyInfo
);
return publicKeyInfo.publicKey; return publicKeyInfo.publicKey;
} }
default: default:
throw new core.OperationError( throw new core.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'");
"format: Must be 'jwk', 'raw', pkcs8' or 'spki'"
);
} }
} }
public static async importKey( public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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, { const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.CurvePrivateKey });
targetSchema: core.asn1.CurvePrivateKey, return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
});
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( return this.importPublicKey(Convert.FromBase64Url(jwk.x), algorithm, extractable, keyUsages);
Convert.FromBase64Url(jwk.x),
algorithm,
extractable,
keyUsages
);
} }
} }
case "raw": { case "raw": {
return this.importPublicKey( return this.importPublicKey(keyData as ArrayBuffer, algorithm, extractable, keyUsages);
keyData as ArrayBuffer,
algorithm,
extractable,
keyUsages
);
} }
case "spki": { case "spki": {
const keyInfo = AsnParser.parse( const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
new Uint8Array(keyData as ArrayBuffer), return this.importPublicKey(keyInfo.publicKey, algorithm, extractable, keyUsages);
core.asn1.PublicKeyInfo
);
return this.importPublicKey(
keyInfo.publicKey,
algorithm,
extractable,
keyUsages
);
} }
case "pkcs8": { case "pkcs8": {
const keyInfo = AsnParser.parse( const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
new Uint8Array(keyData as ArrayBuffer), const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.CurvePrivateKey);
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( throw new core.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'");
"format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"
);
} }
} }
protected static importPrivateKey( protected static importPrivateKey(asnKey: core.asn1.CurvePrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
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,
@ -231,12 +149,7 @@ export class EdCrypto {
return key; return key;
} }
protected static async importPublicKey( protected static async importPublicKey(asnKey: ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
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,
@ -249,4 +162,5 @@ export class EdCrypto {
return key; return key;
} }
} }

View File

@ -4,19 +4,15 @@ 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(
algorithm: EcKeyGenParams, public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
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),
@ -24,40 +20,18 @@ export class EcdhEsProvider extends core.EcdhEsProvider {
}; };
} }
public async onDeriveBits( public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: core.CryptoKey, length: number): Promise<ArrayBuffer> {
algorithm: EcdhKeyDeriveParams, const bits = await EdCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length);
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( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> {
format: KeyFormat,
key: CryptoKey
): Promise<ArrayBuffer | JsonWebKey> {
return EdCrypto.exportKey(format, getCryptoKey(key)); return EdCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: ArrayBuffer | JsonWebKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
format: KeyFormat, const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
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,19 +6,15 @@ 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(
algorithm: EcKeyGenParams, public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
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),
@ -26,53 +22,21 @@ export class EdDsaProvider extends core.EdDsaProvider {
}; };
} }
public async onSign( public async onSign(algorithm: EcdsaParams, key: CryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: EcdsaParams, return EdCrypto.sign(algorithm, getCryptoKey(key) as EdPrivateKey, new Uint8Array(data));
key: CryptoKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return EdCrypto.sign(
algorithm,
getCryptoKey(key) as EdPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify( public async onVerify(algorithm: EcdsaParams, key: CryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
algorithm: EcdsaParams, return EdCrypto.verify(algorithm, getCryptoKey(key) as EdPublicKey, new Uint8Array(signature), new Uint8Array(data));
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( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> {
format: KeyFormat,
key: CryptoKey
): Promise<ArrayBuffer | JsonWebKey> {
return EdCrypto.exportKey(format, getCryptoKey(key)); return EdCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: ArrayBuffer | JsonWebKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
format: KeyFormat, const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
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,24 +3,22 @@ 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( throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`);
`Cannot convert OID(${oid}) to WebCrypto named curve`
);
} }
return namedCurve; return namedCurve;
} }
@ -28,9 +26,7 @@ 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( throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`);
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
);
} }
return oid; return oid;
} }

View File

@ -1,10 +1,5 @@
import { Buffer } from "buffer";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
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";
@ -33,20 +28,17 @@ 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( throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
`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, { const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.CurvePrivateKey });
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,4 +1,3 @@
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";
@ -7,6 +6,7 @@ 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,20 +26,16 @@ 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( throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
`Cannot get named curve from JWK. Property 'crv' is required`
);
} }
if (!json.x) { if (!json.x) {
throw new core.OperationError( throw new core.OperationError(`Cannot get property from JWK. Property 'x' is required`);
`Cannot get property from JWK. Property 'x' is required`
);
} }
const keyInfo = new core.asn1.PublicKeyInfo(); const keyInfo = new core.asn1.PublicKeyInfo();

View File

@ -1,4 +1,3 @@
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";
@ -6,13 +5,8 @@ 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(
format: KeyFormat, public async onImportKey(format: KeyFormat, keyData: ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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");
} }
@ -25,19 +19,14 @@ export class HkdfProvider extends core.HkdfProvider {
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onDeriveBits( public async onDeriveBits(params: HkdfParams, baseKey: HkdfCryptoKey, length: number): Promise<ArrayBuffer> {
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 const PRK = crypto.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
.update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data)) .update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data))
.digest(); .digest();
@ -45,10 +34,9 @@ export class HkdfProvider extends core.HkdfProvider {
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 crypto.createHmac(hash, PRK)
.createHmac(hash, PRK)
.update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])])) .update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])]))
.digest() .digest(),
); );
} }
@ -61,4 +49,5 @@ 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,6 +1,7 @@
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,4 +1,3 @@
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";
@ -7,19 +6,12 @@ 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(
algorithm: HmacKeyGenParams, public async onGenerateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
extractable: boolean, const length = (algorithm.length || this.getDefaultLength((algorithm.hash as Algorithm).name)) >> 3 << 3;
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,
}; };
@ -30,42 +22,23 @@ export class HmacProvider extends core.HmacProvider {
return setCryptoKey(key); return setCryptoKey(key);
} }
public override async onSign( public override async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
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 const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data)
.createHmac(cryptoAlg, getCryptoKey(key).data) .update(Buffer.from(data)).digest();
.update(Buffer.from(data))
.digest();
return new Uint8Array(hmac).buffer; return new Uint8Array(hmac).buffer;
} }
public override async onVerify( public override async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
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 const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data)
.createHmac(cryptoAlg, getCryptoKey(key).data) .update(Buffer.from(data)).digest();
.update(Buffer.from(data))
.digest();
return hmac.compare(Buffer.from(signature)) === 0; return hmac.compare(Buffer.from(signature)) === 0;
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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()) {
@ -91,10 +64,7 @@ export class HmacProvider extends core.HmacProvider {
return setCryptoKey(key); return setCryptoKey(key);
} }
public async onExportKey( public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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));
@ -111,4 +81,5 @@ 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,6 +3,7 @@ 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;
@ -18,4 +19,5 @@ 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,3 +1,4 @@
import { CryptoKey } from "../../keys"; import { CryptoKey } from "../../keys";
export class PbkdfCryptoKey extends CryptoKey {} export class PbkdfCryptoKey extends CryptoKey {
}

View File

@ -1,42 +1,25 @@
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(
algorithm: Pbkdf2Params, public async onDeriveBits(algorithm: Pbkdf2Params, baseKey: PbkdfCryptoKey, length: number): Promise<ArrayBuffer> {
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( crypto.pbkdf2(getCryptoKey(baseKey).data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => {
getCryptoKey(baseKey).data,
Buffer.from(salt),
algorithm.iterations,
length >> 3,
hash,
(err, derivedBits) => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
resolve(new Uint8Array(derivedBits).buffer); resolve(new Uint8Array(derivedBits).buffer);
} }
} });
);
}); });
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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);
@ -54,4 +37,5 @@ 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,4 +1,3 @@
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";
@ -15,27 +14,20 @@ 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( public static async generateKey(algorithm: RsaHashedKeyGenParams | RsaKeyGenParams, extractable: boolean, keyUsages: string[]): Promise<CryptoKeyPair> {
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( privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1) as KeyUsage[];
(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( publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1) as KeyUsage[];
(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),
@ -66,10 +58,7 @@ export class RsaCrypto {
return res; return res;
} }
public static async exportKey( public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
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);
@ -77,78 +66,38 @@ 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( throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'");
"format: Must be 'jwk', 'pkcs8' or 'spki'"
);
} }
} }
public static async importKey( public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
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, { const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPrivateKey });
targetSchema: core.asn1.RsaPrivateKey, return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
});
return this.importPrivateKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} else { } else {
const asnKey = JsonParser.fromJSON(keyData, { const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPublicKey });
targetSchema: core.asn1.RsaPublicKey, return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
});
return this.importPublicKey(
asnKey,
algorithm,
extractable,
keyUsages
);
} }
} }
case "spki": { case "spki": {
const keyInfo = AsnParser.parse( const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
new Uint8Array(keyData as ArrayBuffer), const asnKey = AsnParser.parse(keyInfo.publicKey, core.asn1.RsaPublicKey);
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( const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
new Uint8Array(keyData as ArrayBuffer), const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.RsaPrivateKey);
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( throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'");
"format: Must be 'jwk', 'pkcs8' or 'spki'"
);
} }
} }
public static async sign( public static async sign(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
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":
@ -158,12 +107,7 @@ export class RsaCrypto {
} }
} }
public static async verify( public static async verify(algorithm: Algorithm, key: RsaPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
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":
@ -173,11 +117,7 @@ export class RsaCrypto {
} }
} }
public static async encrypt( public static async encrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array): Promise<ArrayBuffer> {
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);
@ -186,11 +126,7 @@ export class RsaCrypto {
} }
} }
public static async decrypt( public static async decrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
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);
@ -199,12 +135,7 @@ export class RsaCrypto {
} }
} }
protected static importPrivateKey( protected static importPrivateKey(asnKey: core.asn1.RsaPrivateKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
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;
@ -222,12 +153,7 @@ export class RsaCrypto {
return key; return key;
} }
protected static importPublicKey( protected static importPublicKey(asnKey: core.asn1.RsaPublicKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
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;
@ -266,19 +192,13 @@ export class RsaCrypto {
} }
} }
protected static signRsa( protected static signRsa(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array) {
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( key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
"base64"
)}\n-----END PRIVATE KEY-----`;
} }
const options: INodeCryptoSignOptions = { const options: INodeCryptoSignOptions = {
key: key.pem, key: key.pem,
@ -292,20 +212,13 @@ export class RsaCrypto {
return new Uint8Array(signature).buffer; return new Uint8Array(signature).buffer;
} }
protected static verifySSA( protected static verifySSA(algorithm: Algorithm, key: RsaPublicKey, data: Uint8Array, signature: Uint8Array) {
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( key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
"base64"
)}\n-----END PUBLIC KEY-----`;
} }
const options: INodeCryptoSignOptions = { const options: INodeCryptoSignOptions = {
key: key.pem, key: key.pem,
@ -319,15 +232,9 @@ export class RsaCrypto {
return ok; return ok;
} }
protected static encryptOAEP( protected static encryptOAEP(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array) {
algorithm: RsaOaepParams,
key: RsaPublicKey,
data: Uint8Array
) {
const options: crypto.RsaPublicKey = { const options: crypto.RsaPublicKey = {
key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString( key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`,
"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) {
@ -337,15 +244,9 @@ export class RsaCrypto {
return new Uint8Array(crypto.publicEncrypt(options, data)).buffer; return new Uint8Array(crypto.publicEncrypt(options, data)).buffer;
} }
protected static decryptOAEP( protected static decryptOAEP(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array) {
algorithm: RsaOaepParams,
key: RsaPrivateKey,
data: Uint8Array
) {
const options: crypto.RsaPrivateKey = { const options: crypto.RsaPrivateKey = {
key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString( key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`,
"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) {
@ -354,4 +255,5 @@ export class RsaCrypto {
return new Uint8Array(crypto.privateDecrypt(options, data)).buffer; return new Uint8Array(crypto.privateDecrypt(options, data)).buffer;
} }
} }

View File

@ -1,4 +1,3 @@
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";
@ -28,9 +27,7 @@ export class RsaPrivateKey extends AsymmetricKey {
} }
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
const key = JsonParser.fromJSON(json, { const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPrivateKey });
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";
@ -39,4 +36,5 @@ export class RsaPrivateKey extends AsymmetricKey {
this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
} }
} }

View File

@ -1,4 +1,3 @@
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";
@ -28,9 +27,7 @@ export class RsaPublicKey extends AsymmetricKey {
} }
public fromJSON(json: JsonWebKey) { public fromJSON(json: JsonWebKey) {
const key = JsonParser.fromJSON(json, { const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPublicKey });
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,25 +7,21 @@ 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( public override async onGenerateKey(algorithm: RsaKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
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),
@ -36,12 +32,7 @@ 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 ( if (!(algorithm.publicExponent && algorithm.publicExponent instanceof Uint8Array)) {
!(
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);
@ -61,59 +52,31 @@ export class RsaEsProvider extends core.ProviderCrypto {
} }
} }
public override async onEncrypt( public override async onEncrypt(algorithm: Algorithm, key: RsaPublicKey, data: ArrayBuffer): Promise<ArrayBuffer> {
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( public override async onDecrypt(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
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( public override async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public override async onImportKey( public override async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
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 ( if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
!(
internalKey instanceof RsaPrivateKey ||
internalKey instanceof RsaPublicKey
)
) {
throw new TypeError("key: Is not RSA CryptoKey"); throw new TypeError("key: Is not RSA CryptoKey");
} }
} }
@ -123,9 +86,7 @@ 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( key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`,
"base64"
)}\n-----END ${type} KEY-----`,
padding: crypto.constants.RSA_PKCS1_PADDING, padding: crypto.constants.RSA_PKCS1_PADDING,
}; };
} }

View File

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

View File

@ -5,31 +5,20 @@ 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 = [
"SHA-1",
"SHA-256",
"SHA-384",
"SHA-512",
"shake128",
"shake256",
"SHA3-256",
"SHA3-384",
"SHA3-512",
];
public async onGenerateKey( public override hashAlgorithms = [
algorithm: RsaHashedKeyGenParams, "SHA-1", "SHA-256", "SHA-384", "SHA-512",
extractable: boolean, "shake128", "shake256",
keyUsages: KeyUsage[] "SHA3-256", "SHA3-384", "SHA3-512"];
): 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),
@ -37,66 +26,29 @@ export class RsaPssProvider extends core.RsaPssProvider {
}; };
} }
public async onSign( public async onSign(algorithm: RsaPssParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: RsaPssParams, return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data));
key: RsaPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return RsaCrypto.sign(
algorithm,
getCryptoKey(key) as RsaPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify( public async onVerify(algorithm: RsaPssParams, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
algorithm: RsaPssParams, return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data));
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( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
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 ( if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
!(
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,31 +5,20 @@ 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 = [
"SHA-1",
"SHA-256",
"SHA-384",
"SHA-512",
"shake128",
"shake256",
"SHA3-256",
"SHA3-384",
"SHA3-512",
];
public async onGenerateKey( public override hashAlgorithms = [
algorithm: RsaHashedKeyGenParams, "SHA-1", "SHA-256", "SHA-384", "SHA-512",
extractable: boolean, "shake128", "shake256",
keyUsages: KeyUsage[] "SHA3-256", "SHA3-384", "SHA3-512"];
): 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),
@ -37,66 +26,29 @@ export class RsaSsaProvider extends core.RsaSsaProvider {
}; };
} }
public async onSign( public async onSign(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
algorithm: Algorithm, return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data));
key: RsaPrivateKey,
data: ArrayBuffer
): Promise<ArrayBuffer> {
return RsaCrypto.sign(
algorithm,
getCryptoKey(key) as RsaPrivateKey,
new Uint8Array(data)
);
} }
public async onVerify( public async onVerify(algorithm: Algorithm, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
algorithm: Algorithm, return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data));
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( public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
format: KeyFormat,
key: CryptoKey
): Promise<JsonWebKey | ArrayBuffer> {
return RsaCrypto.exportKey(format, getCryptoKey(key)); return RsaCrypto.exportKey(format, getCryptoKey(key));
} }
public async onImportKey( public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
format: KeyFormat, const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
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 ( if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
!(
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,7 +53,9 @@ 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).update(Buffer.from(data)).digest(); const hash = crypto.createHash(hashAlg)
.update(Buffer.from(data)).digest();
return new Uint8Array(hash).buffer; return new Uint8Array(hash).buffer;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,13 @@
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(
algorithm: Required<core.ShakeParams>, public static digest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer) {
data: ArrayBuffer const hash = crypto.createHash(algorithm.name.toLowerCase(), {outputLength: algorithm.length})
) { .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,10 +2,9 @@ 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(
algorithm: Required<core.ShakeParams>, public override async onDigest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer): Promise<ArrayBuffer> {
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShakeCrypto.digest(algorithm, data); return ShakeCrypto.digest(algorithm, data);
} }
} }

View File

@ -2,10 +2,9 @@ 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(
algorithm: Required<core.ShakeParams>, public override async onDigest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer): Promise<ArrayBuffer> {
data: ArrayBuffer
): Promise<ArrayBuffer> {
return ShakeCrypto.digest(algorithm, data); return ShakeCrypto.digest(algorithm, data);
} }
} }

View File

@ -12,12 +12,7 @@ export function getCryptoKey(key: core.CryptoKey) {
} }
export function setCryptoKey(value: InternalCryptoKey) { export function setCryptoKey(value: InternalCryptoKey) {
const key = core.CryptoKey.create( const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages);
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,34 +2,18 @@ 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, AesCbcProvider, AesCmacProvider, AesCtrProvider, AesEcbProvider, AesGcmProvider, AesKwProvider,
AesCmacProvider,
AesCtrProvider,
AesEcbProvider,
AesGcmProvider,
AesKwProvider,
DesCbcProvider, DesCbcProvider,
DesEde3CbcProvider, DesEde3CbcProvider, EcdhProvider,
EcdhProvider, EcdsaProvider, HkdfProvider,
EcdsaProvider,
HkdfProvider,
EdDsaProvider, EdDsaProvider,
EcdhEsProvider, EcdhEsProvider,
HmacProvider, HmacProvider,
Pbkdf2Provider, Pbkdf2Provider,
RsaEsProvider, RsaEsProvider, RsaOaepProvider, RsaPssProvider, RsaSsaProvider,
RsaOaepProvider, Sha1Provider, Sha256Provider, Sha384Provider, Sha512Provider,
RsaPssProvider, Shake128Provider, Shake256Provider,
RsaSsaProvider, Sha3256Provider, Sha3384Provider, Sha3512Provider,
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 {