UNPKG

webcrypto-liner

Version:

A WebCrypto polyfill that "smooths out" the rough-edges in existing User Agent implementations.

1,266 lines (1,235 loc) 96.1 kB
/** * Copyright (c) 2024, Peculiar Ventures, LLC. */ 'use strict'; var core = require('webcrypto-core'); var tslib = require('tslib'); var asn1Schema = require('@peculiar/asn1-schema'); var jsonSchema = require('@peculiar/json-schema'); var pvtsutils = require('pvtsutils'); var asmCrypto = require('asmcrypto.js'); var elliptic = require('elliptic'); var sha3 = require('@stablelib/sha3'); var des = require('des.js'); 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 asmCrypto__namespace = /*#__PURE__*/_interopNamespaceDefault(asmCrypto); var elliptic__namespace = /*#__PURE__*/_interopNamespaceDefault(elliptic); var des__namespace = /*#__PURE__*/_interopNamespaceDefault(des); let window = {}; if (typeof self !== "undefined") { window = self; } exports.nativeCrypto = window["msCrypto"] || window.crypto || {}; exports.nativeSubtle = null; try { exports.nativeSubtle = (exports.nativeCrypto === null || exports.nativeCrypto === void 0 ? void 0 : exports.nativeCrypto.subtle) || (exports.nativeCrypto === null || exports.nativeCrypto === void 0 ? void 0 : exports.nativeCrypto["webkitSubtle"]) || null; } catch (err) { console.warn("Cannot get subtle from crypto", err); } function setCrypto(crypto) { exports.nativeCrypto = crypto; exports.nativeSubtle = crypto.subtle; } class Debug { static get enabled() { return typeof self !== "undefined" && self.PV_WEBCRYPTO_LINER_LOG; } static log(...args) { if (this.enabled) { console.log(...args); } } static error(...args) { if (this.enabled) { console.error(...args); } } static info(...args) { if (this.enabled) { console.info(...args); } } static warn(...args) { if (this.enabled) { console.warn(...args); } } static trace(...args) { if (this.enabled) { console.trace(...args); } } } var Browser; (function (Browser) { Browser["Unknown"] = "Unknown"; Browser["IE"] = "Internet Explorer"; Browser["Safari"] = "Safari"; Browser["Edge"] = "Edge"; Browser["Chrome"] = "Chrome"; Browser["Firefox"] = "Firefox Mozilla"; Browser["Mobile"] = "Mobile"; })(Browser || (Browser = {})); function BrowserInfo() { const res = { name: Browser.Unknown, version: "0", }; if (typeof self === "undefined") { return res; } const userAgent = self.navigator.userAgent; const reg = /edge\/([\d.]+)/i.exec(userAgent); if (reg) { res.name = Browser.Edge; res.version = reg[1]; } else if (/msie/i.test(userAgent)) { res.name = Browser.IE; res.version = /msie ([\d.]+)/i.exec(userAgent)[1]; } else if (/Trident/i.test(userAgent)) { res.name = Browser.IE; res.version = /rv:([\d.]+)/i.exec(userAgent)[1]; } else if (/chrome/i.test(userAgent)) { res.name = Browser.Chrome; res.version = /chrome\/([\d.]+)/i.exec(userAgent)[1]; } else if (/firefox/i.test(userAgent)) { res.name = Browser.Firefox; res.version = /firefox\/([\d.]+)/i.exec(userAgent)[1]; } else if (/mobile/i.test(userAgent)) { res.name = Browser.Mobile; res.version = /mobile\/([\w]+)/i.exec(userAgent)[1]; } else if (/safari/i.test(userAgent)) { res.name = Browser.Safari; res.version = /version\/([\d.]+)/i.exec(userAgent)[1]; } return res; } function concat(...buf) { const res = new Uint8Array(buf.map((item) => item.length).reduce((prev, cur) => prev + cur)); let offset = 0; buf.forEach((item) => { for (let i = 0; i < item.length; i++) { res[offset + i] = item[i]; } offset += item.length; }); return res; } class CryptoKey extends core__namespace.CryptoKey { constructor(algorithm, extractable, type, usages) { super(); this.extractable = extractable; this.type = type; this.usages = usages; this.algorithm = Object.assign({}, algorithm); } } function isAlgorithm(algorithm, name) { return algorithm.name.toUpperCase() === name.toUpperCase(); } class AesCryptoKey extends CryptoKey { constructor(algorithm, extractable, usages, raw) { super(algorithm, extractable, "secret", usages); this.raw = raw; } toJSON() { const jwk = { kty: "oct", alg: this.getJwkAlgorithm(), k: pvtsutils.Convert.ToBase64Url(this.raw), ext: this.extractable, key_ops: this.usages, }; return jwk; } getJwkAlgorithm() { 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-ECB": return `A${this.algorithm.length}ECB`; default: throw new core__namespace.AlgorithmError("Unsupported algorithm name"); } } } class AesCrypto { static checkCryptoKey(key) { if (!(key instanceof AesCryptoKey)) { throw new TypeError("key: Is not AesCryptoKey"); } } static generateKey(algorithm, extractable, usages) { return tslib.__awaiter(this, void 0, void 0, function* () { const raw = exports.nativeCrypto.getRandomValues(new Uint8Array(algorithm.length / 8)); return new AesCryptoKey(algorithm, extractable, usages, raw); }); } static encrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return this.cipher(algorithm, key, core__namespace.BufferSourceConverter.toUint8Array(data), true); }); } static decrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return this.cipher(algorithm, key, core__namespace.BufferSourceConverter.toUint8Array(data), false); }); } static exportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { switch (format) { case "jwk": return key.toJSON(); case "raw": return key.raw.buffer; default: throw new core__namespace.OperationError("format: Must be 'jwk' or 'raw'"); } }); } static importKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { let raw; if (core__namespace.isJWK(keyData)) { raw = pvtsutils.Convert.FromBase64Url(keyData.k); } else { raw = core__namespace.BufferSourceConverter.toArrayBuffer(keyData); } switch (raw.byteLength << 3) { case 128: case 192: case 256: break; default: throw new core__namespace.OperationError("keyData: Is wrong key length"); } const key = new AesCryptoKey({ name: algorithm.name, length: raw.byteLength << 3 }, extractable, keyUsages, new Uint8Array(raw)); return key; }); } static cipher(algorithm, key, data, encrypt) { return tslib.__awaiter(this, void 0, void 0, function* () { const action = encrypt ? "encrypt" : "decrypt"; let result; if (isAlgorithm(algorithm, AesCrypto.AesCBC)) { const iv = core__namespace.BufferSourceConverter.toUint8Array(algorithm.iv); result = asmCrypto__namespace.AES_CBC[action](data, key.raw, undefined, iv); } else if (isAlgorithm(algorithm, AesCrypto.AesGCM)) { const iv = core__namespace.BufferSourceConverter.toUint8Array(algorithm.iv); let additionalData; if (algorithm.additionalData) { additionalData = core__namespace.BufferSourceConverter.toUint8Array(algorithm.additionalData); } const tagLength = (algorithm.tagLength || 128) / 8; result = asmCrypto__namespace.AES_GCM[action](data, key.raw, iv, additionalData, tagLength); } else if (isAlgorithm(algorithm, AesCrypto.AesECB)) { result = asmCrypto__namespace.AES_ECB[action](data, key.raw, true); } else { throw new core__namespace.OperationError(`algorithm: Is not recognized`); } return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } } AesCrypto.AesCBC = "AES-CBC"; AesCrypto.AesECB = "AES-ECB"; AesCrypto.AesGCM = "AES-GCM"; class AesCbcProvider extends core__namespace.AesCbcProvider { onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.generateKey(algorithm, extractable, keyUsages); }); } onEncrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.encrypt(algorithm, key, data); }); } onDecrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.decrypt(algorithm, key, data); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); AesCrypto.checkCryptoKey(key); } } class AesEcbProvider extends core__namespace.AesEcbProvider { onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.generateKey(algorithm, extractable, keyUsages); }); } onEncrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.encrypt(algorithm, key, data); }); } onDecrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.decrypt(algorithm, key, data); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); AesCrypto.checkCryptoKey(key); } } class AesGcmProvider extends core__namespace.AesGcmProvider { onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.generateKey(algorithm, extractable, keyUsages); }); } onEncrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.encrypt(algorithm, key, data); }); } onDecrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.decrypt(algorithm, key, data); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); AesCrypto.checkCryptoKey(key); } } class AesCtrProvider extends core__namespace.AesCtrProvider { onEncrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const result = new asmCrypto__namespace.AES_CTR(key.raw, core__namespace.BufferSourceConverter.toUint8Array(algorithm.counter)) .encrypt(core__namespace.BufferSourceConverter.toUint8Array(data)); return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } onDecrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const result = new asmCrypto__namespace.AES_CTR(key.raw, core__namespace.BufferSourceConverter.toUint8Array(algorithm.counter)) .decrypt(core__namespace.BufferSourceConverter.toUint8Array(data)); return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.generateKey(algorithm, extractable, keyUsages); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); AesCrypto.checkCryptoKey(key); } } class AesKwProvider extends core__namespace.AesKwProvider { onEncrypt(_algorithm, _key, _data) { return tslib.__awaiter(this, void 0, void 0, function* () { throw new Error("Method not implemented."); }); } onDecrypt(_algorithm, _key, _data) { return tslib.__awaiter(this, void 0, void 0, function* () { throw new Error("Method not implemented."); }); } onGenerateKey(_algorithm, _extractable, _keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { throw new Error("Method not implemented."); }); } onExportKey(_format, _key) { return tslib.__awaiter(this, void 0, void 0, function* () { throw new Error("Method not implemented."); }); } onImportKey(_format, _keyData, _algorithm, _extractable, _keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { throw new Error("Method not implemented."); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); AesCrypto.checkCryptoKey(key); } } class RsaCryptoKey extends CryptoKey { constructor(algorithm, extractable, type, usages, data) { super(algorithm, extractable, type, usages); this.data = data; } } class RsaCrypto { static checkCryptoKey(key) { if (!(key instanceof RsaCryptoKey)) { throw new TypeError("key: Is not RsaCryptoKey"); } } static generateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { const alg = { name: "RSA-PSS", hash: "SHA-256", publicExponent: algorithm.publicExponent, modulusLength: algorithm.modulusLength, }; const keys = (yield exports.nativeSubtle.generateKey(alg, true, ["sign", "verify"])); const crypto = new Crypto(); const pkcs8 = yield crypto.subtle.exportKey("pkcs8", keys.privateKey); const privateKey = yield crypto.subtle.importKey("pkcs8", pkcs8, algorithm, extractable, keyUsages.filter((o) => this.privateUsages.includes(o))); const spki = yield crypto.subtle.exportKey("spki", keys.publicKey); const publicKey = yield crypto.subtle.importKey("spki", spki, algorithm, true, keyUsages.filter((o) => this.publicUsages.includes(o))); return { privateKey, publicKey }; }); } static exportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { switch (format) { case "pkcs8": return this.exportPkcs8Key(key); case "spki": return this.exportSpkiKey(key); case "jwk": return this.exportJwkKey(key); default: throw new core__namespace.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); } }); } static importKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { let asmKey; switch (format) { case "pkcs8": asmKey = this.importPkcs8Key(keyData); break; case "spki": asmKey = this.importSpkiKey(keyData); break; case "jwk": asmKey = this.importJwkKey(keyData); break; default: throw new core__namespace.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'"); } const key = new RsaCryptoKey(Object.assign({ publicExponent: asmKey[1][1] === 1 ? asmKey[1].slice(1) : asmKey[1].slice(3), modulusLength: asmKey[0].byteLength << 3 }, algorithm), extractable, asmKey.length === 2 ? "public" : "private", keyUsages, asmKey); return key; }); } static randomNonZeroValues(data) { data = exports.nativeCrypto.getRandomValues(data); return data.map((n) => { while (!n) { n = exports.nativeCrypto.getRandomValues(new Uint8Array(1))[0]; } return n; }); } static exportPkcs8Key(key) { const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.privateKeyAlgorithm.parameters = null; keyInfo.privateKey = asn1Schema.AsnConvert.serialize(this.exportAsmKey(key.data)); return asn1Schema.AsnConvert.serialize(keyInfo); } static importPkcs8Key(data) { const keyInfo = asn1Schema.AsnConvert.parse(data, core__namespace.asn1.PrivateKeyInfo); const privateKey = asn1Schema.AsnConvert.parse(keyInfo.privateKey, core__namespace.asn1.RsaPrivateKey); return this.importAsmKey(privateKey); } static importSpkiKey(data) { const keyInfo = asn1Schema.AsnConvert.parse(data, core__namespace.asn1.PublicKeyInfo); const publicKey = asn1Schema.AsnConvert.parse(keyInfo.publicKey, core__namespace.asn1.RsaPublicKey); return this.importAsmKey(publicKey); } static exportSpkiKey(key) { const publicKey = new core__namespace.asn1.RsaPublicKey(); publicKey.modulus = key.data[0].buffer; publicKey.publicExponent = key.data[1][1] === 1 ? key.data[1].buffer.slice(1) : key.data[1].buffer.slice(3); const keyInfo = new core__namespace.asn1.PublicKeyInfo(); keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1"; keyInfo.publicKeyAlgorithm.parameters = null; keyInfo.publicKey = asn1Schema.AsnConvert.serialize(publicKey); return asn1Schema.AsnConvert.serialize(keyInfo); } static importJwkKey(data) { let key; if (data.d) { key = jsonSchema.JsonParser.fromJSON(data, { targetSchema: core__namespace.asn1.RsaPrivateKey }); } else { key = jsonSchema.JsonParser.fromJSON(data, { targetSchema: core__namespace.asn1.RsaPublicKey }); } return this.importAsmKey(key); } static exportJwkKey(key) { const asnKey = this.exportAsmKey(key.data); const jwk = jsonSchema.JsonSerializer.toJSON(asnKey); jwk.ext = true; jwk.key_ops = key.usages; jwk.kty = "RSA"; jwk.alg = this.getJwkAlgorithm(key.algorithm); return jwk; } static 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 "RSAES-PKCS1-V1_5": return `PS1`; default: throw new core__namespace.OperationError("algorithm: Is not recognized"); } } static exportAsmKey(asmKey) { let key; if (asmKey.length > 2) { const privateKey = new core__namespace.asn1.RsaPrivateKey(); privateKey.privateExponent = asmKey[2].buffer; privateKey.prime1 = asmKey[3].buffer; privateKey.prime2 = asmKey[4].buffer; privateKey.exponent1 = asmKey[5].buffer; privateKey.exponent2 = asmKey[6].buffer; privateKey.coefficient = asmKey[7].buffer; key = privateKey; } else { key = new core__namespace.asn1.RsaPublicKey(); } key.modulus = asmKey[0].buffer; key.publicExponent = asmKey[1][1] === 1 ? asmKey[1].buffer.slice(1) : asmKey[1].buffer.slice(3); return key; } static importAsmKey(key) { const expPadding = new Uint8Array(4 - key.publicExponent.byteLength); const asmKey = [ new Uint8Array(key.modulus), concat(expPadding, new Uint8Array(key.publicExponent)), ]; if (key instanceof core__namespace.asn1.RsaPrivateKey) { asmKey.push(new Uint8Array(key.privateExponent)); asmKey.push(new Uint8Array(key.prime1)); asmKey.push(new Uint8Array(key.prime2)); asmKey.push(new Uint8Array(key.exponent1)); asmKey.push(new Uint8Array(key.exponent2)); asmKey.push(new Uint8Array(key.coefficient)); } return asmKey; } } RsaCrypto.RsaSsa = "RSASSA-PKCS1-v1_5"; RsaCrypto.RsaPss = "RSA-PSS"; RsaCrypto.RsaOaep = "RSA-OAEP"; RsaCrypto.privateUsages = ["sign", "decrypt", "unwrapKey"]; RsaCrypto.publicUsages = ["verify", "encrypt", "wrapKey"]; class ShaCrypto { static getDigest(name) { switch (name) { case "SHA-1": return new asmCrypto__namespace.Sha1(); case "SHA-256": return new asmCrypto__namespace.Sha256(); case "SHA-512": return new asmCrypto__namespace.Sha512(); default: throw new core__namespace.AlgorithmError("keyAlgorithm.hash: Is not recognized"); } } static digest(algorithm, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const mech = this.getDigest(algorithm.name); const result = mech .process(core__namespace.BufferSourceConverter.toUint8Array(data)) .finish().result; return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } } class RsaOaepProvider extends core__namespace.RsaOaepProvider { onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.generateKey(algorithm, extractable, keyUsages); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } onEncrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return this.cipher(algorithm, key, data); }); } onDecrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { return this.cipher(algorithm, key, data); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); RsaCrypto.checkCryptoKey(key); } cipher(algorithm, key, data) { const digest = ShaCrypto.getDigest(key.algorithm.hash.name); let label; if (algorithm.label) { label = core__namespace.BufferSourceConverter.toUint8Array(algorithm.label); } const cipher = new asmCrypto__namespace.RSA_OAEP(key.data, digest, label); let res; const u8Data = core__namespace.BufferSourceConverter.toUint8Array(data); if (key.type === "public") { res = cipher.encrypt(u8Data); } else { res = cipher.decrypt(u8Data); } return core__namespace.BufferSourceConverter.toArrayBuffer(res); } } class RsaPssProvider extends core__namespace.RsaPssProvider { onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.generateKey(algorithm, extractable, keyUsages); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } onSign(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const rsa = new asmCrypto__namespace.RSA_PSS(key.data, ShaCrypto.getDigest(key.algorithm.hash.name), algorithm.saltLength); const result = rsa.sign(core__namespace.BufferSourceConverter.toUint8Array(data)); return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } onVerify(algorithm, key, signature, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const rsa = new asmCrypto__namespace.RSA_PSS(key.data, ShaCrypto.getDigest(key.algorithm.hash.name), algorithm.saltLength); try { rsa.verify(core__namespace.BufferSourceConverter.toUint8Array(signature), core__namespace.BufferSourceConverter.toUint8Array(data)); } catch (_a) { return false; } return true; }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); RsaCrypto.checkCryptoKey(key); } } class RsaSsaProvider extends core__namespace.RsaSsaProvider { onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.generateKey(algorithm, extractable, keyUsages); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } onSign(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const rsa = new asmCrypto__namespace.RSA_PKCS1_v1_5(key.data, ShaCrypto.getDigest(key.algorithm.hash.name)); const result = rsa.sign(core__namespace.BufferSourceConverter.toUint8Array(data)); return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } onVerify(algorithm, key, signature, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const rsa = new asmCrypto__namespace.RSA_PKCS1_v1_5(key.data, ShaCrypto.getDigest(key.algorithm.hash.name)); try { rsa.verify(core__namespace.BufferSourceConverter.toUint8Array(signature), core__namespace.BufferSourceConverter.toUint8Array(data)); } catch (_a) { return false; } return true; }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); RsaCrypto.checkCryptoKey(key); } } class RsaEsProvider extends core__namespace.ProviderCrypto { constructor() { super(...arguments); this.name = "RSAES-PKCS1-v1_5"; this.usages = { publicKey: ["encrypt", "wrapKey"], privateKey: ["decrypt", "unwrapKey"], }; this.hashAlgorithms = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]; } onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.generateKey(algorithm, extractable, keyUsages); }); } 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"); } } onDecrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const EM = new asmCrypto__namespace.RSA(key.data).decrypt(new asmCrypto__namespace.BigNumber(core__namespace.BufferSourceConverter.toUint8Array(data))).result; const k = key.algorithm.modulusLength >> 3; if (data.byteLength !== k) { throw new core__namespace.CryptoError("Decryption error. Encrypted message size doesn't match to key length"); } let offset = 0; if (EM[offset++] || EM[offset++] !== 2) { throw new core__namespace.CryptoError("Decryption error"); } do { if (EM[offset++] === 0) { break; } } while (offset < EM.length); if (offset < 11) { throw new core__namespace.CryptoError("Decryption error. PS is less than 8 octets."); } if (offset === EM.length) { throw new core__namespace.CryptoError("Decryption error. There is no octet with hexadecimal value 0x00 to separate PS from M"); } return EM.buffer.slice(offset); }); } onEncrypt(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { const k = key.algorithm.modulusLength >> 3; if (data.byteLength > k - 11) { throw new core__namespace.CryptoError("Message too long"); } const psLen = k - data.byteLength - 3; const PS = RsaCrypto.randomNonZeroValues(new Uint8Array(psLen)); const EM = new Uint8Array(k); EM[0] = 0; EM[1] = 2; EM.set(PS, 2); EM[2 + psLen] = 0; EM.set(new Uint8Array(data), 3 + psLen); const result = new asmCrypto__namespace.RSA(key.data).encrypt(new asmCrypto__namespace.BigNumber(EM)).result; return core__namespace.BufferSourceConverter.toArrayBuffer(result); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return RsaCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { const key = yield RsaCrypto.importKey(format, keyData, Object.assign(Object.assign({}, algorithm), { name: this.name }), extractable, keyUsages); return key; }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); RsaCrypto.checkCryptoKey(key); } } 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", "1.3.36.3.3.2.8.1.1.7": "brainpoolP256r1", "brainpoolP256r1": "1.3.36.3.3.2.8.1.1.7", "1.3.36.3.3.2.8.1.1.11": "brainpoolP384r1", "brainpoolP384r1": "1.3.36.3.3.2.8.1.1.11", "1.3.36.3.3.2.8.1.1.13": "brainpoolP512r1", "brainpoolP512r1": "1.3.36.3.3.2.8.1.1.13", }; 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 EcCryptoKey extends CryptoKey { constructor(algorithm, extractable, type, usages, data) { super(algorithm, extractable, type, usages); this.data = data; } } class EcCrypto { static checkLib() { if (typeof (elliptic__namespace) === "undefined") { throw new core__namespace.OperationError("Cannot implement EC mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/elliptic.js' script to your project"); } } static generateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { this.checkLib(); const key = this.initEcKey(algorithm.namedCurve); const ecKey = key.genKeyPair(); ecKey.getPublic(); const prvKey = new EcCryptoKey(Object.assign({}, algorithm), extractable, "private", keyUsages.filter((usage) => ~this.privateUsages.indexOf(usage)), ecKey); const pubKey = new EcCryptoKey(Object.assign({}, algorithm), true, "public", keyUsages.filter((usage) => ~this.publicUsages.indexOf(usage)), ecKey); return { privateKey: prvKey, publicKey: pubKey, }; }); } static checkCryptoKey(key) { if (!(key instanceof EcCryptoKey)) { throw new TypeError("key: Is not EcCryptoKey"); } } static concat(...buf) { const res = new Uint8Array(buf.map((item) => item.length).reduce((prev, cur) => prev + cur)); let offset = 0; buf.forEach((item) => { for (let i = 0; i < item.length; i++) { res[offset + i] = item[i]; } offset += item.length; }); return res; } static exportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { this.checkLib(); switch (format) { case "pkcs8": return this.exportPkcs8Key(key); case "spki": return this.exportSpkiKey(key); case "jwk": return this.exportJwkKey(key); case "raw": return new Uint8Array(key.data.getPublic("der")).buffer; default: throw new core__namespace.OperationError("format: Must be 'jwk', 'raw, 'pkcs8' or 'spki'"); } }); } static importKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { this.checkLib(); let ecKey; switch (format) { case "pkcs8": ecKey = this.importPkcs8Key(keyData, algorithm.namedCurve); break; case "spki": ecKey = this.importSpkiKey(keyData, algorithm.namedCurve); break; case "raw": ecKey = this.importEcKey(new core__namespace.asn1.EcPublicKey(keyData), algorithm.namedCurve); break; case "jwk": ecKey = this.importJwkKey(keyData); break; default: throw new core__namespace.OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'"); } const key = new EcCryptoKey(Object.assign({}, algorithm), extractable, ecKey.priv ? "private" : "public", keyUsages, ecKey); return key; }); } static getNamedCurve(wcNamedCurve) { const crv = wcNamedCurve.toUpperCase(); let res = ""; if (["P-256", "P-384", "P-521"].indexOf(crv) > -1) { res = crv.replace("-", "").toLowerCase(); } else if (crv === "K-256") { res = "secp256k1"; } else if (["brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"].includes(wcNamedCurve)) { res = wcNamedCurve; } else { throw new core__namespace.OperationError(`Unsupported named curve '${wcNamedCurve}'`); } return res; } static initEcKey(namedCurve) { return elliptic__namespace.ec(this.getNamedCurve(namedCurve)); } static exportPkcs8Key(key) { const keyInfo = new core__namespace.asn1.PrivateKeyInfo(); keyInfo.privateKeyAlgorithm.algorithm = this.ASN_ALGORITHM; keyInfo.privateKeyAlgorithm.parameters = asn1Schema.AsnConvert.serialize(new core__namespace.asn1.ObjectIdentifier(getOidByNamedCurve$1(key.algorithm.namedCurve))); keyInfo.privateKey = asn1Schema.AsnConvert.serialize(this.exportEcKey(key)); return asn1Schema.AsnConvert.serialize(keyInfo); } static importPkcs8Key(data, namedCurve) { const keyInfo = asn1Schema.AsnConvert.parse(data, core__namespace.asn1.PrivateKeyInfo); const privateKey = asn1Schema.AsnConvert.parse(keyInfo.privateKey, core__namespace.asn1.EcPrivateKey); return this.importEcKey(privateKey, namedCurve); } static importSpkiKey(data, namedCurve) { const keyInfo = asn1Schema.AsnConvert.parse(data, core__namespace.asn1.PublicKeyInfo); const publicKey = new core__namespace.asn1.EcPublicKey(keyInfo.publicKey); return this.importEcKey(publicKey, namedCurve); } static exportSpkiKey(key) { const publicKey = new core__namespace.asn1.EcPublicKey(new Uint8Array(key.data.getPublic("der")).buffer); const keyInfo = new core__namespace.asn1.PublicKeyInfo(); keyInfo.publicKeyAlgorithm.algorithm = this.ASN_ALGORITHM; keyInfo.publicKeyAlgorithm.parameters = asn1Schema.AsnConvert.serialize(new core__namespace.asn1.ObjectIdentifier(getOidByNamedCurve$1(key.algorithm.namedCurve))); keyInfo.publicKey = publicKey.value; return asn1Schema.AsnConvert.serialize(keyInfo); } static importJwkKey(data) { let key; if (data.d) { key = jsonSchema.JsonParser.fromJSON(data, { targetSchema: core__namespace.asn1.EcPrivateKey }); } else { key = jsonSchema.JsonParser.fromJSON(data, { targetSchema: core__namespace.asn1.EcPublicKey }); } return this.importEcKey(key, data.crv); } static exportJwkKey(key) { const asnKey = this.exportEcKey(key); const jwk = jsonSchema.JsonSerializer.toJSON(asnKey); jwk.ext = true; jwk.key_ops = key.usages; jwk.crv = key.algorithm.namedCurve; jwk.kty = "EC"; return jwk; } static exportEcKey(ecKey) { if (ecKey.type === "private") { const privateKey = new core__namespace.asn1.EcPrivateKey(); const point = new Uint8Array(ecKey.data.getPrivate("der").toArray()); const pointPad = new Uint8Array(this.getPointSize(ecKey.algorithm.namedCurve) - point.length); privateKey.privateKey = concat(pointPad, point); privateKey.publicKey = new Uint8Array(ecKey.data.getPublic("der")); return privateKey; } else if (ecKey.data.pub) { return new core__namespace.asn1.EcPublicKey(new Uint8Array(ecKey.data.getPublic("der")).buffer); } else { throw new Error("Cannot get private or public key"); } } static importEcKey(key, namedCurve) { const ecKey = this.initEcKey(namedCurve); if (key instanceof core__namespace.asn1.EcPublicKey) { return ecKey.keyFromPublic(new Uint8Array(key.value)); } return ecKey.keyFromPrivate(new Uint8Array(key.privateKey)); } static getPointSize(namedCurve) { switch (namedCurve) { case "P-256": case "K-256": return 32; case "P-384": return 48; case "P-521": return 66; } throw new Error("namedCurve: Is not recognized"); } } EcCrypto.privateUsages = ["sign", "deriveKey", "deriveBits"]; EcCrypto.publicUsages = ["verify"]; EcCrypto.ASN_ALGORITHM = "1.2.840.10045.2.1"; class EcdhProvider extends core__namespace.EcdhProvider { constructor() { super(...arguments); this.namedCurves = ["P-256", "P-384", "P-521", "K-256", "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"]; } onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return EcCrypto.generateKey(algorithm, extractable, keyUsages); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return EcCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return EcCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } onDeriveBits(algorithm, baseKey, length) { return tslib.__awaiter(this, void 0, void 0, function* () { EcCrypto.checkLib(); const shared = baseKey.data.derive(algorithm.public.data.getPublic()); let array = new Uint8Array(shared.toArray()); let len = array.length; len = (len > 32 ? (len > 48 ? 66 : 48) : 32); if (array.length < len) { array = EcCrypto.concat(new Uint8Array(len - array.length), array); } const buf = array.slice(0, length / 8).buffer; return buf; }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); EcCrypto.checkCryptoKey(key); } } function b2a(buffer) { const buf = new Uint8Array(buffer); const res = []; for (let i = 0; i < buf.length; i++) { res.push(buf[i]); } return res; } class EcdsaProvider extends core__namespace.EcdsaProvider { constructor() { super(...arguments); this.hashAlgorithms = ["SHA-1", "SHA-256", "SHA-384", "SHA-512", "SHA3-256", "SHA3-384", "SHA3-512"]; this.namedCurves = ["P-256", "P-384", "P-521", "K-256", "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"]; } onGenerateKey(algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return EcCrypto.generateKey(algorithm, extractable, keyUsages); }); } onExportKey(format, key) { return tslib.__awaiter(this, void 0, void 0, function* () { return EcCrypto.exportKey(format, key); }); } onImportKey(format, keyData, algorithm, extractable, keyUsages) { return tslib.__awaiter(this, void 0, void 0, function* () { return EcCrypto.importKey(format, keyData, algorithm, extractable, keyUsages); }); } onSign(algorithm, key, data) { return tslib.__awaiter(this, void 0, void 0, function* () { EcCrypto.checkLib(); const crypto = new Crypto(); const hash = yield crypto.subtle.digest(algorithm.hash, data); const array = b2a(hash); const signature = yield key.data.sign(array); const asnSignature = new core__namespace.asn1.EcDsaSignature(); asnSignature.r = new Uint8Array(signature.r.toArray()).buffer; asnSignature.s = new Uint8Array(signature.s.toArray()).buffer; return asnSignature.toWebCryptoSignature(); }); } onVerify(algorithm, key, signature, data) { return tslib.__awaiter(this, void 0, void 0, function* () { EcCrypto.checkLib(); const crypto = new Crypto(); const sig = { r: new Uint8Array(signature.slice(0, signature.byteLength / 2)), s: new Uint8Array(signature.slice(signature.byteLength / 2)), }; const hashedData = yield crypto.subtle.digest(algorithm.hash, data); const array = b2a(hashedData); return key.data.verify(array, sig); }); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); EcCrypto.checkCryptoKey(key); } } 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 CryptoKey { constructor(algorithm, extractable, usages, data) { super(algorithm, extractable, "private", usages); this.data = data; } toJSON() { const json = { kty: "OKP", crv: this.algorithm.namedCurve, key_ops: this.usages, ext: this.extractable, }; return Object.assign(json, { d: pvtsutils.Convert.ToBase64Url(pvtsutils.Convert.FromHex(/^ed/i.test(json.crv) ? this.data.getSecret("hex") : this.data.getPrivate("hex"))), }); } fromJSON(json) { if (!json.d) { throw new core__namespace.OperationError(`Cannot get private data from JWK. Property 'd' is required`); } if (!json.crv) { throw new core__namespace.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`); } const hexPrivateKey = pvtsutils.Convert.ToHex(pvtsutils.Convert.FromBase64Url(json.d)); if (/^ed/i.test(json.crv)) { const eddsa = new elliptic__namespace.eddsa("ed25519"); this.data = eddsa.keyFromSecret(hexPrivateKey); } else { const ecdhEs = elliptic__namespace.ec(json.crv.replace(/^x/i, "curve")); this.data = ecdhEs.keyFromPrivate(hexPrivateKey, "hex"); } return this; } } class EdPublicKey extends CryptoKey { constructor(algorithm, extractable, usages, data) { super(algorithm, extractable, "public", usages); this.data = data; } toJSON() { const json = { kty: "OKP", crv: this.algorithm.namedCurve, key_ops: this.usages, ext: this.extractable, }; return Object.assign(json, { x: pvtsutils.Convert.ToBase64Url(pvtsutils.Convert.FromHex(this.data.getPublic("hex"))), }); } 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_