diff --git a/build/webcrypto.es.js b/build/webcrypto.es.js new file mode 100644 index 0000000..d1aa884 --- /dev/null +++ b/build/webcrypto.es.js @@ -0,0 +1,2353 @@ +/*! + Copyright (c) Peculiar Ventures, LLC +*/ + +import * as core from 'webcrypto-core'; +import { BufferSourceConverter as BufferSourceConverter$1 } from 'webcrypto-core'; +export { CryptoKey } from 'webcrypto-core'; +import { Buffer } from 'buffer'; +import * as crypto from 'crypto'; +import crypto__default from 'crypto'; +import * as process from 'process'; +import { __decorate } from 'tslib'; +import { JsonProp, JsonPropTypes, JsonSerializer, JsonParser } from '@peculiar/json-schema'; +import { Convert, BufferSourceConverter } from 'pvtsutils'; +import { AsnParser, AsnSerializer } from '@peculiar/asn1-schema'; + +const JsonBase64UrlConverter = { + fromJSON: (value) => Buffer.from(Convert.FromBase64Url(value)), + toJSON: (value) => Convert.ToBase64Url(value), +}; + +class CryptoKey extends core.CryptoKey { + constructor() { + super(...arguments); + this.data = Buffer.alloc(0); + this.algorithm = { name: "" }; + this.extractable = false; + this.type = "secret"; + this.usages = []; + this.kty = "oct"; + this.alg = ""; + } +} +__decorate([ + JsonProp({ name: "ext", type: JsonPropTypes.Boolean, optional: true }) +], CryptoKey.prototype, "extractable", void 0); +__decorate([ + JsonProp({ + name: "key_ops", + type: JsonPropTypes.String, + repeated: true, + optional: true, + }) +], CryptoKey.prototype, "usages", void 0); +__decorate([ + JsonProp({ type: JsonPropTypes.String }) +], CryptoKey.prototype, "kty", void 0); +__decorate([ + JsonProp({ type: JsonPropTypes.String, optional: true }) +], CryptoKey.prototype, "alg", void 0); + +class SymmetricKey extends CryptoKey { + constructor() { + super(...arguments); + this.kty = "oct"; + this.type = "secret"; + } +} + +class AsymmetricKey extends CryptoKey { +} + +class AesCryptoKey extends SymmetricKey { + get alg() { + switch (this.algorithm.name.toUpperCase()) { + case "AES-CBC": + return `A${this.algorithm.length}CBC`; + case "AES-CTR": + return `A${this.algorithm.length}CTR`; + case "AES-GCM": + return `A${this.algorithm.length}GCM`; + case "AES-KW": + return `A${this.algorithm.length}KW`; + case "AES-CMAC": + return `A${this.algorithm.length}CMAC`; + case "AES-ECB": + return `A${this.algorithm.length}ECB`; + default: + throw new core.AlgorithmError("Unsupported algorithm name"); + } + } + set alg(value) { + } +} +__decorate([ + JsonProp({ name: "k", converter: JsonBase64UrlConverter }) +], AesCryptoKey.prototype, "data", void 0); + +class AesCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const key = new AesCryptoKey(); + key.algorithm = algorithm; + key.extractable = extractable; + key.usages = keyUsages; + key.data = crypto__default.randomBytes(algorithm.length >> 3); + return key; + } + static async exportKey(format, key) { + if (!(key instanceof AesCryptoKey)) { + throw new Error("key: Is not AesCryptoKey"); + } + switch (format.toLowerCase()) { + case "jwk": + return JsonSerializer.toJSON(key); + case "raw": + return new Uint8Array(key.data).buffer; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + let key; + switch (format.toLowerCase()) { + case "jwk": + key = JsonParser.fromJSON(keyData, { targetSchema: AesCryptoKey }); + break; + case "raw": + key = new AesCryptoKey(); + key.data = Buffer.from(keyData); + break; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + key.algorithm = algorithm; + key.algorithm.length = key.data.length << 3; + key.extractable = extractable; + key.usages = keyUsages; + switch (key.algorithm.length) { + case 128: + case 192: + case 256: + break; + default: + throw new core.OperationError("keyData: Is wrong key length"); + } + return key; + } + static async encrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "AES-CBC": + return this.encryptAesCBC(algorithm, key, Buffer.from(data)); + case "AES-CTR": + return this.encryptAesCTR(algorithm, key, Buffer.from(data)); + case "AES-GCM": + return this.encryptAesGCM(algorithm, key, Buffer.from(data)); + case "AES-KW": + return this.encryptAesKW(algorithm, key, Buffer.from(data)); + case "AES-ECB": + return this.encryptAesECB(algorithm, key, Buffer.from(data)); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async decrypt(algorithm, key, data) { + if (!(key instanceof AesCryptoKey)) { + throw new Error("key: Is not AesCryptoKey"); + } + switch (algorithm.name.toUpperCase()) { + case "AES-CBC": + return this.decryptAesCBC(algorithm, key, Buffer.from(data)); + case "AES-CTR": + return this.decryptAesCTR(algorithm, key, Buffer.from(data)); + case "AES-GCM": + return this.decryptAesGCM(algorithm, key, Buffer.from(data)); + case "AES-KW": + return this.decryptAesKW(algorithm, key, Buffer.from(data)); + case "AES-ECB": + return this.decryptAesECB(algorithm, key, Buffer.from(data)); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async encryptAesCBC(algorithm, key, data) { + const cipher = crypto__default.createCipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv)); + let enc = cipher.update(data); + enc = Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesCBC(algorithm, key, data) { + const decipher = crypto__default.createDecipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv)); + let dec = decipher.update(data); + dec = Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesCTR(algorithm, key, data) { + const cipher = crypto__default.createCipheriv(`aes-${key.algorithm.length}-ctr`, key.data, Buffer.from(algorithm.counter)); + let enc = cipher.update(data); + enc = Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesCTR(algorithm, key, data) { + const decipher = crypto__default.createDecipheriv(`aes-${key.algorithm.length}-ctr`, key.data, new Uint8Array(algorithm.counter)); + let dec = decipher.update(data); + dec = Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesGCM(algorithm, key, data) { + const cipher = crypto__default.createCipheriv(`aes-${key.algorithm.length}-gcm`, key.data, Buffer.from(algorithm.iv), { + authTagLength: (algorithm.tagLength || 128) >> 3, + }); + if (algorithm.additionalData) { + cipher.setAAD(Buffer.from(algorithm.additionalData)); + } + let enc = cipher.update(data); + enc = Buffer.concat([enc, cipher.final(), cipher.getAuthTag()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesGCM(algorithm, key, data) { + const decipher = crypto__default.createDecipheriv(`aes-${key.algorithm.length}-gcm`, key.data, new Uint8Array(algorithm.iv)); + const tagLength = (algorithm.tagLength || 128) >> 3; + const enc = data.slice(0, data.length - tagLength); + const tag = data.slice(data.length - tagLength); + if (algorithm.additionalData) { + decipher.setAAD(Buffer.from(algorithm.additionalData)); + } + decipher.setAuthTag(tag); + let dec = decipher.update(enc); + dec = Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesKW(algorithm, key, data) { + const cipher = crypto__default.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; + } + static async decryptAesKW(algorithm, key, data) { + const decipher = crypto__default.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; + } + static async encryptAesECB(algorithm, key, data) { + const cipher = crypto__default.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; + } + static async decryptAesECB(algorithm, key, data) { + const decipher = crypto__default.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; + } +} +AesCrypto.AES_KW_IV = Buffer.from("A6A6A6A6A6A6A6A6", "hex"); + +const keyStorage = new WeakMap(); +function getCryptoKey(key) { + const res = keyStorage.get(key); + if (!res) { + throw new core.OperationError("Cannot get CryptoKey from secure storage"); + } + return res; +} +function setCryptoKey(value) { + const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages); + Object.freeze(key); + keyStorage.set(key, value); + return key; +} + +class AesCbcProvider extends core.AesCbcProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +const zero = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); +const rb = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135]); +const blockSize = 16; +function bitShiftLeft(buffer) { + const shifted = Buffer.alloc(buffer.length); + const last = buffer.length - 1; + for (let index = 0; index < last; index++) { + shifted[index] = buffer[index] << 1; + if (buffer[index + 1] & 0x80) { + shifted[index] += 0x01; + } + } + shifted[last] = buffer[last] << 1; + return shifted; +} +function xor(a, b) { + const length = Math.min(a.length, b.length); + const output = Buffer.alloc(length); + for (let index = 0; index < length; index++) { + output[index] = a[index] ^ b[index]; + } + return output; +} +function aes(key, message) { + const cipher = crypto.createCipheriv(`aes${key.length << 3}`, key, zero); + const result = cipher.update(message); + cipher.final(); + return result; +} +function getMessageBlock(message, blockIndex) { + const block = Buffer.alloc(blockSize); + const start = blockIndex * blockSize; + const end = start + blockSize; + message.copy(block, 0, start, end); + return block; +} +function getPaddedMessageBlock(message, blockIndex) { + const block = Buffer.alloc(blockSize); + const start = blockIndex * blockSize; + const end = message.length; + block.fill(0); + message.copy(block, 0, start, end); + block[end - start] = 0x80; + return block; +} +function generateSubkeys(key) { + const l = aes(key, zero); + let subkey1 = bitShiftLeft(l); + if (l[0] & 0x80) { + subkey1 = xor(subkey1, rb); + } + let subkey2 = bitShiftLeft(subkey1); + if (subkey1[0] & 0x80) { + subkey2 = xor(subkey2, rb); + } + return { subkey1, subkey2 }; +} +function aesCmac(key, message) { + const subkeys = generateSubkeys(key); + let blockCount = Math.ceil(message.length / blockSize); + let lastBlockCompleteFlag; + let lastBlock; + if (blockCount === 0) { + blockCount = 1; + lastBlockCompleteFlag = false; + } + else { + 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); + } + let x = zero; + let y; + for (let index = 0; index < lastBlockIndex; index++) { + y = xor(x, getMessageBlock(message, index)); + x = aes(key, y); + } + y = xor(lastBlock, x); + return aes(key, y); +} +class AesCmacProvider extends core.AesCmacProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onSign(algorithm, key, data) { + const result = aesCmac(getCryptoKey(key).data, Buffer.from(data)); + return new Uint8Array(result).buffer; + } + async onVerify(algorithm, key, signature, data) { + const signature2 = await this.sign(algorithm, key, data); + return Buffer.from(signature).compare(Buffer.from(signature2)) === 0; + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesCtrProvider extends core.AesCtrProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesGcmProvider extends core.AesGcmProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesKwProvider extends core.AesKwProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const res = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(res); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesEcbProvider extends core.AesEcbProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class DesCryptoKey extends SymmetricKey { + get alg() { + switch (this.algorithm.name.toUpperCase()) { + case "DES-CBC": + return `DES-CBC`; + case "DES-EDE3-CBC": + return `3DES-CBC`; + default: + throw new core.AlgorithmError("Unsupported algorithm name"); + } + } + set alg(value) { + } +} +__decorate([ + JsonProp({ name: "k", converter: JsonBase64UrlConverter }) +], DesCryptoKey.prototype, "data", void 0); + +class DesCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const key = new DesCryptoKey(); + key.algorithm = algorithm; + key.extractable = extractable; + key.usages = keyUsages; + key.data = crypto__default.randomBytes(algorithm.length >> 3); + return key; + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return JsonSerializer.toJSON(key); + case "raw": + return new Uint8Array(key.data).buffer; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + let key; + switch (format.toLowerCase()) { + case "jwk": + key = JsonParser.fromJSON(keyData, { targetSchema: DesCryptoKey }); + break; + case "raw": + key = new DesCryptoKey(); + key.data = Buffer.from(keyData); + break; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + key.algorithm = algorithm; + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static async encrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "DES-CBC": + return this.encryptDesCBC(algorithm, key, Buffer.from(data)); + case "DES-EDE3-CBC": + return this.encryptDesEDE3CBC(algorithm, key, Buffer.from(data)); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async decrypt(algorithm, key, data) { + if (!(key instanceof DesCryptoKey)) { + throw new Error("key: Is not DesCryptoKey"); + } + switch (algorithm.name.toUpperCase()) { + case "DES-CBC": + return this.decryptDesCBC(algorithm, key, Buffer.from(data)); + case "DES-EDE3-CBC": + return this.decryptDesEDE3CBC(algorithm, key, Buffer.from(data)); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async encryptDesCBC(algorithm, key, data) { + const cipher = crypto__default.createCipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv)); + let enc = cipher.update(data); + enc = Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptDesCBC(algorithm, key, data) { + const decipher = crypto__default.createDecipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv)); + let dec = decipher.update(data); + dec = Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptDesEDE3CBC(algorithm, key, data) { + const cipher = crypto__default.createCipheriv(`des-ede3-cbc`, key.data, Buffer.from(algorithm.iv)); + let enc = cipher.update(data); + enc = Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptDesEDE3CBC(algorithm, key, data) { + const decipher = crypto__default.createDecipheriv(`des-ede3-cbc`, key.data, new Uint8Array(algorithm.iv)); + let dec = decipher.update(data); + dec = Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } +} + +class DesCbcProvider extends core.DesProvider { + constructor() { + super(...arguments); + this.keySizeBits = 64; + this.ivSize = 8; + this.name = "DES-CBC"; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await DesCrypto.generateKey({ + name: this.name, + length: this.keySizeBits, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return DesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return DesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return DesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + 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); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof DesCryptoKey)) { + throw new TypeError("key: Is not a DesCryptoKey"); + } + } +} + +class DesEde3CbcProvider extends core.DesProvider { + constructor() { + super(...arguments); + this.keySizeBits = 192; + this.ivSize = 8; + this.name = "DES-EDE3-CBC"; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await DesCrypto.generateKey({ + name: this.name, + length: this.keySizeBits, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return DesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return DesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return DesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + 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); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof DesCryptoKey)) { + throw new TypeError("key: Is not a DesCryptoKey"); + } + } +} + +function getJwkAlgorithm(algorithm) { + switch (algorithm.name.toUpperCase()) { + case "RSA-OAEP": { + const mdSize = /(\d+)$/.exec(algorithm.hash.name)[1]; + return `RSA-OAEP${mdSize !== "1" ? `-${mdSize}` : ""}`; + } + case "RSASSA-PKCS1-V1_5": + return `RS${/(\d+)$/.exec(algorithm.hash.name)[1]}`; + case "RSA-PSS": + return `PS${/(\d+)$/.exec(algorithm.hash.name)[1]}`; + case "RSA-PKCS1": + return `RS1`; + default: + throw new core.OperationError("algorithm: Is not recognized"); + } +} + +class RsaPrivateKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "private"; + } + getKey() { + const keyInfo = AsnParser.parse(this.data, core.asn1.PrivateKeyInfo); + return AsnParser.parse(keyInfo.privateKey, core.asn1.RsaPrivateKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "RSA", + alg: getJwkAlgorithm(this.algorithm), + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, JsonSerializer.toJSON(key)); + } + fromJSON(json) { + 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"; + keyInfo.privateKeyAlgorithm.parameters = null; + keyInfo.privateKey = AsnSerializer.serialize(key); + this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + } +} + +class RsaPublicKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "public"; + } + getKey() { + const keyInfo = AsnParser.parse(this.data, core.asn1.PublicKeyInfo); + return AsnParser.parse(keyInfo.publicKey, core.asn1.RsaPublicKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "RSA", + alg: getJwkAlgorithm(this.algorithm), + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, JsonSerializer.toJSON(key)); + } + fromJSON(json) { + 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"; + keyInfo.publicKeyAlgorithm.parameters = null; + keyInfo.publicKey = AsnSerializer.serialize(key); + this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + } +} + +class RsaCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const privateKey = new RsaPrivateKey(); + privateKey.algorithm = algorithm; + privateKey.extractable = extractable; + privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1); + const publicKey = new RsaPublicKey(); + publicKey.algorithm = algorithm; + publicKey.extractable = true; + publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1); + const publicExponent = Buffer.concat([ + Buffer.alloc(4 - algorithm.publicExponent.byteLength, 0), + Buffer.from(algorithm.publicExponent), + ]).readInt32BE(0); + const keys = crypto__default.generateKeyPairSync("rsa", { + modulusLength: algorithm.modulusLength, + publicExponent, + publicKeyEncoding: { + format: "der", + type: "spki", + }, + privateKeyEncoding: { + format: "der", + type: "pkcs8", + }, + }); + privateKey.data = keys.privateKey; + publicKey.data = keys.publicKey; + const res = { + privateKey, + publicKey, + }; + return res; + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return JsonSerializer.toJSON(key); + case "pkcs8": + case "spki": + return new Uint8Array(key.data).buffer; + default: + throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + switch (format.toLowerCase()) { + case "jwk": { + const jwk = keyData; + if (jwk.d) { + 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); + } + } + case "spki": { + const keyInfo = AsnParser.parse(new Uint8Array(keyData), 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), 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'"); + } + } + static async sign(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-PSS": + case "RSASSA-PKCS1-V1_5": + return this.signRsa(algorithm, key, data); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async verify(algorithm, key, signature, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-PSS": + case "RSASSA-PKCS1-V1_5": + return this.verifySSA(algorithm, key, data, signature); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async encrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-OAEP": + return this.encryptOAEP(algorithm, key, data); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static async decrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-OAEP": + return this.decryptOAEP(algorithm, key, data); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + static importPrivateKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core.asn1.PrivateKeyInfo(); + keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; + keyInfo.privateKeyAlgorithm.parameters = null; + keyInfo.privateKey = AsnSerializer.serialize(asnKey); + const key = new RsaPrivateKey(); + key.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.algorithm.publicExponent = new Uint8Array(asnKey.publicExponent); + key.algorithm.modulusLength = asnKey.modulus.byteLength << 3; + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static importPublicKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; + keyInfo.publicKeyAlgorithm.parameters = null; + keyInfo.publicKey = AsnSerializer.serialize(asnKey); + const key = new RsaPublicKey(); + key.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.algorithm.publicExponent = new Uint8Array(asnKey.publicExponent); + key.algorithm.modulusLength = asnKey.modulus.byteLength << 3; + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static getCryptoAlgorithm(alg) { + switch (alg.hash.name.toUpperCase()) { + case "SHA-1": + return "RSA-SHA1"; + case "SHA-256": + return "RSA-SHA256"; + case "SHA-384": + return "RSA-SHA384"; + case "SHA-512": + return "RSA-SHA512"; + case "SHA3-256": + return "RSA-SHA3-256"; + case "SHA3-384": + return "RSA-SHA3-384"; + case "SHA3-512": + return "RSA-SHA3-512"; + default: + throw new core.OperationError("algorithm.hash: Is not recognized"); + } + } + static signRsa(algorithm, key, data) { + const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); + const signer = crypto__default.createSign(cryptoAlg); + signer.update(Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + const options = { + key: key.pem, + }; + if (algorithm.name.toUpperCase() === "RSA-PSS") { + options.padding = crypto__default.constants.RSA_PKCS1_PSS_PADDING; + options.saltLength = algorithm.saltLength; + } + const signature = signer.sign(options); + return new Uint8Array(signature).buffer; + } + static verifySSA(algorithm, key, data, signature) { + const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); + const signer = crypto__default.createVerify(cryptoAlg); + signer.update(Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; + } + const options = { + key: key.pem, + }; + if (algorithm.name.toUpperCase() === "RSA-PSS") { + options.padding = crypto__default.constants.RSA_PKCS1_PSS_PADDING; + options.saltLength = algorithm.saltLength; + } + const ok = signer.verify(options, signature); + return ok; + } + static encryptOAEP(algorithm, key, data) { + const options = { + key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`, + padding: crypto__default.constants.RSA_PKCS1_OAEP_PADDING, + }; + if (algorithm.label) ; + return new Uint8Array(crypto__default.publicEncrypt(options, data)).buffer; + } + static decryptOAEP(algorithm, key, data) { + const options = { + key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`, + padding: crypto__default.constants.RSA_PKCS1_OAEP_PADDING, + }; + if (algorithm.label) ; + return new Uint8Array(crypto__default.privateDecrypt(options, data)).buffer; + } +} +RsaCrypto.publicKeyUsages = ["verify", "encrypt", "wrapKey"]; +RsaCrypto.privateKeyUsages = ["sign", "decrypt", "unwrapKey"]; + +class RsaSsaProvider extends core.RsaSsaProvider { + constructor() { + super(...arguments); + this.hashAlgorithms = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + "shake128", + "shake256", + "SHA3-256", + "SHA3-384", + "SHA3-512", + ]; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return RsaCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return RsaCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } +} + +class RsaPssProvider extends core.RsaPssProvider { + constructor() { + super(...arguments); + this.hashAlgorithms = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + "shake128", + "shake256", + "SHA3-256", + "SHA3-384", + "SHA3-512", + ]; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return RsaCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return RsaCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } +} + +class ShaCrypto { + static size(algorithm) { + switch (algorithm.name.toUpperCase()) { + case "SHA-1": + return 160; + case "SHA-256": + case "SHA3-256": + return 256; + case "SHA-384": + case "SHA3-384": + return 384; + case "SHA-512": + case "SHA3-512": + return 512; + default: + throw new Error("Unrecognized name"); + } + } + static getAlgorithmName(algorithm) { + switch (algorithm.name.toUpperCase()) { + case "SHA-1": + return "sha1"; + case "SHA-256": + return "sha256"; + case "SHA-384": + return "sha384"; + case "SHA-512": + return "sha512"; + case "SHA3-256": + return "sha3-256"; + case "SHA3-384": + return "sha3-384"; + case "SHA3-512": + return "sha3-512"; + default: + throw new Error("Unrecognized name"); + } + } + static digest(algorithm, data) { + const hashAlg = this.getAlgorithmName(algorithm); + const hash = crypto__default.createHash(hashAlg).update(Buffer.from(data)).digest(); + return new Uint8Array(hash).buffer; + } +} + +class RsaOaepProvider extends core.RsaOaepProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onEncrypt(algorithm, key, data) { + const internalKey = getCryptoKey(key); + const dataView = new Uint8Array(data); + const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); + const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; + const dataLength = dataView.byteLength; + const psLength = keySize - dataLength - 2 * hashSize - 2; + if (dataLength > keySize - 2 * hashSize - 2) { + throw new Error("Data too large"); + } + const message = new Uint8Array(keySize); + const seed = message.subarray(1, hashSize + 1); + const dataBlock = message.subarray(hashSize + 1); + dataBlock.set(dataView, hashSize + psLength + 1); + const labelHash = crypto__default + .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__default.randomFillSync(seed); + 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); + 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-----`; + } + const pkcs0 = crypto__default.publicEncrypt({ + key: internalKey.pem, + padding: crypto__default.constants.RSA_NO_PADDING, + }, Buffer.from(message)); + return new Uint8Array(pkcs0).buffer; + } + async onDecrypt(algorithm, key, data) { + const internalKey = getCryptoKey(key); + const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); + const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; + const dataLength = data.byteLength; + if (dataLength !== keySize) { + throw new Error("Bad data"); + } + if (!internalKey.pem) { + internalKey.pem = `-----BEGIN PRIVATE KEY-----\n${internalKey.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + let pkcs0 = crypto__default.privateDecrypt({ + key: internalKey.pem, + padding: crypto__default.constants.RSA_NO_PADDING, + }, Buffer.from(data)); + const z = pkcs0[0]; + const seed = pkcs0.subarray(1, hashSize + 1); + const dataBlock = pkcs0.subarray(hashSize + 1); + if (z !== 0) { + throw new Error("Decryption failed"); + } + 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); + for (let i = 0; i < dataBlock.length; i++) { + dataBlock[i] ^= dataBlockMask[i]; + } + const labelHash = crypto__default + .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]) { + throw new Error("Decryption failed"); + } + } + let psEnd = hashSize; + for (; psEnd < dataBlock.length; psEnd++) { + const psz = dataBlock[psEnd]; + if (psz === 1) { + break; + } + if (psz !== 0) { + throw new Error("Decryption failed"); + } + } + if (psEnd === dataBlock.length) { + throw new Error("Decryption failed"); + } + pkcs0 = dataBlock.subarray(psEnd + 1); + return new Uint8Array(pkcs0).buffer; + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } + mgf1(algorithm, seed, length = 0) { + const hashSize = ShaCrypto.size(algorithm) >> 3; + const mask = new Uint8Array(length); + const counter = new Uint8Array(4); + const chunks = Math.ceil(length / hashSize); + for (let i = 0; i < chunks; i++) { + counter[0] = i >>> 24; + counter[1] = (i >>> 16) & 255; + counter[2] = (i >>> 8) & 255; + counter[3] = i & 255; + const submask = mask.subarray(i * hashSize); + let chunk = crypto__default + .createHash(algorithm.name.replace("-", "")) + .update(seed) + .update(counter) + .digest(); + if (chunk.length > submask.length) { + chunk = chunk.subarray(0, submask.length); + } + submask.set(chunk); + } + return mask; + } +} + +class RsaEsProvider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "RSAES-PKCS1-v1_5"; + this.usages = { + publicKey: ["encrypt", "wrapKey"], + privateKey: ["decrypt", "unwrapKey"], + }; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + checkGenerateKeyParams(algorithm) { + this.checkRequiredProperty(algorithm, "publicExponent"); + if (!(algorithm.publicExponent && + algorithm.publicExponent instanceof Uint8Array)) { + throw new TypeError("publicExponent: Missing or not a Uint8Array"); + } + const publicExponent = Convert.ToBase64(algorithm.publicExponent); + if (!(publicExponent === "Aw==" || publicExponent === "AQAB")) { + throw new TypeError("publicExponent: Must be [3] or [1,0,1]"); + } + this.checkRequiredProperty(algorithm, "modulusLength"); + switch (algorithm.modulusLength) { + case 1024: + case 2048: + case 4096: + break; + default: + throw new TypeError("modulusLength: Must be 1024, 2048, or 4096"); + } + } + async onEncrypt(algorithm, key, data) { + const options = this.toCryptoOptions(key); + const enc = crypto.publicEncrypt(options, new Uint8Array(data)); + return new Uint8Array(enc).buffer; + } + async onDecrypt(algorithm, key, data) { + const options = this.toCryptoOptions(key); + const dec = crypto.privateDecrypt(options, new Uint8Array(data)); + return new Uint8Array(dec).buffer; + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } + toCryptoOptions(key) { + const type = key.type.toUpperCase(); + return { + key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`, + padding: crypto.constants.RSA_PKCS1_PADDING, + }; + } +} + +const namedOIDs = { + "1.2.840.10045.3.1.7": "P-256", + "P-256": "1.2.840.10045.3.1.7", + "1.3.132.0.34": "P-384", + "P-384": "1.3.132.0.34", + "1.3.132.0.35": "P-521", + "P-521": "1.3.132.0.35", + "1.3.132.0.10": "K-256", + "K-256": "1.3.132.0.10", + 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", + "1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1", + 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", + "1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1", + 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", + "1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1", + 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", + "1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1", + 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", + "1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1", + 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", + "1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1", + 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", + "1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1", +}; +function getOidByNamedCurve$1(namedCurve) { + const oid = namedOIDs[namedCurve]; + if (!oid) { + throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); + } + return oid; +} + +class EcPrivateKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "private"; + } + getKey() { + const keyInfo = AsnParser.parse(this.data, core.asn1.PrivateKeyInfo); + return AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "EC", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, JsonSerializer.toJSON(key)); + } + fromJSON(json) { + if (!json.crv) { + 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$1(json.crv))); + const key = JsonParser.fromJSON(json, { + targetSchema: core.asn1.EcPrivateKey, + }); + keyInfo.privateKey = AsnSerializer.serialize(key); + this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class EcPublicKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "public"; + } + getKey() { + const keyInfo = AsnParser.parse(this.data, core.asn1.PublicKeyInfo); + return new core.asn1.EcPublicKey(keyInfo.publicKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "EC", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, JsonSerializer.toJSON(key)); + } + fromJSON(json) { + if (!json.crv) { + throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); + } + 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$1(json.crv))); + keyInfo.publicKey = AsnSerializer.toASN(key).valueHex; + this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class Sha1Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-1"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha256Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-256"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha384Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-384"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha512Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-512"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha3256Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA3-256"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha3384Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA3-384"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha3512Provider extends core.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA3-512"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class EcCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const privateKey = new EcPrivateKey(); + privateKey.algorithm = algorithm; + privateKey.extractable = extractable; + 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); + const keys = crypto__default.generateKeyPairSync("ec", { + namedCurve: this.getOpenSSLNamedCurve(algorithm.namedCurve), + publicKeyEncoding: { + format: "der", + type: "spki", + }, + privateKeyEncoding: { + format: "der", + type: "pkcs8", + }, + }); + privateKey.data = keys.privateKey; + publicKey.data = keys.publicKey; + const res = { + privateKey, + publicKey, + }; + return res; + } + static async sign(algorithm, key, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash); + const signer = crypto__default.createSign(cryptoAlg); + signer.update(Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + const options = { + key: key.pem, + }; + 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); + return signatureRaw.buffer; + } + static async verify(algorithm, key, signature, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash); + const signer = crypto__default.createVerify(cryptoAlg); + signer.update(Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; + } + const options = { + key: key.pem, + }; + const ecSignature = new core.asn1.EcDsaSignature(); + const namedCurve = core.EcCurves.get(key.algorithm.namedCurve); + const signaturePoint = core.EcUtils.decodeSignature(signature, namedCurve.size); + ecSignature.r = BufferSourceConverter.toArrayBuffer(signaturePoint.r); + ecSignature.s = BufferSourceConverter.toArrayBuffer(signaturePoint.s); + const ecSignatureRaw = Buffer.from(AsnSerializer.serialize(ecSignature)); + const ok = signer.verify(options, ecSignatureRaw); + return ok; + } + static async deriveBits(algorithm, baseKey, length) { + const cryptoAlg = this.getOpenSSLNamedCurve(baseKey.algorithm.namedCurve); + const ecdh = crypto__default.createECDH(cryptoAlg); + 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.data, core.asn1.PublicKeyInfo); + const bits = ecdh.computeSecret(Buffer.from(asnPublicKey.publicKey)); + if (length === null) { + return bits; + } + return new Uint8Array(bits).buffer.slice(0, length >> 3); + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return JsonSerializer.toJSON(key); + case "pkcs8": + case "spki": + return new Uint8Array(key.data).buffer; + case "raw": { + 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'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + switch (format.toLowerCase()) { + case "jwk": { + const jwk = keyData; + if (jwk.d) { + 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); + } + } + case "raw": { + const asnKey = new core.asn1.EcPublicKey(keyData); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + case "spki": { + const keyInfo = AsnParser.parse(new Uint8Array(keyData), core.asn1.PublicKeyInfo); + const asnKey = new core.asn1.EcPublicKey(keyInfo.publicKey); + this.assertKeyParameters(keyInfo.publicKeyAlgorithm.parameters, algorithm.namedCurve); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + case "pkcs8": { + const keyInfo = AsnParser.parse(new Uint8Array(keyData), 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'"); + } + } + static assertKeyParameters(parameters, namedCurve) { + if (!parameters) { + throw new core.CryptoError("Key info doesn't have required parameters"); + } + let namedCurveIdentifier = ""; + try { + namedCurveIdentifier = AsnParser.parse(parameters, core.asn1.ObjectIdentifier).value; + } + catch (e) { + throw new core.CryptoError("Cannot read key info parameters"); + } + if (getOidByNamedCurve$1(namedCurve) !== namedCurveIdentifier) { + throw new core.CryptoError("Key info parameter doesn't match to named curve"); + } + } + static async importPrivateKey(asnKey, algorithm, extractable, keyUsages) { + 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$1(algorithm.namedCurve))); + keyInfo.privateKey = AsnSerializer.serialize(asnKey); + const key = new EcPrivateKey(); + key.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static async importPublicKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; + const namedCurve = getOidByNamedCurve$1(algorithm.namedCurve); + keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(namedCurve)); + keyInfo.publicKey = asnKey.value; + const key = new EcPublicKey(); + key.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static getOpenSSLNamedCurve(curve) { + switch (curve.toUpperCase()) { + case "P-256": + return "prime256v1"; + case "K-256": + return "secp256k1"; + case "P-384": + return "secp384r1"; + case "P-521": + return "secp521r1"; + default: + return curve; + } + } +} +EcCrypto.publicKeyUsages = ["verify"]; +EcCrypto.privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; + +class EcdsaProvider extends core.EcdsaProvider { + constructor() { + super(...arguments); + this.namedCurves = core.EcCurves.names; + this.hashAlgorithms = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + "shake128", + "shake256", + "SHA3-256", + "SHA3-384", + "SHA3-512", + ]; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EcCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return EcCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return EcCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return EcCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof EcPrivateKey || + internalKey instanceof EcPublicKey)) { + throw new TypeError("key: Is not EC CryptoKey"); + } + } +} + +class EcdhProvider extends core.EcdhProvider { + constructor() { + super(...arguments); + this.namedCurves = core.EcCurves.names; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EcCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onExportKey(format, key) { + return EcCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof EcPrivateKey || + internalKey instanceof EcPublicKey)) { + throw new TypeError("key: Is not EC CryptoKey"); + } + } + async onDeriveBits(algorithm, baseKey, length) { + const bits = await EcCrypto.deriveBits({ ...algorithm, public: getCryptoKey(algorithm.public) }, getCryptoKey(baseKey), length); + return bits; + } +} + +const edOIDs = { + [core.asn1.idEd448]: "Ed448", + ed448: core.asn1.idEd448, + [core.asn1.idX448]: "X448", + x448: core.asn1.idX448, + [core.asn1.idEd25519]: "Ed25519", + ed25519: core.asn1.idEd25519, + [core.asn1.idX25519]: "X25519", + x25519: core.asn1.idX25519, +}; +function getOidByNamedCurve(namedCurve) { + const oid = edOIDs[namedCurve.toLowerCase()]; + if (!oid) { + throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); + } + return oid; +} + +class EdPrivateKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "private"; + } + getKey() { + const keyInfo = AsnParser.parse(this.data, core.asn1.PrivateKeyInfo); + return AsnParser.parse(keyInfo.privateKey, core.asn1.CurvePrivateKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "OKP", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, JsonSerializer.toJSON(key)); + } + fromJSON(json) { + if (!json.crv) { + 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, + }); + keyInfo.privateKey = AsnSerializer.serialize(key); + this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class EdPublicKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "public"; + } + getKey() { + const keyInfo = AsnParser.parse(this.data, core.asn1.PublicKeyInfo); + return keyInfo.publicKey; + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "OKP", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, { + x: Convert.ToBase64Url(key), + }); + } + fromJSON(json) { + if (!json.crv) { + 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`); + } + const keyInfo = new core.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = getOidByNamedCurve(json.crv); + keyInfo.publicKey = Convert.FromBase64Url(json.x); + this.data = Buffer.from(AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class EdCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const privateKey = new EdPrivateKey(); + privateKey.algorithm = algorithm; + privateKey.extractable = extractable; + 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); + const type = algorithm.namedCurve.toLowerCase(); + const keys = crypto__default.generateKeyPairSync(type, { + publicKeyEncoding: { + format: "der", + type: "spki", + }, + privateKeyEncoding: { + format: "der", + type: "pkcs8", + }, + }); + privateKey.data = keys.privateKey; + publicKey.data = keys.publicKey; + const res = { + privateKey, + publicKey, + }; + return res; + } + static async sign(algorithm, key, data) { + if (!key.pem) { + key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + const options = { + key: key.pem, + }; + const signature = crypto__default.sign(null, Buffer.from(data), options); + return core.BufferSourceConverter.toArrayBuffer(signature); + } + static async verify(algorithm, key, signature, data) { + if (!key.pem) { + key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; + } + const options = { + key: key.pem, + }; + const ok = crypto__default.verify(null, Buffer.from(data), options, Buffer.from(signature)); + return ok; + } + static async deriveBits(algorithm, baseKey, length) { + const publicKey = crypto__default.createPublicKey({ + key: algorithm.public.data, + format: "der", + type: "spki", + }); + const privateKey = crypto__default.createPrivateKey({ + key: baseKey.data, + format: "der", + type: "pkcs8", + }); + const bits = crypto__default.diffieHellman({ + publicKey, + privateKey, + }); + return new Uint8Array(bits).buffer.slice(0, length >> 3); + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return JsonSerializer.toJSON(key); + case "pkcs8": + case "spki": + return new Uint8Array(key.data).buffer; + case "raw": { + 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'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + switch (format.toLowerCase()) { + case "jwk": { + const jwk = keyData; + if (jwk.d) { + 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); + } + } + case "raw": { + return this.importPublicKey(keyData, algorithm, extractable, keyUsages); + } + case "spki": { + const keyInfo = AsnParser.parse(new Uint8Array(keyData), core.asn1.PublicKeyInfo); + return this.importPublicKey(keyInfo.publicKey, algorithm, extractable, keyUsages); + } + case "pkcs8": { + const keyInfo = AsnParser.parse(new Uint8Array(keyData), 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'"); + } + } + static importPrivateKey(asnKey, algorithm, extractable, keyUsages) { + const key = new EdPrivateKey(); + key.fromJSON({ + crv: algorithm.namedCurve, + d: Convert.ToBase64Url(asnKey.d), + }); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static async importPublicKey(asnKey, algorithm, extractable, keyUsages) { + const key = new EdPublicKey(); + key.fromJSON({ + crv: algorithm.namedCurve, + x: Convert.ToBase64Url(asnKey), + }); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } +} +EdCrypto.publicKeyUsages = ["verify"]; +EdCrypto.privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; + +class EdDsaProvider extends core.EdDsaProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EdCrypto.generateKey({ + name: this.name, + namedCurve: algorithm.namedCurve.replace(/^ed/i, "Ed"), + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return EdCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return EdCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return EdCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } +} + +class EcdhEsProvider extends core.EcdhEsProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EdCrypto.generateKey({ + name: this.name, + namedCurve: algorithm.namedCurve.toUpperCase(), + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onDeriveBits(algorithm, baseKey, length) { + const bits = await EdCrypto.deriveBits({ ...algorithm, public: getCryptoKey(algorithm.public) }, getCryptoKey(baseKey), length); + return bits; + } + async onExportKey(format, key) { + return EdCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } +} + +class PbkdfCryptoKey extends CryptoKey { +} + +class Pbkdf2Provider extends core.Pbkdf2Provider { + async onDeriveBits(algorithm, baseKey, length) { + return new Promise((resolve, reject) => { + const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt); + const hash = algorithm.hash.name.replace("-", ""); + crypto__default.pbkdf2(getCryptoKey(baseKey).data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => { + if (err) { + reject(err); + } + else { + resolve(new Uint8Array(derivedBits).buffer); + } + }); + }); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + if (format === "raw") { + const key = new PbkdfCryptoKey(); + key.data = Buffer.from(keyData); + key.algorithm = { name: this.name }; + key.extractable = false; + key.usages = keyUsages; + return setCryptoKey(key); + } + throw new core.OperationError("format: Must be 'raw'"); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof PbkdfCryptoKey)) { + throw new TypeError("key: Is not PBKDF CryptoKey"); + } + } +} + +class HmacCryptoKey extends CryptoKey { + get alg() { + const hash = this.algorithm.hash.name.toUpperCase(); + return `HS${hash.replace("SHA-", "")}`; + } + set alg(value) { + } +} +__decorate([ + JsonProp({ name: "k", converter: JsonBase64UrlConverter }) +], HmacCryptoKey.prototype, "data", void 0); + +class HmacProvider extends core.HmacProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const length = ((algorithm.length || + this.getDefaultLength(algorithm.hash.name)) >> + 3) << + 3; + const key = new HmacCryptoKey(); + key.algorithm = { + ...algorithm, + length, + name: this.name, + }; + key.extractable = extractable; + key.usages = keyUsages; + key.data = crypto__default.randomBytes(length >> 3); + return setCryptoKey(key); + } + async onSign(algorithm, key, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash); + const hmac = crypto__default + .createHmac(cryptoAlg, getCryptoKey(key).data) + .update(Buffer.from(data)) + .digest(); + return new Uint8Array(hmac).buffer; + } + async onVerify(algorithm, key, signature, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash); + const hmac = crypto__default + .createHmac(cryptoAlg, getCryptoKey(key).data) + .update(Buffer.from(data)) + .digest(); + return hmac.compare(Buffer.from(signature)) === 0; + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + let key; + switch (format.toLowerCase()) { + case "jwk": + key = JsonParser.fromJSON(keyData, { targetSchema: HmacCryptoKey }); + break; + case "raw": + key = new HmacCryptoKey(); + key.data = Buffer.from(keyData); + break; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + key.algorithm = { + hash: { name: algorithm.hash.name }, + name: this.name, + length: key.data.length << 3, + }; + key.extractable = extractable; + key.usages = keyUsages; + return setCryptoKey(key); + } + async onExportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return JsonSerializer.toJSON(getCryptoKey(key)); + case "raw": + return new Uint8Array(getCryptoKey(key).data).buffer; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof HmacCryptoKey)) { + throw new TypeError("key: Is not HMAC CryptoKey"); + } + } +} + +class HkdfCryptoKey extends CryptoKey { +} + +class HkdfProvider extends core.HkdfProvider { + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + if (format.toLowerCase() !== "raw") { + throw new core.OperationError("Operation not supported"); + } + const key = new HkdfCryptoKey(); + key.data = Buffer.from(keyData); + key.algorithm = { name: this.name }; + key.extractable = extractable; + key.usages = keyUsages; + return setCryptoKey(key); + } + async onDeriveBits(params, baseKey, length) { + const hash = params.hash.name.replace("-", ""); + const hashLength = crypto__default.createHash(hash).digest().length; + const byteLength = length / 8; + const info = BufferSourceConverter$1.toUint8Array(params.info); + const PRK = crypto__default + .createHmac(hash, BufferSourceConverter$1.toUint8Array(params.salt)) + .update(BufferSourceConverter$1.toUint8Array(getCryptoKey(baseKey).data)) + .digest(); + const blocks = [Buffer.alloc(0)]; + const blockCount = Math.ceil(byteLength / hashLength) + 1; + for (let i = 1; i < blockCount; ++i) { + blocks.push(crypto__default + .createHmac(hash, PRK) + .update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])])) + .digest()); + } + return Buffer.concat(blocks).slice(0, byteLength); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof HkdfCryptoKey)) { + throw new TypeError("key: Is not HKDF CryptoKey"); + } + } +} + +class ShakeCrypto { + static digest(algorithm, data) { + const hash = crypto__default + .createHash(algorithm.name.toLowerCase(), { + outputLength: algorithm.length, + }) + .update(Buffer.from(data)) + .digest(); + return new Uint8Array(hash).buffer; + } +} + +class Shake128Provider extends core.Shake128Provider { + async onDigest(algorithm, data) { + return ShakeCrypto.digest(algorithm, data); + } +} + +class Shake256Provider extends core.Shake256Provider { + async onDigest(algorithm, data) { + return ShakeCrypto.digest(algorithm, data); + } +} + +class SubtleCrypto extends core.SubtleCrypto { + constructor() { + var _a; + super(); + this.providers.set(new AesCbcProvider()); + this.providers.set(new AesCtrProvider()); + this.providers.set(new AesGcmProvider()); + this.providers.set(new AesCmacProvider()); + this.providers.set(new AesKwProvider()); + this.providers.set(new AesEcbProvider()); + const ciphers = crypto.getCiphers(); + if (ciphers.includes("des-cbc")) { + this.providers.set(new DesCbcProvider()); + } + this.providers.set(new DesEde3CbcProvider()); + this.providers.set(new RsaSsaProvider()); + this.providers.set(new RsaPssProvider()); + this.providers.set(new RsaOaepProvider()); + this.providers.set(new RsaEsProvider()); + this.providers.set(new EcdsaProvider()); + this.providers.set(new EcdhProvider()); + this.providers.set(new Sha1Provider()); + this.providers.set(new Sha256Provider()); + this.providers.set(new Sha384Provider()); + this.providers.set(new Sha512Provider()); + this.providers.set(new Pbkdf2Provider()); + this.providers.set(new HmacProvider()); + this.providers.set(new HkdfProvider()); + const nodeMajorVersion = (_a = /^v(\d+)/.exec(process.version)) === null || _a === void 0 ? void 0 : _a[1]; + if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 12) { + this.providers.set(new Shake128Provider()); + this.providers.set(new Shake256Provider()); + } + const hashes = crypto.getHashes(); + if (hashes.includes("sha3-256")) { + this.providers.set(new Sha3256Provider()); + } + if (hashes.includes("sha3-384")) { + this.providers.set(new Sha3384Provider()); + } + if (hashes.includes("sha3-512")) { + this.providers.set(new Sha3512Provider()); + } + if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 14) { + this.providers.set(new EdDsaProvider()); + this.providers.set(new EcdhEsProvider()); + } + } +} + +class Crypto extends core.Crypto { + constructor() { + super(...arguments); + this.subtle = new SubtleCrypto(); + } + getRandomValues(array) { + if (!ArrayBuffer.isView(array)) { + 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); + crypto__default.randomFillSync(buffer); + return array; + } +} + +export { Crypto }; diff --git a/build/webcrypto.js b/build/webcrypto.js new file mode 100644 index 0000000..79409c9 --- /dev/null +++ b/build/webcrypto.js @@ -0,0 +1,2377 @@ +/*! + Copyright (c) Peculiar Ventures, LLC +*/ + +'use strict'; + +var core = require('webcrypto-core'); +var buffer = require('buffer'); +var crypto = require('crypto'); +var process = require('process'); +var tslib = require('tslib'); +var jsonSchema = require('@peculiar/json-schema'); +var pvtsutils = require('pvtsutils'); +var asn1Schema = require('@peculiar/asn1-schema'); + +function _interopNamespaceDefault(e) { + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n.default = e; + return Object.freeze(n); +} + +var core__namespace = /*#__PURE__*/_interopNamespaceDefault(core); +var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto); +var process__namespace = /*#__PURE__*/_interopNamespaceDefault(process); + +const JsonBase64UrlConverter = { + fromJSON: (value) => buffer.Buffer.from(pvtsutils.Convert.FromBase64Url(value)), + toJSON: (value) => pvtsutils.Convert.ToBase64Url(value), +}; + +class CryptoKey extends core__namespace.CryptoKey { + constructor() { + super(...arguments); + this.data = buffer.Buffer.alloc(0); + this.algorithm = { name: "" }; + this.extractable = false; + this.type = "secret"; + this.usages = []; + this.kty = "oct"; + this.alg = ""; + } +} +tslib.__decorate([ + jsonSchema.JsonProp({ name: "ext", type: jsonSchema.JsonPropTypes.Boolean, optional: true }) +], CryptoKey.prototype, "extractable", void 0); +tslib.__decorate([ + jsonSchema.JsonProp({ + name: "key_ops", + type: jsonSchema.JsonPropTypes.String, + repeated: true, + optional: true, + }) +], CryptoKey.prototype, "usages", void 0); +tslib.__decorate([ + jsonSchema.JsonProp({ type: jsonSchema.JsonPropTypes.String }) +], CryptoKey.prototype, "kty", void 0); +tslib.__decorate([ + jsonSchema.JsonProp({ type: jsonSchema.JsonPropTypes.String, optional: true }) +], CryptoKey.prototype, "alg", void 0); + +class SymmetricKey extends CryptoKey { + constructor() { + super(...arguments); + this.kty = "oct"; + this.type = "secret"; + } +} + +class AsymmetricKey extends CryptoKey { +} + +class AesCryptoKey extends SymmetricKey { + get alg() { + switch (this.algorithm.name.toUpperCase()) { + case "AES-CBC": + return `A${this.algorithm.length}CBC`; + case "AES-CTR": + return `A${this.algorithm.length}CTR`; + case "AES-GCM": + return `A${this.algorithm.length}GCM`; + case "AES-KW": + return `A${this.algorithm.length}KW`; + case "AES-CMAC": + return `A${this.algorithm.length}CMAC`; + case "AES-ECB": + return `A${this.algorithm.length}ECB`; + default: + throw new core__namespace.AlgorithmError("Unsupported algorithm name"); + } + } + set alg(value) { + } +} +tslib.__decorate([ + jsonSchema.JsonProp({ name: "k", converter: JsonBase64UrlConverter }) +], AesCryptoKey.prototype, "data", void 0); + +class AesCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const key = new AesCryptoKey(); + key.algorithm = algorithm; + key.extractable = extractable; + key.usages = keyUsages; + key.data = crypto.randomBytes(algorithm.length >> 3); + return key; + } + static async exportKey(format, key) { + if (!(key instanceof AesCryptoKey)) { + throw new Error("key: Is not AesCryptoKey"); + } + switch (format.toLowerCase()) { + case "jwk": + return jsonSchema.JsonSerializer.toJSON(key); + case "raw": + return new Uint8Array(key.data).buffer; + default: + throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + let key; + switch (format.toLowerCase()) { + case "jwk": + key = jsonSchema.JsonParser.fromJSON(keyData, { targetSchema: AesCryptoKey }); + break; + case "raw": + key = new AesCryptoKey(); + key.data = buffer.Buffer.from(keyData); + break; + default: + throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); + } + key.algorithm = algorithm; + key.algorithm.length = key.data.length << 3; + key.extractable = extractable; + key.usages = keyUsages; + switch (key.algorithm.length) { + case 128: + case 192: + case 256: + break; + default: + throw new core__namespace.OperationError("keyData: Is wrong key length"); + } + return key; + } + static async encrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "AES-CBC": + return this.encryptAesCBC(algorithm, key, buffer.Buffer.from(data)); + case "AES-CTR": + return this.encryptAesCTR(algorithm, key, buffer.Buffer.from(data)); + case "AES-GCM": + return this.encryptAesGCM(algorithm, key, buffer.Buffer.from(data)); + case "AES-KW": + return this.encryptAesKW(algorithm, key, buffer.Buffer.from(data)); + case "AES-ECB": + return this.encryptAesECB(algorithm, key, buffer.Buffer.from(data)); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async decrypt(algorithm, key, data) { + if (!(key instanceof AesCryptoKey)) { + throw new Error("key: Is not AesCryptoKey"); + } + switch (algorithm.name.toUpperCase()) { + case "AES-CBC": + return this.decryptAesCBC(algorithm, key, buffer.Buffer.from(data)); + case "AES-CTR": + return this.decryptAesCTR(algorithm, key, buffer.Buffer.from(data)); + case "AES-GCM": + return this.decryptAesGCM(algorithm, key, buffer.Buffer.from(data)); + case "AES-KW": + return this.decryptAesKW(algorithm, key, buffer.Buffer.from(data)); + case "AES-ECB": + return this.decryptAesECB(algorithm, key, buffer.Buffer.from(data)); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async encryptAesCBC(algorithm, key, data) { + const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv)); + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesCBC(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv)); + let dec = decipher.update(data); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesCTR(algorithm, key, data) { + const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ctr`, key.data, buffer.Buffer.from(algorithm.counter)); + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesCTR(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ctr`, key.data, new Uint8Array(algorithm.counter)); + let dec = decipher.update(data); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesGCM(algorithm, key, data) { + const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-gcm`, key.data, buffer.Buffer.from(algorithm.iv), { + authTagLength: (algorithm.tagLength || 128) >> 3, + }); + if (algorithm.additionalData) { + cipher.setAAD(buffer.Buffer.from(algorithm.additionalData)); + } + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final(), cipher.getAuthTag()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesGCM(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-gcm`, key.data, new Uint8Array(algorithm.iv)); + const tagLength = (algorithm.tagLength || 128) >> 3; + const enc = data.slice(0, data.length - tagLength); + const tag = data.slice(data.length - tagLength); + if (algorithm.additionalData) { + decipher.setAAD(buffer.Buffer.from(algorithm.additionalData)); + } + decipher.setAuthTag(tag); + let dec = decipher.update(enc); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesKW(algorithm, key, data) { + const cipher = crypto.createCipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV); + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final()]); + return new Uint8Array(enc).buffer; + } + static async decryptAesKW(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV); + let dec = decipher.update(data); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptAesECB(algorithm, key, data) { + const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0)); + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptAesECB(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0)); + let dec = decipher.update(data); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } +} +AesCrypto.AES_KW_IV = buffer.Buffer.from("A6A6A6A6A6A6A6A6", "hex"); + +const keyStorage = new WeakMap(); +function getCryptoKey(key) { + const res = keyStorage.get(key); + if (!res) { + throw new core__namespace.OperationError("Cannot get CryptoKey from secure storage"); + } + return res; +} +function setCryptoKey(value) { + const key = core__namespace.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages); + Object.freeze(key); + keyStorage.set(key, value); + return key; +} + +class AesCbcProvider extends core__namespace.AesCbcProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +const zero = buffer.Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); +const rb = buffer.Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135]); +const blockSize = 16; +function bitShiftLeft(buffer$1) { + const shifted = buffer.Buffer.alloc(buffer$1.length); + const last = buffer$1.length - 1; + for (let index = 0; index < last; index++) { + shifted[index] = buffer$1[index] << 1; + if (buffer$1[index + 1] & 0x80) { + shifted[index] += 0x01; + } + } + shifted[last] = buffer$1[last] << 1; + return shifted; +} +function xor(a, b) { + const length = Math.min(a.length, b.length); + const output = buffer.Buffer.alloc(length); + for (let index = 0; index < length; index++) { + output[index] = a[index] ^ b[index]; + } + return output; +} +function aes(key, message) { + const cipher = crypto__namespace.createCipheriv(`aes${key.length << 3}`, key, zero); + const result = cipher.update(message); + cipher.final(); + return result; +} +function getMessageBlock(message, blockIndex) { + const block = buffer.Buffer.alloc(blockSize); + const start = blockIndex * blockSize; + const end = start + blockSize; + message.copy(block, 0, start, end); + return block; +} +function getPaddedMessageBlock(message, blockIndex) { + const block = buffer.Buffer.alloc(blockSize); + const start = blockIndex * blockSize; + const end = message.length; + block.fill(0); + message.copy(block, 0, start, end); + block[end - start] = 0x80; + return block; +} +function generateSubkeys(key) { + const l = aes(key, zero); + let subkey1 = bitShiftLeft(l); + if (l[0] & 0x80) { + subkey1 = xor(subkey1, rb); + } + let subkey2 = bitShiftLeft(subkey1); + if (subkey1[0] & 0x80) { + subkey2 = xor(subkey2, rb); + } + return { subkey1, subkey2 }; +} +function aesCmac(key, message) { + const subkeys = generateSubkeys(key); + let blockCount = Math.ceil(message.length / blockSize); + let lastBlockCompleteFlag; + let lastBlock; + if (blockCount === 0) { + blockCount = 1; + lastBlockCompleteFlag = false; + } + else { + 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); + } + let x = zero; + let y; + for (let index = 0; index < lastBlockIndex; index++) { + y = xor(x, getMessageBlock(message, index)); + x = aes(key, y); + } + y = xor(lastBlock, x); + return aes(key, y); +} +class AesCmacProvider extends core__namespace.AesCmacProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onSign(algorithm, key, data) { + const result = aesCmac(getCryptoKey(key).data, buffer.Buffer.from(data)); + return new Uint8Array(result).buffer; + } + async onVerify(algorithm, key, signature, data) { + const signature2 = await this.sign(algorithm, key, data); + return buffer.Buffer.from(signature).compare(buffer.Buffer.from(signature2)) === 0; + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesCtrProvider extends core__namespace.AesCtrProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesGcmProvider extends core__namespace.AesGcmProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesKwProvider extends core__namespace.AesKwProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const res = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(res); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class AesEcbProvider extends core__namespace.AesEcbProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await AesCrypto.generateKey({ + name: this.name, + length: algorithm.length, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return AesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} + +class DesCryptoKey extends SymmetricKey { + get alg() { + switch (this.algorithm.name.toUpperCase()) { + case "DES-CBC": + return `DES-CBC`; + case "DES-EDE3-CBC": + return `3DES-CBC`; + default: + throw new core__namespace.AlgorithmError("Unsupported algorithm name"); + } + } + set alg(value) { + } +} +tslib.__decorate([ + jsonSchema.JsonProp({ name: "k", converter: JsonBase64UrlConverter }) +], DesCryptoKey.prototype, "data", void 0); + +class DesCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const key = new DesCryptoKey(); + key.algorithm = algorithm; + key.extractable = extractable; + key.usages = keyUsages; + key.data = crypto.randomBytes(algorithm.length >> 3); + return key; + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return jsonSchema.JsonSerializer.toJSON(key); + case "raw": + return new Uint8Array(key.data).buffer; + default: + throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + let key; + switch (format.toLowerCase()) { + case "jwk": + key = jsonSchema.JsonParser.fromJSON(keyData, { targetSchema: DesCryptoKey }); + break; + case "raw": + key = new DesCryptoKey(); + key.data = buffer.Buffer.from(keyData); + break; + default: + throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); + } + key.algorithm = algorithm; + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static async encrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "DES-CBC": + return this.encryptDesCBC(algorithm, key, buffer.Buffer.from(data)); + case "DES-EDE3-CBC": + return this.encryptDesEDE3CBC(algorithm, key, buffer.Buffer.from(data)); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async decrypt(algorithm, key, data) { + if (!(key instanceof DesCryptoKey)) { + throw new Error("key: Is not DesCryptoKey"); + } + switch (algorithm.name.toUpperCase()) { + case "DES-CBC": + return this.decryptDesCBC(algorithm, key, buffer.Buffer.from(data)); + case "DES-EDE3-CBC": + return this.decryptDesEDE3CBC(algorithm, key, buffer.Buffer.from(data)); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async encryptDesCBC(algorithm, key, data) { + const cipher = crypto.createCipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv)); + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptDesCBC(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv)); + let dec = decipher.update(data); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } + static async encryptDesEDE3CBC(algorithm, key, data) { + const cipher = crypto.createCipheriv(`des-ede3-cbc`, key.data, buffer.Buffer.from(algorithm.iv)); + let enc = cipher.update(data); + enc = buffer.Buffer.concat([enc, cipher.final()]); + const res = new Uint8Array(enc).buffer; + return res; + } + static async decryptDesEDE3CBC(algorithm, key, data) { + const decipher = crypto.createDecipheriv(`des-ede3-cbc`, key.data, new Uint8Array(algorithm.iv)); + let dec = decipher.update(data); + dec = buffer.Buffer.concat([dec, decipher.final()]); + return new Uint8Array(dec).buffer; + } +} + +class DesCbcProvider extends core__namespace.DesProvider { + constructor() { + super(...arguments); + this.keySizeBits = 64; + this.ivSize = 8; + this.name = "DES-CBC"; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await DesCrypto.generateKey({ + name: this.name, + length: this.keySizeBits, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return DesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return DesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return DesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + 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__namespace.OperationError("keyData: Wrong key size"); + } + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof DesCryptoKey)) { + throw new TypeError("key: Is not a DesCryptoKey"); + } + } +} + +class DesEde3CbcProvider extends core__namespace.DesProvider { + constructor() { + super(...arguments); + this.keySizeBits = 192; + this.ivSize = 8; + this.name = "DES-EDE3-CBC"; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const key = await DesCrypto.generateKey({ + name: this.name, + length: this.keySizeBits, + }, extractable, keyUsages); + return setCryptoKey(key); + } + async onEncrypt(algorithm, key, data) { + return DesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onDecrypt(algorithm, key, data) { + return DesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onExportKey(format, key) { + return DesCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + 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__namespace.OperationError("keyData: Wrong key size"); + } + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof DesCryptoKey)) { + throw new TypeError("key: Is not a DesCryptoKey"); + } + } +} + +function getJwkAlgorithm(algorithm) { + switch (algorithm.name.toUpperCase()) { + case "RSA-OAEP": { + const mdSize = /(\d+)$/.exec(algorithm.hash.name)[1]; + return `RSA-OAEP${mdSize !== "1" ? `-${mdSize}` : ""}`; + } + case "RSASSA-PKCS1-V1_5": + return `RS${/(\d+)$/.exec(algorithm.hash.name)[1]}`; + case "RSA-PSS": + return `PS${/(\d+)$/.exec(algorithm.hash.name)[1]}`; + case "RSA-PKCS1": + return `RS1`; + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } +} + +class RsaPrivateKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "private"; + } + getKey() { + const keyInfo = asn1Schema.AsnParser.parse(this.data, core__namespace.asn1.PrivateKeyInfo); + return asn1Schema.AsnParser.parse(keyInfo.privateKey, core__namespace.asn1.RsaPrivateKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "RSA", + alg: getJwkAlgorithm(this.algorithm), + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, jsonSchema.JsonSerializer.toJSON(key)); + } + fromJSON(json) { + const key = jsonSchema.JsonParser.fromJSON(json, { + targetSchema: core__namespace.asn1.RsaPrivateKey, + }); + const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); + keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; + keyInfo.privateKeyAlgorithm.parameters = null; + keyInfo.privateKey = asn1Schema.AsnSerializer.serialize(key); + this.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + } +} + +class RsaPublicKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "public"; + } + getKey() { + const keyInfo = asn1Schema.AsnParser.parse(this.data, core__namespace.asn1.PublicKeyInfo); + return asn1Schema.AsnParser.parse(keyInfo.publicKey, core__namespace.asn1.RsaPublicKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "RSA", + alg: getJwkAlgorithm(this.algorithm), + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, jsonSchema.JsonSerializer.toJSON(key)); + } + fromJSON(json) { + const key = jsonSchema.JsonParser.fromJSON(json, { + targetSchema: core__namespace.asn1.RsaPublicKey, + }); + const keyInfo = new core__namespace.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; + keyInfo.publicKeyAlgorithm.parameters = null; + keyInfo.publicKey = asn1Schema.AsnSerializer.serialize(key); + this.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + } +} + +class RsaCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const privateKey = new RsaPrivateKey(); + privateKey.algorithm = algorithm; + privateKey.extractable = extractable; + privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1); + const publicKey = new RsaPublicKey(); + publicKey.algorithm = algorithm; + publicKey.extractable = true; + publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1); + const publicExponent = buffer.Buffer.concat([ + buffer.Buffer.alloc(4 - algorithm.publicExponent.byteLength, 0), + buffer.Buffer.from(algorithm.publicExponent), + ]).readInt32BE(0); + const keys = crypto.generateKeyPairSync("rsa", { + modulusLength: algorithm.modulusLength, + publicExponent, + publicKeyEncoding: { + format: "der", + type: "spki", + }, + privateKeyEncoding: { + format: "der", + type: "pkcs8", + }, + }); + privateKey.data = keys.privateKey; + publicKey.data = keys.publicKey; + const res = { + privateKey, + publicKey, + }; + return res; + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return jsonSchema.JsonSerializer.toJSON(key); + case "pkcs8": + case "spki": + return new Uint8Array(key.data).buffer; + default: + throw new core__namespace.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + switch (format.toLowerCase()) { + case "jwk": { + const jwk = keyData; + if (jwk.d) { + const asnKey = jsonSchema.JsonParser.fromJSON(keyData, { + targetSchema: core__namespace.asn1.RsaPrivateKey, + }); + return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); + } + else { + const asnKey = jsonSchema.JsonParser.fromJSON(keyData, { + targetSchema: core__namespace.asn1.RsaPublicKey, + }); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + } + case "spki": { + const keyInfo = asn1Schema.AsnParser.parse(new Uint8Array(keyData), core__namespace.asn1.PublicKeyInfo); + const asnKey = asn1Schema.AsnParser.parse(keyInfo.publicKey, core__namespace.asn1.RsaPublicKey); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + case "pkcs8": { + const keyInfo = asn1Schema.AsnParser.parse(new Uint8Array(keyData), core__namespace.asn1.PrivateKeyInfo); + const asnKey = asn1Schema.AsnParser.parse(keyInfo.privateKey, core__namespace.asn1.RsaPrivateKey); + return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); + } + default: + throw new core__namespace.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); + } + } + static async sign(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-PSS": + case "RSASSA-PKCS1-V1_5": + return this.signRsa(algorithm, key, data); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async verify(algorithm, key, signature, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-PSS": + case "RSASSA-PKCS1-V1_5": + return this.verifySSA(algorithm, key, data, signature); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async encrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-OAEP": + return this.encryptOAEP(algorithm, key, data); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static async decrypt(algorithm, key, data) { + switch (algorithm.name.toUpperCase()) { + case "RSA-OAEP": + return this.decryptOAEP(algorithm, key, data); + default: + throw new core__namespace.OperationError("algorithm: Is not recognized"); + } + } + static importPrivateKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); + keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; + keyInfo.privateKeyAlgorithm.parameters = null; + keyInfo.privateKey = asn1Schema.AsnSerializer.serialize(asnKey); + const key = new RsaPrivateKey(); + key.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.algorithm.publicExponent = new Uint8Array(asnKey.publicExponent); + key.algorithm.modulusLength = asnKey.modulus.byteLength << 3; + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static importPublicKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core__namespace.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; + keyInfo.publicKeyAlgorithm.parameters = null; + keyInfo.publicKey = asn1Schema.AsnSerializer.serialize(asnKey); + const key = new RsaPublicKey(); + key.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.algorithm.publicExponent = new Uint8Array(asnKey.publicExponent); + key.algorithm.modulusLength = asnKey.modulus.byteLength << 3; + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static getCryptoAlgorithm(alg) { + switch (alg.hash.name.toUpperCase()) { + case "SHA-1": + return "RSA-SHA1"; + case "SHA-256": + return "RSA-SHA256"; + case "SHA-384": + return "RSA-SHA384"; + case "SHA-512": + return "RSA-SHA512"; + case "SHA3-256": + return "RSA-SHA3-256"; + case "SHA3-384": + return "RSA-SHA3-384"; + case "SHA3-512": + return "RSA-SHA3-512"; + default: + throw new core__namespace.OperationError("algorithm.hash: Is not recognized"); + } + } + static signRsa(algorithm, key, data) { + const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); + const signer = crypto.createSign(cryptoAlg); + signer.update(buffer.Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + const options = { + key: key.pem, + }; + if (algorithm.name.toUpperCase() === "RSA-PSS") { + options.padding = crypto.constants.RSA_PKCS1_PSS_PADDING; + options.saltLength = algorithm.saltLength; + } + const signature = signer.sign(options); + return new Uint8Array(signature).buffer; + } + static verifySSA(algorithm, key, data, signature) { + const cryptoAlg = this.getCryptoAlgorithm(key.algorithm); + const signer = crypto.createVerify(cryptoAlg); + signer.update(buffer.Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; + } + const options = { + key: key.pem, + }; + if (algorithm.name.toUpperCase() === "RSA-PSS") { + options.padding = crypto.constants.RSA_PKCS1_PSS_PADDING; + options.saltLength = algorithm.saltLength; + } + const ok = signer.verify(options, signature); + return ok; + } + static encryptOAEP(algorithm, key, data) { + const options = { + key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`, + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, + }; + if (algorithm.label) ; + return new Uint8Array(crypto.publicEncrypt(options, data)).buffer; + } + static decryptOAEP(algorithm, key, data) { + const options = { + key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`, + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, + }; + if (algorithm.label) ; + return new Uint8Array(crypto.privateDecrypt(options, data)).buffer; + } +} +RsaCrypto.publicKeyUsages = ["verify", "encrypt", "wrapKey"]; +RsaCrypto.privateKeyUsages = ["sign", "decrypt", "unwrapKey"]; + +class RsaSsaProvider extends core__namespace.RsaSsaProvider { + constructor() { + super(...arguments); + this.hashAlgorithms = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + "shake128", + "shake256", + "SHA3-256", + "SHA3-384", + "SHA3-512", + ]; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return RsaCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return RsaCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } +} + +class RsaPssProvider extends core__namespace.RsaPssProvider { + constructor() { + super(...arguments); + this.hashAlgorithms = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + "shake128", + "shake256", + "SHA3-256", + "SHA3-384", + "SHA3-512", + ]; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return RsaCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return RsaCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } +} + +class ShaCrypto { + static size(algorithm) { + switch (algorithm.name.toUpperCase()) { + case "SHA-1": + return 160; + case "SHA-256": + case "SHA3-256": + return 256; + case "SHA-384": + case "SHA3-384": + return 384; + case "SHA-512": + case "SHA3-512": + return 512; + default: + throw new Error("Unrecognized name"); + } + } + static getAlgorithmName(algorithm) { + switch (algorithm.name.toUpperCase()) { + case "SHA-1": + return "sha1"; + case "SHA-256": + return "sha256"; + case "SHA-384": + return "sha384"; + case "SHA-512": + return "sha512"; + case "SHA3-256": + return "sha3-256"; + case "SHA3-384": + return "sha3-384"; + case "SHA3-512": + return "sha3-512"; + default: + throw new Error("Unrecognized name"); + } + } + static digest(algorithm, data) { + const hashAlg = this.getAlgorithmName(algorithm); + const hash = crypto.createHash(hashAlg).update(buffer.Buffer.from(data)).digest(); + return new Uint8Array(hash).buffer; + } +} + +class RsaOaepProvider extends core__namespace.RsaOaepProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onEncrypt(algorithm, key, data) { + const internalKey = getCryptoKey(key); + const dataView = new Uint8Array(data); + const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); + const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; + const dataLength = dataView.byteLength; + const psLength = keySize - dataLength - 2 * hashSize - 2; + if (dataLength > keySize - 2 * hashSize - 2) { + throw new Error("Data too large"); + } + const message = new Uint8Array(keySize); + const seed = message.subarray(1, hashSize + 1); + const dataBlock = message.subarray(hashSize + 1); + dataBlock.set(dataView, hashSize + psLength + 1); + const labelHash = crypto + .createHash(internalKey.algorithm.hash.name.replace("-", "")) + .update(core__namespace.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); + for (let i = 0; i < dataBlock.length; i++) { + dataBlock[i] ^= dataBlockMask[i]; + } + 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-----`; + } + const pkcs0 = crypto.publicEncrypt({ + key: internalKey.pem, + padding: crypto.constants.RSA_NO_PADDING, + }, buffer.Buffer.from(message)); + return new Uint8Array(pkcs0).buffer; + } + async onDecrypt(algorithm, key, data) { + const internalKey = getCryptoKey(key); + const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); + const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; + const dataLength = data.byteLength; + if (dataLength !== keySize) { + throw new Error("Bad data"); + } + if (!internalKey.pem) { + 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.Buffer.from(data)); + const z = pkcs0[0]; + const seed = pkcs0.subarray(1, hashSize + 1); + const dataBlock = pkcs0.subarray(hashSize + 1); + if (z !== 0) { + throw new Error("Decryption failed"); + } + 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); + for (let i = 0; i < dataBlock.length; i++) { + dataBlock[i] ^= dataBlockMask[i]; + } + const labelHash = crypto + .createHash(internalKey.algorithm.hash.name.replace("-", "")) + .update(core__namespace.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0))) + .digest(); + for (let i = 0; i < hashSize; i++) { + if (labelHash[i] !== dataBlock[i]) { + throw new Error("Decryption failed"); + } + } + let psEnd = hashSize; + for (; psEnd < dataBlock.length; psEnd++) { + const psz = dataBlock[psEnd]; + if (psz === 1) { + break; + } + if (psz !== 0) { + throw new Error("Decryption failed"); + } + } + if (psEnd === dataBlock.length) { + throw new Error("Decryption failed"); + } + pkcs0 = dataBlock.subarray(psEnd + 1); + return new Uint8Array(pkcs0).buffer; + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } + mgf1(algorithm, seed, length = 0) { + const hashSize = ShaCrypto.size(algorithm) >> 3; + const mask = new Uint8Array(length); + const counter = new Uint8Array(4); + const chunks = Math.ceil(length / hashSize); + for (let i = 0; i < chunks; i++) { + counter[0] = i >>> 24; + counter[1] = (i >>> 16) & 255; + counter[2] = (i >>> 8) & 255; + counter[3] = i & 255; + const submask = mask.subarray(i * hashSize); + let chunk = crypto + .createHash(algorithm.name.replace("-", "")) + .update(seed) + .update(counter) + .digest(); + if (chunk.length > submask.length) { + chunk = chunk.subarray(0, submask.length); + } + submask.set(chunk); + } + return mask; + } +} + +class RsaEsProvider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "RSAES-PKCS1-v1_5"; + this.usages = { + publicKey: ["encrypt", "wrapKey"], + privateKey: ["decrypt", "unwrapKey"], + }; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await RsaCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + checkGenerateKeyParams(algorithm) { + this.checkRequiredProperty(algorithm, "publicExponent"); + if (!(algorithm.publicExponent && + algorithm.publicExponent instanceof Uint8Array)) { + throw new TypeError("publicExponent: Missing or not a Uint8Array"); + } + const publicExponent = pvtsutils.Convert.ToBase64(algorithm.publicExponent); + if (!(publicExponent === "Aw==" || publicExponent === "AQAB")) { + throw new TypeError("publicExponent: Must be [3] or [1,0,1]"); + } + this.checkRequiredProperty(algorithm, "modulusLength"); + switch (algorithm.modulusLength) { + case 1024: + case 2048: + case 4096: + break; + default: + throw new TypeError("modulusLength: Must be 1024, 2048, or 4096"); + } + } + async onEncrypt(algorithm, key, data) { + const options = this.toCryptoOptions(key); + const enc = crypto__namespace.publicEncrypt(options, new Uint8Array(data)); + return new Uint8Array(enc).buffer; + } + async onDecrypt(algorithm, key, data) { + const options = this.toCryptoOptions(key); + const dec = crypto__namespace.privateDecrypt(options, new Uint8Array(data)); + return new Uint8Array(dec).buffer; + } + async onExportKey(format, key) { + return RsaCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || + internalKey instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } + toCryptoOptions(key) { + const type = key.type.toUpperCase(); + return { + key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`, + padding: crypto__namespace.constants.RSA_PKCS1_PADDING, + }; + } +} + +const namedOIDs = { + "1.2.840.10045.3.1.7": "P-256", + "P-256": "1.2.840.10045.3.1.7", + "1.3.132.0.34": "P-384", + "P-384": "1.3.132.0.34", + "1.3.132.0.35": "P-521", + "P-521": "1.3.132.0.35", + "1.3.132.0.10": "K-256", + "K-256": "1.3.132.0.10", + 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", + "1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1", + 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", + "1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1", + 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", + "1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1", + 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", + "1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1", + 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", + "1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1", + 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", + "1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1", + 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", + "1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1", +}; +function getOidByNamedCurve$1(namedCurve) { + const oid = namedOIDs[namedCurve]; + if (!oid) { + throw new core__namespace.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); + } + return oid; +} + +class EcPrivateKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "private"; + } + getKey() { + const keyInfo = asn1Schema.AsnParser.parse(this.data, core__namespace.asn1.PrivateKeyInfo); + return asn1Schema.AsnParser.parse(keyInfo.privateKey, core__namespace.asn1.EcPrivateKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "EC", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, jsonSchema.JsonSerializer.toJSON(key)); + } + fromJSON(json) { + if (!json.crv) { + throw new core__namespace.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); + } + const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); + keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; + keyInfo.privateKeyAlgorithm.parameters = asn1Schema.AsnSerializer.serialize(new core__namespace.asn1.ObjectIdentifier(getOidByNamedCurve$1(json.crv))); + const key = jsonSchema.JsonParser.fromJSON(json, { + targetSchema: core__namespace.asn1.EcPrivateKey, + }); + keyInfo.privateKey = asn1Schema.AsnSerializer.serialize(key); + this.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class EcPublicKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "public"; + } + getKey() { + const keyInfo = asn1Schema.AsnParser.parse(this.data, core__namespace.asn1.PublicKeyInfo); + return new core__namespace.asn1.EcPublicKey(keyInfo.publicKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "EC", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, jsonSchema.JsonSerializer.toJSON(key)); + } + fromJSON(json) { + if (!json.crv) { + throw new core__namespace.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); + } + const key = jsonSchema.JsonParser.fromJSON(json, { + targetSchema: core__namespace.asn1.EcPublicKey, + }); + const keyInfo = new core__namespace.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; + keyInfo.publicKeyAlgorithm.parameters = asn1Schema.AsnSerializer.serialize(new core__namespace.asn1.ObjectIdentifier(getOidByNamedCurve$1(json.crv))); + keyInfo.publicKey = asn1Schema.AsnSerializer.toASN(key).valueHex; + this.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class Sha1Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-1"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha256Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-256"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha384Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-384"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha512Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA-512"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha3256Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA3-256"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha3384Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA3-384"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class Sha3512Provider extends core__namespace.ProviderCrypto { + constructor() { + super(...arguments); + this.name = "SHA3-512"; + this.usages = []; + } + async onDigest(algorithm, data) { + return ShaCrypto.digest(algorithm, data); + } +} + +class EcCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const privateKey = new EcPrivateKey(); + privateKey.algorithm = algorithm; + privateKey.extractable = extractable; + 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); + const keys = crypto.generateKeyPairSync("ec", { + namedCurve: this.getOpenSSLNamedCurve(algorithm.namedCurve), + publicKeyEncoding: { + format: "der", + type: "spki", + }, + privateKeyEncoding: { + format: "der", + type: "pkcs8", + }, + }); + privateKey.data = keys.privateKey; + publicKey.data = keys.publicKey; + const res = { + privateKey, + publicKey, + }; + return res; + } + static async sign(algorithm, key, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash); + const signer = crypto.createSign(cryptoAlg); + signer.update(buffer.Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + const options = { + key: key.pem, + }; + const signature = signer.sign(options); + const ecSignature = asn1Schema.AsnParser.parse(signature, core__namespace.asn1.EcDsaSignature); + const signatureRaw = core__namespace.EcUtils.encodeSignature(ecSignature, core__namespace.EcCurves.get(key.algorithm.namedCurve).size); + return signatureRaw.buffer; + } + static async verify(algorithm, key, signature, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash); + const signer = crypto.createVerify(cryptoAlg); + signer.update(buffer.Buffer.from(data)); + if (!key.pem) { + key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; + } + const options = { + key: key.pem, + }; + const ecSignature = new core__namespace.asn1.EcDsaSignature(); + const namedCurve = core__namespace.EcCurves.get(key.algorithm.namedCurve); + const signaturePoint = core__namespace.EcUtils.decodeSignature(signature, namedCurve.size); + ecSignature.r = pvtsutils.BufferSourceConverter.toArrayBuffer(signaturePoint.r); + ecSignature.s = pvtsutils.BufferSourceConverter.toArrayBuffer(signaturePoint.s); + const ecSignatureRaw = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(ecSignature)); + const ok = signer.verify(options, ecSignatureRaw); + return ok; + } + static async deriveBits(algorithm, baseKey, length) { + const cryptoAlg = this.getOpenSSLNamedCurve(baseKey.algorithm.namedCurve); + const ecdh = crypto.createECDH(cryptoAlg); + const asnPrivateKey = asn1Schema.AsnParser.parse(baseKey.data, core__namespace.asn1.PrivateKeyInfo); + const asnEcPrivateKey = asn1Schema.AsnParser.parse(asnPrivateKey.privateKey, core__namespace.asn1.EcPrivateKey); + ecdh.setPrivateKey(buffer.Buffer.from(asnEcPrivateKey.privateKey)); + const asnPublicKey = asn1Schema.AsnParser.parse(algorithm.public.data, core__namespace.asn1.PublicKeyInfo); + const bits = ecdh.computeSecret(buffer.Buffer.from(asnPublicKey.publicKey)); + if (length === null) { + return bits; + } + return new Uint8Array(bits).buffer.slice(0, length >> 3); + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return jsonSchema.JsonSerializer.toJSON(key); + case "pkcs8": + case "spki": + return new Uint8Array(key.data).buffer; + case "raw": { + const publicKeyInfo = asn1Schema.AsnParser.parse(key.data, core__namespace.asn1.PublicKeyInfo); + return publicKeyInfo.publicKey; + } + default: + throw new core__namespace.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + switch (format.toLowerCase()) { + case "jwk": { + const jwk = keyData; + if (jwk.d) { + const asnKey = jsonSchema.JsonParser.fromJSON(keyData, { + targetSchema: core__namespace.asn1.EcPrivateKey, + }); + return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); + } + else { + const asnKey = jsonSchema.JsonParser.fromJSON(keyData, { + targetSchema: core__namespace.asn1.EcPublicKey, + }); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + } + case "raw": { + const asnKey = new core__namespace.asn1.EcPublicKey(keyData); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + case "spki": { + const keyInfo = asn1Schema.AsnParser.parse(new Uint8Array(keyData), core__namespace.asn1.PublicKeyInfo); + const asnKey = new core__namespace.asn1.EcPublicKey(keyInfo.publicKey); + this.assertKeyParameters(keyInfo.publicKeyAlgorithm.parameters, algorithm.namedCurve); + return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); + } + case "pkcs8": { + const keyInfo = asn1Schema.AsnParser.parse(new Uint8Array(keyData), core__namespace.asn1.PrivateKeyInfo); + const asnKey = asn1Schema.AsnParser.parse(keyInfo.privateKey, core__namespace.asn1.EcPrivateKey); + this.assertKeyParameters(keyInfo.privateKeyAlgorithm.parameters, algorithm.namedCurve); + return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); + } + default: + throw new core__namespace.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"); + } + } + static assertKeyParameters(parameters, namedCurve) { + if (!parameters) { + throw new core__namespace.CryptoError("Key info doesn't have required parameters"); + } + let namedCurveIdentifier = ""; + try { + namedCurveIdentifier = asn1Schema.AsnParser.parse(parameters, core__namespace.asn1.ObjectIdentifier).value; + } + catch (e) { + throw new core__namespace.CryptoError("Cannot read key info parameters"); + } + if (getOidByNamedCurve$1(namedCurve) !== namedCurveIdentifier) { + throw new core__namespace.CryptoError("Key info parameter doesn't match to named curve"); + } + } + static async importPrivateKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); + keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; + keyInfo.privateKeyAlgorithm.parameters = asn1Schema.AsnSerializer.serialize(new core__namespace.asn1.ObjectIdentifier(getOidByNamedCurve$1(algorithm.namedCurve))); + keyInfo.privateKey = asn1Schema.AsnSerializer.serialize(asnKey); + const key = new EcPrivateKey(); + key.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static async importPublicKey(asnKey, algorithm, extractable, keyUsages) { + const keyInfo = new core__namespace.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; + const namedCurve = getOidByNamedCurve$1(algorithm.namedCurve); + keyInfo.publicKeyAlgorithm.parameters = asn1Schema.AsnSerializer.serialize(new core__namespace.asn1.ObjectIdentifier(namedCurve)); + keyInfo.publicKey = asnKey.value; + const key = new EcPublicKey(); + key.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static getOpenSSLNamedCurve(curve) { + switch (curve.toUpperCase()) { + case "P-256": + return "prime256v1"; + case "K-256": + return "secp256k1"; + case "P-384": + return "secp384r1"; + case "P-521": + return "secp521r1"; + default: + return curve; + } + } +} +EcCrypto.publicKeyUsages = ["verify"]; +EcCrypto.privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; + +class EcdsaProvider extends core__namespace.EcdsaProvider { + constructor() { + super(...arguments); + this.namedCurves = core__namespace.EcCurves.names; + this.hashAlgorithms = [ + "SHA-1", + "SHA-256", + "SHA-384", + "SHA-512", + "shake128", + "shake256", + "SHA3-256", + "SHA3-384", + "SHA3-512", + ]; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EcCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return EcCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return EcCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return EcCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof EcPrivateKey || + internalKey instanceof EcPublicKey)) { + throw new TypeError("key: Is not EC CryptoKey"); + } + } +} + +class EcdhProvider extends core__namespace.EcdhProvider { + constructor() { + super(...arguments); + this.namedCurves = core__namespace.EcCurves.names; + } + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EcCrypto.generateKey({ + ...algorithm, + name: this.name, + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onExportKey(format, key) { + return EcCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof EcPrivateKey || + internalKey instanceof EcPublicKey)) { + throw new TypeError("key: Is not EC CryptoKey"); + } + } + async onDeriveBits(algorithm, baseKey, length) { + const bits = await EcCrypto.deriveBits({ ...algorithm, public: getCryptoKey(algorithm.public) }, getCryptoKey(baseKey), length); + return bits; + } +} + +const edOIDs = { + [core__namespace.asn1.idEd448]: "Ed448", + ed448: core__namespace.asn1.idEd448, + [core__namespace.asn1.idX448]: "X448", + x448: core__namespace.asn1.idX448, + [core__namespace.asn1.idEd25519]: "Ed25519", + ed25519: core__namespace.asn1.idEd25519, + [core__namespace.asn1.idX25519]: "X25519", + x25519: core__namespace.asn1.idX25519, +}; +function getOidByNamedCurve(namedCurve) { + const oid = edOIDs[namedCurve.toLowerCase()]; + if (!oid) { + throw new core__namespace.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); + } + return oid; +} + +class EdPrivateKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "private"; + } + getKey() { + const keyInfo = asn1Schema.AsnParser.parse(this.data, core__namespace.asn1.PrivateKeyInfo); + return asn1Schema.AsnParser.parse(keyInfo.privateKey, core__namespace.asn1.CurvePrivateKey); + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "OKP", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, jsonSchema.JsonSerializer.toJSON(key)); + } + fromJSON(json) { + if (!json.crv) { + throw new core__namespace.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); + } + const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); + keyInfo.privateKeyAlgorithm.algorithm = getOidByNamedCurve(json.crv); + const key = jsonSchema.JsonParser.fromJSON(json, { + targetSchema: core__namespace.asn1.CurvePrivateKey, + }); + keyInfo.privateKey = asn1Schema.AsnSerializer.serialize(key); + this.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class EdPublicKey extends AsymmetricKey { + constructor() { + super(...arguments); + this.type = "public"; + } + getKey() { + const keyInfo = asn1Schema.AsnParser.parse(this.data, core__namespace.asn1.PublicKeyInfo); + return keyInfo.publicKey; + } + toJSON() { + const key = this.getKey(); + const json = { + kty: "OKP", + crv: this.algorithm.namedCurve, + key_ops: this.usages, + ext: this.extractable, + }; + return Object.assign(json, { + x: pvtsutils.Convert.ToBase64Url(key), + }); + } + fromJSON(json) { + if (!json.crv) { + throw new core__namespace.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); + } + if (!json.x) { + throw new core__namespace.OperationError(`Cannot get property from JWK. Property 'x' is required`); + } + const keyInfo = new core__namespace.asn1.PublicKeyInfo(); + keyInfo.publicKeyAlgorithm.algorithm = getOidByNamedCurve(json.crv); + keyInfo.publicKey = pvtsutils.Convert.FromBase64Url(json.x); + this.data = buffer.Buffer.from(asn1Schema.AsnSerializer.serialize(keyInfo)); + return this; + } +} + +class EdCrypto { + static async generateKey(algorithm, extractable, keyUsages) { + const privateKey = new EdPrivateKey(); + privateKey.algorithm = algorithm; + privateKey.extractable = extractable; + 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); + const type = algorithm.namedCurve.toLowerCase(); + const keys = crypto.generateKeyPairSync(type, { + publicKeyEncoding: { + format: "der", + type: "spki", + }, + privateKeyEncoding: { + format: "der", + type: "pkcs8", + }, + }); + privateKey.data = keys.privateKey; + publicKey.data = keys.publicKey; + const res = { + privateKey, + publicKey, + }; + return res; + } + static async sign(algorithm, key, data) { + if (!key.pem) { + key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + } + const options = { + key: key.pem, + }; + const signature = crypto.sign(null, buffer.Buffer.from(data), options); + return core__namespace.BufferSourceConverter.toArrayBuffer(signature); + } + static async verify(algorithm, key, signature, data) { + if (!key.pem) { + 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.Buffer.from(data), options, buffer.Buffer.from(signature)); + return ok; + } + static async deriveBits(algorithm, baseKey, length) { + const publicKey = crypto.createPublicKey({ + key: algorithm.public.data, + format: "der", + type: "spki", + }); + const privateKey = crypto.createPrivateKey({ + key: baseKey.data, + format: "der", + type: "pkcs8", + }); + const bits = crypto.diffieHellman({ + publicKey, + privateKey, + }); + return new Uint8Array(bits).buffer.slice(0, length >> 3); + } + static async exportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return jsonSchema.JsonSerializer.toJSON(key); + case "pkcs8": + case "spki": + return new Uint8Array(key.data).buffer; + case "raw": { + const publicKeyInfo = asn1Schema.AsnParser.parse(key.data, core__namespace.asn1.PublicKeyInfo); + return publicKeyInfo.publicKey; + } + default: + throw new core__namespace.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'"); + } + } + static async importKey(format, keyData, algorithm, extractable, keyUsages) { + switch (format.toLowerCase()) { + case "jwk": { + const jwk = keyData; + if (jwk.d) { + const asnKey = jsonSchema.JsonParser.fromJSON(keyData, { + targetSchema: core__namespace.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(pvtsutils.Convert.FromBase64Url(jwk.x), algorithm, extractable, keyUsages); + } + } + case "raw": { + return this.importPublicKey(keyData, algorithm, extractable, keyUsages); + } + case "spki": { + const keyInfo = asn1Schema.AsnParser.parse(new Uint8Array(keyData), core__namespace.asn1.PublicKeyInfo); + return this.importPublicKey(keyInfo.publicKey, algorithm, extractable, keyUsages); + } + case "pkcs8": { + const keyInfo = asn1Schema.AsnParser.parse(new Uint8Array(keyData), core__namespace.asn1.PrivateKeyInfo); + const asnKey = asn1Schema.AsnParser.parse(keyInfo.privateKey, core__namespace.asn1.CurvePrivateKey); + return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); + } + default: + throw new core__namespace.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"); + } + } + static importPrivateKey(asnKey, algorithm, extractable, keyUsages) { + const key = new EdPrivateKey(); + key.fromJSON({ + crv: algorithm.namedCurve, + d: pvtsutils.Convert.ToBase64Url(asnKey.d), + }); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } + static async importPublicKey(asnKey, algorithm, extractable, keyUsages) { + const key = new EdPublicKey(); + key.fromJSON({ + crv: algorithm.namedCurve, + x: pvtsutils.Convert.ToBase64Url(asnKey), + }); + key.algorithm = Object.assign({}, algorithm); + key.extractable = extractable; + key.usages = keyUsages; + return key; + } +} +EdCrypto.publicKeyUsages = ["verify"]; +EdCrypto.privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; + +class EdDsaProvider extends core__namespace.EdDsaProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EdCrypto.generateKey({ + name: this.name, + namedCurve: algorithm.namedCurve.replace(/^ed/i, "Ed"), + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onSign(algorithm, key, data) { + return EdCrypto.sign(algorithm, getCryptoKey(key), new Uint8Array(data)); + } + async onVerify(algorithm, key, signature, data) { + return EdCrypto.verify(algorithm, getCryptoKey(key), new Uint8Array(signature), new Uint8Array(data)); + } + async onExportKey(format, key) { + return EdCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } +} + +class EcdhEsProvider extends core__namespace.EcdhEsProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const keys = await EdCrypto.generateKey({ + name: this.name, + namedCurve: algorithm.namedCurve.toUpperCase(), + }, extractable, keyUsages); + return { + privateKey: setCryptoKey(keys.privateKey), + publicKey: setCryptoKey(keys.publicKey), + }; + } + async onDeriveBits(algorithm, baseKey, length) { + const bits = await EdCrypto.deriveBits({ ...algorithm, public: getCryptoKey(algorithm.public) }, getCryptoKey(baseKey), length); + return bits; + } + async onExportKey(format, key) { + return EdCrypto.exportKey(format, getCryptoKey(key)); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + return setCryptoKey(key); + } +} + +class PbkdfCryptoKey extends CryptoKey { +} + +class Pbkdf2Provider extends core__namespace.Pbkdf2Provider { + async onDeriveBits(algorithm, baseKey, length) { + return new Promise((resolve, reject) => { + const salt = core__namespace.BufferSourceConverter.toArrayBuffer(algorithm.salt); + const hash = algorithm.hash.name.replace("-", ""); + crypto.pbkdf2(getCryptoKey(baseKey).data, buffer.Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => { + if (err) { + reject(err); + } + else { + resolve(new Uint8Array(derivedBits).buffer); + } + }); + }); + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + if (format === "raw") { + const key = new PbkdfCryptoKey(); + key.data = buffer.Buffer.from(keyData); + key.algorithm = { name: this.name }; + key.extractable = false; + key.usages = keyUsages; + return setCryptoKey(key); + } + throw new core__namespace.OperationError("format: Must be 'raw'"); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof PbkdfCryptoKey)) { + throw new TypeError("key: Is not PBKDF CryptoKey"); + } + } +} + +class HmacCryptoKey extends CryptoKey { + get alg() { + const hash = this.algorithm.hash.name.toUpperCase(); + return `HS${hash.replace("SHA-", "")}`; + } + set alg(value) { + } +} +tslib.__decorate([ + jsonSchema.JsonProp({ name: "k", converter: JsonBase64UrlConverter }) +], HmacCryptoKey.prototype, "data", void 0); + +class HmacProvider extends core__namespace.HmacProvider { + async onGenerateKey(algorithm, extractable, keyUsages) { + const length = ((algorithm.length || + this.getDefaultLength(algorithm.hash.name)) >> + 3) << + 3; + const key = new HmacCryptoKey(); + key.algorithm = { + ...algorithm, + length, + name: this.name, + }; + key.extractable = extractable; + key.usages = keyUsages; + key.data = crypto.randomBytes(length >> 3); + return setCryptoKey(key); + } + async onSign(algorithm, key, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash); + const hmac = crypto + .createHmac(cryptoAlg, getCryptoKey(key).data) + .update(buffer.Buffer.from(data)) + .digest(); + return new Uint8Array(hmac).buffer; + } + async onVerify(algorithm, key, signature, data) { + const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash); + const hmac = crypto + .createHmac(cryptoAlg, getCryptoKey(key).data) + .update(buffer.Buffer.from(data)) + .digest(); + return hmac.compare(buffer.Buffer.from(signature)) === 0; + } + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + let key; + switch (format.toLowerCase()) { + case "jwk": + key = jsonSchema.JsonParser.fromJSON(keyData, { targetSchema: HmacCryptoKey }); + break; + case "raw": + key = new HmacCryptoKey(); + key.data = buffer.Buffer.from(keyData); + break; + default: + throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); + } + key.algorithm = { + hash: { name: algorithm.hash.name }, + name: this.name, + length: key.data.length << 3, + }; + key.extractable = extractable; + key.usages = keyUsages; + return setCryptoKey(key); + } + async onExportKey(format, key) { + switch (format.toLowerCase()) { + case "jwk": + return jsonSchema.JsonSerializer.toJSON(getCryptoKey(key)); + case "raw": + return new Uint8Array(getCryptoKey(key).data).buffer; + default: + throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof HmacCryptoKey)) { + throw new TypeError("key: Is not HMAC CryptoKey"); + } + } +} + +class HkdfCryptoKey extends CryptoKey { +} + +class HkdfProvider extends core__namespace.HkdfProvider { + async onImportKey(format, keyData, algorithm, extractable, keyUsages) { + if (format.toLowerCase() !== "raw") { + throw new core__namespace.OperationError("Operation not supported"); + } + const key = new HkdfCryptoKey(); + key.data = buffer.Buffer.from(keyData); + key.algorithm = { name: this.name }; + key.extractable = extractable; + key.usages = keyUsages; + return setCryptoKey(key); + } + async onDeriveBits(params, baseKey, length) { + const hash = params.hash.name.replace("-", ""); + const hashLength = crypto.createHash(hash).digest().length; + const byteLength = length / 8; + const info = core.BufferSourceConverter.toUint8Array(params.info); + const PRK = crypto + .createHmac(hash, core.BufferSourceConverter.toUint8Array(params.salt)) + .update(core.BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data)) + .digest(); + const blocks = [buffer.Buffer.alloc(0)]; + const blockCount = Math.ceil(byteLength / hashLength) + 1; + for (let i = 1; i < blockCount; ++i) { + blocks.push(crypto + .createHmac(hash, PRK) + .update(buffer.Buffer.concat([blocks[i - 1], info, buffer.Buffer.from([i])])) + .digest()); + } + return buffer.Buffer.concat(blocks).slice(0, byteLength); + } + checkCryptoKey(key, keyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(getCryptoKey(key) instanceof HkdfCryptoKey)) { + throw new TypeError("key: Is not HKDF CryptoKey"); + } + } +} + +class ShakeCrypto { + static digest(algorithm, data) { + const hash = crypto + .createHash(algorithm.name.toLowerCase(), { + outputLength: algorithm.length, + }) + .update(buffer.Buffer.from(data)) + .digest(); + return new Uint8Array(hash).buffer; + } +} + +class Shake128Provider extends core__namespace.Shake128Provider { + async onDigest(algorithm, data) { + return ShakeCrypto.digest(algorithm, data); + } +} + +class Shake256Provider extends core__namespace.Shake256Provider { + async onDigest(algorithm, data) { + return ShakeCrypto.digest(algorithm, data); + } +} + +class SubtleCrypto extends core__namespace.SubtleCrypto { + constructor() { + var _a; + super(); + this.providers.set(new AesCbcProvider()); + this.providers.set(new AesCtrProvider()); + this.providers.set(new AesGcmProvider()); + this.providers.set(new AesCmacProvider()); + this.providers.set(new AesKwProvider()); + this.providers.set(new AesEcbProvider()); + const ciphers = crypto__namespace.getCiphers(); + if (ciphers.includes("des-cbc")) { + this.providers.set(new DesCbcProvider()); + } + this.providers.set(new DesEde3CbcProvider()); + this.providers.set(new RsaSsaProvider()); + this.providers.set(new RsaPssProvider()); + this.providers.set(new RsaOaepProvider()); + this.providers.set(new RsaEsProvider()); + this.providers.set(new EcdsaProvider()); + this.providers.set(new EcdhProvider()); + this.providers.set(new Sha1Provider()); + this.providers.set(new Sha256Provider()); + this.providers.set(new Sha384Provider()); + this.providers.set(new Sha512Provider()); + this.providers.set(new Pbkdf2Provider()); + this.providers.set(new HmacProvider()); + this.providers.set(new HkdfProvider()); + const nodeMajorVersion = (_a = /^v(\d+)/.exec(process__namespace.version)) === null || _a === void 0 ? void 0 : _a[1]; + if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 12) { + this.providers.set(new Shake128Provider()); + this.providers.set(new Shake256Provider()); + } + const hashes = crypto__namespace.getHashes(); + if (hashes.includes("sha3-256")) { + this.providers.set(new Sha3256Provider()); + } + if (hashes.includes("sha3-384")) { + this.providers.set(new Sha3384Provider()); + } + if (hashes.includes("sha3-512")) { + this.providers.set(new Sha3512Provider()); + } + if (nodeMajorVersion && parseInt(nodeMajorVersion, 10) >= 14) { + this.providers.set(new EdDsaProvider()); + this.providers.set(new EcdhEsProvider()); + } + } +} + +class Crypto extends core__namespace.Crypto { + constructor() { + super(...arguments); + this.subtle = new SubtleCrypto(); + } + getRandomValues(array) { + if (!ArrayBuffer.isView(array)) { + throw new TypeError("Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'"); + } + const buffer$1 = buffer.Buffer.from(array.buffer, array.byteOffset, array.byteLength); + crypto.randomFillSync(buffer$1); + return array; + } +} + +Object.defineProperty(exports, 'CryptoKey', { + enumerable: true, + get: function () { return core.CryptoKey; } +}); +exports.Crypto = Crypto;