From f50bab48149f5495b80fbaf2bba0505a77876622 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 4 Apr 2023 06:19:16 -0400 Subject: [PATCH] *add buffer import --- package.json | 1 + src/converters/base64_url.ts | 1 + src/crypto.ts | 13 ++- src/keys/key.ts | 8 +- src/mechs/aes/aes_cmac.ts | 52 +++++++-- src/mechs/aes/crypto.ts | 218 +++++++++++++++++++++++++++++------ src/mechs/des/crypto.ts | 82 ++++++++++--- src/mechs/ec/crypto.ts | 182 +++++++++++++++++++++++------ src/mechs/ec/private_key.ts | 18 ++- src/mechs/ec/public_key.ts | 18 ++- src/mechs/ed/crypto.ts | 144 ++++++++++++++++++----- src/mechs/ed/private_key.ts | 16 ++- src/mechs/ed/public_key.ts | 12 +- src/mechs/hkdf/hkdf.ts | 33 ++++-- src/mechs/hmac/hmac.ts | 55 ++++++--- src/mechs/pbkdf/pbkdf2.ts | 36 ++++-- src/mechs/rsa/crypto.ts | 160 ++++++++++++++++++++----- src/mechs/rsa/private_key.ts | 6 +- src/mechs/rsa/public_key.ts | 5 +- src/mechs/rsa/rsa_oaep.ts | 135 ++++++++++++++++------ src/mechs/sha/crypto.ts | 6 +- src/mechs/shake/crypto.ts | 16 ++- 22 files changed, 955 insertions(+), 262 deletions(-) diff --git a/package.json b/package.json index 835fc44..157ca02 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "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" diff --git a/src/converters/base64_url.ts b/src/converters/base64_url.ts index 7cb969c..6f2d72a 100644 --- a/src/converters/base64_url.ts +++ b/src/converters/base64_url.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import { IJsonConverter } from "@peculiar/json-schema"; import { Convert } from "pvtsutils"; diff --git a/src/crypto.ts b/src/crypto.ts index 513d9a3..a9c511a 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -1,18 +1,23 @@ +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(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; } - } diff --git a/src/keys/key.ts b/src/keys/key.ts index a00c344..e1dcb40 100644 --- a/src/keys/key.ts +++ b/src/keys/key.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import { JsonProp, JsonPropTypes } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; @@ -11,7 +12,12 @@ 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 }) diff --git a/src/mechs/aes/aes_cmac.ts b/src/mechs/aes/aes_cmac.ts index 9032e8b..87e45c0 100644 --- a/src/mechs/aes/aes_cmac.ts +++ b/src/mechs/aes/aes_cmac.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import * as crypto from "crypto"; import * as core from "webcrypto-core"; import { AesCrypto } from "./crypto"; @@ -90,14 +91,17 @@ 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; @@ -112,35 +116,63 @@ function aesCmac(key: Buffer, message: Buffer) { } export class AesCmacProvider extends core.AesCmacProvider { - - public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onGenerateKey( + algorithm: AesKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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 { + public async onSign( + algorithm: core.AesCmacParams, + key: AesCryptoKey, + data: ArrayBuffer + ): Promise { 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 { + public async onVerify( + algorithm: core.AesCmacParams, + key: AesCryptoKey, + signature: ArrayBuffer, + data: ArrayBuffer + ): Promise { 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 { + public async onExportKey( + format: KeyFormat, + key: AesCryptoKey + ): Promise { return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } - public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - 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 { + const res = await AesCrypto.importKey( + format, + keyData, + { name: algorithm.name }, + extractable, + keyUsages + ); return setCryptoKey(res); } diff --git a/src/mechs/aes/crypto.ts b/src/mechs/aes/crypto.ts index 3cbfed4..1486384 100644 --- a/src/mechs/aes/crypto.ts +++ b/src/mechs/aes/crypto.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto, { CipherGCM, DecipherGCM } from "crypto"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; @@ -5,10 +6,13 @@ 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 { + public static async generateKey( + algorithm: AesKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { const key = new AesCryptoKey(); key.algorithm = algorithm; key.extractable = extractable; @@ -18,7 +22,10 @@ export class AesCrypto { return key; } - public static async exportKey(format: string, key: AesCryptoKey): Promise { + public static async exportKey( + format: string, + key: AesCryptoKey + ): Promise { if (!(key instanceof AesCryptoKey)) { throw new Error("key: Is not AesCryptoKey"); } @@ -33,7 +40,13 @@ export class AesCrypto { } } - public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public static async importKey( + format: string, + keyData: JsonWebKey | ArrayBuffer, + algorithm: any, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { let key: AesCryptoKey; switch (format.toLowerCase()) { @@ -66,78 +79,167 @@ export class AesCrypto { return key; } - public static async encrypt(algorithm: Algorithm, key: AesCryptoKey, data: Uint8Array): Promise { + public static async encrypt( + algorithm: Algorithm, + key: AesCryptoKey, + data: Uint8Array + ): Promise { 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 { + public static async decrypt( + algorithm: Algorithm, + key: CryptoKey, + data: Uint8Array + ): Promise { 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)); } @@ -147,8 +249,16 @@ 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); @@ -161,30 +271,62 @@ 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; diff --git a/src/mechs/des/crypto.ts b/src/mechs/des/crypto.ts index 5f76048..25b33bf 100644 --- a/src/mechs/des/crypto.ts +++ b/src/mechs/des/crypto.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; @@ -6,8 +7,11 @@ import { DesCryptoKey } from "./key"; import { CryptoKey } from "../../keys"; export class DesCrypto { - - public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public static async generateKey( + algorithm: AesKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { const key = new DesCryptoKey(); key.algorithm = algorithm; key.extractable = extractable; @@ -17,7 +21,10 @@ export class DesCrypto { return key; } - public static async exportKey(format: string, key: CryptoKey): Promise { + public static async exportKey( + format: string, + key: CryptoKey + ): Promise { switch (format.toLowerCase()) { case "jwk": return JsonSerializer.toJSON(key); @@ -28,7 +35,13 @@ export class DesCrypto { } } - public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public static async importKey( + format: string, + keyData: JsonWebKey | ArrayBuffer, + algorithm: any, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { let key: DesCryptoKey; switch (format.toLowerCase()) { @@ -50,7 +63,11 @@ export class DesCrypto { return key; } - public static async encrypt(algorithm: DesParams, key: DesCryptoKey, data: Uint8Array): Promise { + public static async encrypt( + algorithm: DesParams, + key: DesCryptoKey, + data: Uint8Array + ): Promise { switch (algorithm.name.toUpperCase()) { case "DES-CBC": return this.encryptDesCBC(algorithm, key, Buffer.from(data)); @@ -61,7 +78,11 @@ export class DesCrypto { } } - public static async decrypt(algorithm: DesParams, key: CryptoKey, data: Uint8Array): Promise { + public static async decrypt( + algorithm: DesParams, + key: CryptoKey, + data: Uint8Array + ): Promise { if (!(key instanceof DesCryptoKey)) { throw new Error("key: Is not DesCryptoKey"); } @@ -76,34 +97,65 @@ export class DesCrypto { } } - public static async encryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) { - 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; } - } diff --git a/src/mechs/ec/crypto.ts b/src/mechs/ec/crypto.ts index 69a84dc..f344678 100644 --- a/src/mechs/ec/crypto.ts +++ b/src/mechs/ec/crypto.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; @@ -10,20 +11,27 @@ 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 { + public static async generateKey( + algorithm: EcKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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), @@ -48,13 +56,19 @@ export class EcCrypto { return res; } - public static async sign(algorithm: EcdsaParams, key: EcPrivateKey, data: Uint8Array): Promise { + public static async sign( + algorithm: EcdsaParams, + key: EcPrivateKey, + data: Uint8Array + ): Promise { 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, @@ -63,18 +77,28 @@ 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 { + public static async verify( + algorithm: EcdsaParams, + key: EcPublicKey, + signature: Uint8Array, + data: Uint8Array + ): Promise { 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, @@ -82,7 +106,10 @@ 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); @@ -91,15 +118,30 @@ export class EcCrypto { return ok; } - public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number | null): Promise { - const cryptoAlg = this.getOpenSSLNamedCurve((baseKey.algorithm as EcKeyAlgorithm).namedCurve); + public static async deriveBits( + algorithm: EcdhKeyDeriveParams, + baseKey: CryptoKey, + length: number | null + ): Promise { + 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) { @@ -109,7 +151,10 @@ export class EcCrypto { return new Uint8Array(bits).buffer.slice(0, length >> 3); } - public static async exportKey(format: KeyFormat, key: CryptoKey): Promise { + public static async exportKey( + format: KeyFormat, + key: CryptoKey + ): Promise { switch (format.toLowerCase()) { case "jwk": return JsonSerializer.toJSON(key); @@ -117,24 +162,49 @@ 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 { + public static async importKey( + format: KeyFormat, + keyData: JsonWebKey | ArrayBuffer, + algorithm: EcKeyImportParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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": { @@ -142,43 +212,75 @@ 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(); @@ -191,11 +293,18 @@ 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(); @@ -222,5 +331,4 @@ export class EcCrypto { return curve; } } - } diff --git a/src/mechs/ec/private_key.ts b/src/mechs/ec/private_key.ts index c1bd013..cf0a689 100644 --- a/src/mechs/ec/private_key.ts +++ b/src/mechs/ec/private_key.ts @@ -1,5 +1,10 @@ +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"; @@ -28,20 +33,23 @@ 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; } - } diff --git a/src/mechs/ec/public_key.ts b/src/mechs/ec/public_key.ts index 60d5517..fb87332 100644 --- a/src/mechs/ec/public_key.ts +++ b/src/mechs/ec/public_key.ts @@ -1,11 +1,15 @@ +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; @@ -29,15 +33,19 @@ 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; diff --git a/src/mechs/ed/crypto.ts b/src/mechs/ed/crypto.ts index 5089f73..86934dc 100644 --- a/src/mechs/ed/crypto.ts +++ b/src/mechs/ed/crypto.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import { AsnParser } from "@peculiar/asn1-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; @@ -8,20 +9,27 @@ 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 { + public static async generateKey( + algorithm: EcKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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, { @@ -46,9 +54,15 @@ export class EdCrypto { return res; } - public static async sign(algorithm: Algorithm, key: EdPrivateKey, data: Uint8Array): Promise { + public static async sign( + algorithm: Algorithm, + key: EdPrivateKey, + data: Uint8Array + ): Promise { 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, @@ -58,18 +72,34 @@ export class EdCrypto { return core.BufferSourceConverter.toArrayBuffer(signature); } - public static async verify(algorithm: EcdsaParams, key: EdPublicKey, signature: Uint8Array, data: Uint8Array): Promise { + public static async verify( + algorithm: EcdsaParams, + key: EdPublicKey, + signature: Uint8Array, + data: Uint8Array + ): Promise { 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 { + public static async deriveBits( + algorithm: EcdhKeyDeriveParams, + baseKey: CryptoKey, + length: number + ): Promise { const publicKey = crypto.createPublicKey({ key: (algorithm.public as CryptoKey).data, format: "der", @@ -88,7 +118,10 @@ export class EdCrypto { return new Uint8Array(bits).buffer.slice(0, length >> 3); } - public static async exportKey(format: KeyFormat, key: CryptoKey): Promise { + public static async exportKey( + format: KeyFormat, + key: CryptoKey + ): Promise { switch (format.toLowerCase()) { case "jwk": return JsonSerializer.toJSON(key); @@ -96,60 +129,114 @@ 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 { + public static async importKey( + format: KeyFormat, + keyData: JsonWebKey | ArrayBuffer, + algorithm: EcKeyImportParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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, @@ -162,5 +249,4 @@ export class EdCrypto { return key; } - } diff --git a/src/mechs/ed/private_key.ts b/src/mechs/ed/private_key.ts index 443f208..d390d5e 100644 --- a/src/mechs/ed/private_key.ts +++ b/src/mechs/ed/private_key.ts @@ -1,5 +1,10 @@ +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"; @@ -28,17 +33,20 @@ 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; } - } diff --git a/src/mechs/ed/public_key.ts b/src/mechs/ed/public_key.ts index ae9ffa6..c25ec28 100644 --- a/src/mechs/ed/public_key.ts +++ b/src/mechs/ed/public_key.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { IJsonConvertible } from "@peculiar/json-schema"; import { Convert } from "pvtsutils"; @@ -6,7 +7,6 @@ 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,16 +26,20 @@ 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(); diff --git a/src/mechs/hkdf/hkdf.ts b/src/mechs/hkdf/hkdf.ts index 553b550..cf5a59e 100644 --- a/src/mechs/hkdf/hkdf.ts +++ b/src/mechs/hkdf/hkdf.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import * as core from "webcrypto-core"; import { BufferSourceConverter, CryptoKey } from "webcrypto-core"; @@ -5,10 +6,15 @@ 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 { + public async onImportKey( + format: KeyFormat, + keyData: ArrayBuffer, + algorithm: HmacImportParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { if (format.toLowerCase() !== "raw") { - throw new core.OperationError("Operation not supported"); + throw new core.OperationError("Operation not supported"); } const key: HkdfCryptoKey = new HkdfCryptoKey(); @@ -19,24 +25,30 @@ export class HkdfProvider extends core.HkdfProvider { return setCryptoKey(key); } - public async onDeriveBits(params: HkdfParams, baseKey: HkdfCryptoKey, length: number): Promise { + public async onDeriveBits( + params: HkdfParams, + baseKey: HkdfCryptoKey, + length: number + ): Promise { 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() ); } @@ -49,5 +61,4 @@ export class HkdfProvider extends core.HkdfProvider { throw new TypeError("key: Is not HKDF CryptoKey"); } } - } diff --git a/src/mechs/hmac/hmac.ts b/src/mechs/hmac/hmac.ts index 340a4c5..c14a229 100644 --- a/src/mechs/hmac/hmac.ts +++ b/src/mechs/hmac/hmac.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; @@ -6,12 +7,19 @@ 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 { - const length = (algorithm.length || this.getDefaultLength((algorithm.hash as Algorithm).name)) >> 3 << 3; + public async onGenerateKey( + algorithm: HmacKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { + 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, }; @@ -22,23 +30,42 @@ export class HmacProvider extends core.HmacProvider { return setCryptoKey(key); } - public override async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise { + public override async onSign( + algorithm: Algorithm, + key: HmacCryptoKey, + data: ArrayBuffer + ): Promise { 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 { + public override async onVerify( + algorithm: Algorithm, + key: HmacCryptoKey, + signature: ArrayBuffer, + data: ArrayBuffer + ): Promise { 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 { + public async onImportKey( + format: KeyFormat, + keyData: JsonWebKey | ArrayBuffer, + algorithm: HmacImportParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { let key: HmacCryptoKey; switch (format.toLowerCase()) { @@ -64,7 +91,10 @@ export class HmacProvider extends core.HmacProvider { return setCryptoKey(key); } - public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise { + public async onExportKey( + format: KeyFormat, + key: HmacCryptoKey + ): Promise { switch (format.toLowerCase()) { case "jwk": return JsonSerializer.toJSON(getCryptoKey(key)); @@ -81,5 +111,4 @@ export class HmacProvider extends core.HmacProvider { throw new TypeError("key: Is not HMAC CryptoKey"); } } - } diff --git a/src/mechs/pbkdf/pbkdf2.ts b/src/mechs/pbkdf/pbkdf2.ts index c707e92..9326b13 100644 --- a/src/mechs/pbkdf/pbkdf2.ts +++ b/src/mechs/pbkdf/pbkdf2.ts @@ -1,25 +1,42 @@ +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 { + public async onDeriveBits( + algorithm: Pbkdf2Params, + baseKey: PbkdfCryptoKey, + length: number + ): Promise { return new Promise((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 { + public async onImportKey( + format: KeyFormat, + keyData: JsonWebKey | ArrayBuffer, + algorithm: Algorithm, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { if (format === "raw") { const key = new PbkdfCryptoKey(); key.data = Buffer.from(keyData as ArrayBuffer); @@ -37,5 +54,4 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider { throw new TypeError("key: Is not PBKDF CryptoKey"); } } - } diff --git a/src/mechs/rsa/crypto.ts b/src/mechs/rsa/crypto.ts index 0b80282..421f6af 100644 --- a/src/mechs/rsa/crypto.ts +++ b/src/mechs/rsa/crypto.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; @@ -14,20 +15,27 @@ 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 { + public static async generateKey( + algorithm: RsaHashedKeyGenParams | RsaKeyGenParams, + extractable: boolean, + keyUsages: string[] + ): Promise { 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), @@ -58,7 +66,10 @@ export class RsaCrypto { return res; } - public static async exportKey(format: KeyFormat, key: CryptoKey): Promise { + public static async exportKey( + format: KeyFormat, + key: CryptoKey + ): Promise { switch (format.toLowerCase()) { case "jwk": return JsonSerializer.toJSON(key); @@ -66,38 +77,78 @@ 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 { + public static async importKey( + format: KeyFormat, + keyData: JsonWebKey | ArrayBuffer, + algorithm: RsaHashedImportParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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 { + public static async sign( + algorithm: Algorithm, + key: RsaPrivateKey, + data: Uint8Array + ): Promise { switch (algorithm.name.toUpperCase()) { case "RSA-PSS": case "RSASSA-PKCS1-V1_5": @@ -107,7 +158,12 @@ export class RsaCrypto { } } - public static async verify(algorithm: Algorithm, key: RsaPublicKey, signature: Uint8Array, data: Uint8Array): Promise { + public static async verify( + algorithm: Algorithm, + key: RsaPublicKey, + signature: Uint8Array, + data: Uint8Array + ): Promise { switch (algorithm.name.toUpperCase()) { case "RSA-PSS": case "RSASSA-PKCS1-V1_5": @@ -117,7 +173,11 @@ export class RsaCrypto { } } - public static async encrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array): Promise { + public static async encrypt( + algorithm: RsaOaepParams, + key: RsaPublicKey, + data: Uint8Array + ): Promise { switch (algorithm.name.toUpperCase()) { case "RSA-OAEP": return this.encryptOAEP(algorithm, key, data); @@ -126,7 +186,11 @@ export class RsaCrypto { } } - public static async decrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array): Promise { + public static async decrypt( + algorithm: RsaOaepParams, + key: RsaPrivateKey, + data: Uint8Array + ): Promise { switch (algorithm.name.toUpperCase()) { case "RSA-OAEP": return this.decryptOAEP(algorithm, key, data); @@ -135,7 +199,12 @@ export class RsaCrypto { } } - protected static importPrivateKey(asnKey: core.asn1.RsaPrivateKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) { + protected static importPrivateKey( + asnKey: core.asn1.RsaPrivateKey, + algorithm: RsaHashedImportParams, + extractable: boolean, + keyUsages: KeyUsage[] + ) { const keyInfo = new core.asn1.PrivateKeyInfo(); keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.privateKeyAlgorithm.parameters = null; @@ -153,7 +222,12 @@ 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; @@ -192,13 +266,19 @@ export class RsaCrypto { } } - protected static signRsa(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array) { + protected static signRsa( + algorithm: Algorithm, + key: RsaPrivateKey, + data: Uint8Array + ) { const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); const 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, @@ -212,13 +292,20 @@ 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, @@ -232,9 +319,15 @@ 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) { @@ -244,9 +337,15 @@ 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) { @@ -255,5 +354,4 @@ export class RsaCrypto { return new Uint8Array(crypto.privateDecrypt(options, data)).buffer; } - } diff --git a/src/mechs/rsa/private_key.ts b/src/mechs/rsa/private_key.ts index c3a7559..2f78734 100644 --- a/src/mechs/rsa/private_key.ts +++ b/src/mechs/rsa/private_key.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; @@ -27,7 +28,9 @@ 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"; @@ -36,5 +39,4 @@ export class RsaPrivateKey extends AsymmetricKey { this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); } - } diff --git a/src/mechs/rsa/public_key.ts b/src/mechs/rsa/public_key.ts index 0cc6ec1..f822439 100644 --- a/src/mechs/rsa/public_key.ts +++ b/src/mechs/rsa/public_key.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; @@ -27,7 +28,9 @@ 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"; diff --git a/src/mechs/rsa/rsa_oaep.ts b/src/mechs/rsa/rsa_oaep.ts index 81fac3b..ade1d68 100644 --- a/src/mechs/rsa/rsa_oaep.ts +++ b/src/mechs/rsa/rsa_oaep.ts @@ -1,3 +1,4 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import * as core from "webcrypto-core"; import { RsaCrypto } from "./crypto"; @@ -14,23 +15,31 @@ import { setCryptoKey, getCryptoKey } from "../storage"; */ export class RsaOaepProvider extends core.RsaOaepProvider { - - public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onGenerateKey( + algorithm: RsaHashedKeyGenParams, + extractable: boolean, + keyUsages: KeyUsage[] + ): Promise { 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 { + public async onEncrypt( + algorithm: RsaOaepParams, + key: RsaPublicKey, + data: ArrayBuffer + ): Promise { const internalKey = getCryptoKey(key) as RsaPublicKey; const dataView = new Uint8Array(data); const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); @@ -48,37 +57,59 @@ 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 { + public async onDecrypt( + algorithm: RsaOaepParams, + key: RsaPrivateKey, + data: ArrayBuffer + ): Promise { const internalKey = getCryptoKey(key) as RsaPrivateKey; const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; @@ -89,13 +120,18 @@ 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); @@ -104,18 +140,31 @@ 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]) { @@ -142,19 +191,39 @@ export class RsaOaepProvider extends core.RsaOaepProvider { return new Uint8Array(pkcs0).buffer; } - public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + public async onExportKey( + format: KeyFormat, + key: CryptoKey + ): Promise { return RsaCrypto.exportKey(format, getCryptoKey(key)); } - public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - 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 { + 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"); } } @@ -178,7 +247,8 @@ 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; @@ -191,5 +261,4 @@ export class RsaOaepProvider extends core.RsaOaepProvider { return mask; } - } diff --git a/src/mechs/sha/crypto.ts b/src/mechs/sha/crypto.ts index 8cc13d8..7d5c049 100644 --- a/src/mechs/sha/crypto.ts +++ b/src/mechs/sha/crypto.ts @@ -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,9 +53,7 @@ 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; } - } diff --git a/src/mechs/shake/crypto.ts b/src/mechs/shake/crypto.ts index 11594cd..b68a1fc 100644 --- a/src/mechs/shake/crypto.ts +++ b/src/mechs/shake/crypto.ts @@ -1,13 +1,19 @@ +import { Buffer } from "buffer"; import crypto from "crypto"; import * as core from "webcrypto-core"; export class ShakeCrypto { - - public static digest(algorithm: Required, data: ArrayBuffer) { - const hash = crypto.createHash(algorithm.name.toLowerCase(), {outputLength: algorithm.length}) - .update(Buffer.from(data)).digest(); + public static digest( + algorithm: Required, + data: ArrayBuffer + ) { + const hash = crypto + .createHash(algorithm.name.toLowerCase(), { + outputLength: algorithm.length, + }) + .update(Buffer.from(data)) + .digest(); return new Uint8Array(hash).buffer; } - }