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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,42 +15,40 @@ const namedOIDs: { [key: string]: string } = {
"K-256": "1.3.132.0.10",
// 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",
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",
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",
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",
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",
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",
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",
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",
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",
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",
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",
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",
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",
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",
};
export function getNamedCurveByOid(oid: string) {
const namedCurve = namedOIDs[oid];
if (!namedCurve) {
throw new core.OperationError(
`Cannot convert OID(${oid}) to WebCrypto named curve`
);
throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`);
}
return namedCurve;
}
@ -58,9 +56,7 @@ export function getNamedCurveByOid(oid: string) {
export function getOidByNamedCurve(namedCurve: string) {
const oid = namedOIDs[namedCurve];
if (!oid) {
throw new core.OperationError(
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
);
throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`);
}
return oid;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import { Buffer } from "buffer";
import crypto from "crypto";
export class ShaCrypto {
/**
* Returns size of the hash algorithm in bits
* @param algorithm Hash algorithm
@ -53,7 +53,9 @@ export class ShaCrypto {
public static digest(algorithm: Algorithm, data: ArrayBuffer) {
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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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