From e73f0f646b305f3e89984a98045507610ff01f96 Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 23 Mar 2020 11:36:54 +0300 Subject: [PATCH 1/5] Update core --- .npmignore | 6 +- .waiting.html | 21 - README.md | 13 +- lib/crypto.ts | 50 + lib/crypto/aes.ts | 230 ---- lib/crypto/ec.ts | 357 ------ lib/crypto/hmac.ts | 145 --- lib/crypto/pbkdf2.ts | 87 -- lib/crypto/rsa.ts | 317 ----- lib/index.ts | 1 + lib/key.ts | 33 - lib/key_storage.ts | 367 ++---- lib/keys/asymmetric.ts | 6 + lib/keys/index.ts | 4 + lib/keys/key.ts | 13 + lib/keys/storage.ts | 23 + lib/keys/symmetric.ts | 5 + lib/mechs/aes/aes_cbc.ts | 61 + lib/mechs/aes/aes_cmac.ts | 152 +++ lib/mechs/aes/aes_ctr.ts | 60 + lib/mechs/aes/aes_ecb.ts | 59 + lib/mechs/aes/aes_gcm.ts | 62 + lib/mechs/aes/aes_kw.ts | 60 + lib/mechs/aes/crypto.ts | 104 ++ lib/mechs/aes/index.ts | 7 + lib/mechs/aes/key.ts | 5 + lib/mechs/des/crypto.ts | 86 ++ lib/mechs/des/des_cbc.ts | 55 + lib/mechs/des/des_ede3_cbc.ts | 55 + lib/mechs/des/index.ts | 3 + lib/mechs/des/key.ts | 19 + lib/mechs/ec/crypto.ts | 280 +++++ lib/mechs/ec/ec_dh.ts | 49 + lib/mechs/ec/ec_dsa.ts | 71 ++ lib/mechs/ec/helper.ts | 32 + lib/mechs/ec/index.ts | 4 + lib/mechs/ec/private_key.ts | 6 + lib/mechs/ec/public_key.ts | 6 + lib/mechs/hmac/hmac.ts | 122 ++ lib/mechs/hmac/index.ts | 1 + lib/mechs/hmac/key.ts | 5 + lib/mechs/pbkdf/index.ts | 1 + lib/mechs/pbkdf/key.ts | 4 + lib/mechs/pbkdf/pbkdf2.ts | 59 + lib/mechs/rsa/crypto.ts | 199 ++++ lib/mechs/rsa/index.ts | 5 + lib/mechs/rsa/private_key.ts | 6 + lib/mechs/rsa/public_key.ts | 6 + lib/mechs/rsa/rsa_oaep.ts | 67 ++ lib/mechs/rsa/rsa_pss.ts | 68 ++ lib/mechs/rsa/rsa_ssa.ts | 68 ++ lib/mechs/sha/crypto.ts | 48 + lib/mechs/sha/index.ts | 4 + lib/mechs/sha/sha_1.ts | 12 + lib/mechs/sha/sha_256.ts | 12 + lib/mechs/sha/sha_384.ts | 12 + lib/mechs/sha/sha_512.ts | 12 + lib/native.ts | 476 ++++---- lib/subtle.ts | 472 +------- lib/types.d.ts | 1 - lib/webcrypto.ts | 57 - package-lock.json | 2109 +++++++++++++++++++-------------- package.json | 67 +- rollup.config.js | 44 + test/aes.js | 296 ----- test/config.js | 4 - test/crypto.js | 19 - test/crypto.ts | 33 + test/digest.js | 70 -- test/ec.js | 217 ---- test/helper.js | 45 - test/hmac.js | 104 -- test/key_storage.js | 129 -- test/key_storage.ts | 76 ++ test/native.js | 509 -------- test/native/pbkdf2.js | 70 -- test/native_hmac.js | 75 -- test/pbkdf2.js | 77 -- test/rsa.js | 242 ---- test/vectors/aes_ctr.js | 62 - test/vectors/aes_kw.js | 54 - test/vectors/ec_secp256k1.js | 170 --- test/vectors/hmac.js | 86 -- test/vectors/pbkdf2.js | 81 -- test/vectors/rsa_pss.js | 41 - tsconfig.json | 8 +- tslint.json | 12 +- 87 files changed, 3921 insertions(+), 5410 deletions(-) delete mode 100644 .waiting.html create mode 100644 lib/crypto.ts delete mode 100644 lib/crypto/aes.ts delete mode 100644 lib/crypto/ec.ts delete mode 100644 lib/crypto/hmac.ts delete mode 100644 lib/crypto/pbkdf2.ts delete mode 100644 lib/crypto/rsa.ts create mode 100644 lib/index.ts delete mode 100644 lib/key.ts create mode 100644 lib/keys/asymmetric.ts create mode 100644 lib/keys/index.ts create mode 100644 lib/keys/key.ts create mode 100644 lib/keys/storage.ts create mode 100644 lib/keys/symmetric.ts create mode 100644 lib/mechs/aes/aes_cbc.ts create mode 100644 lib/mechs/aes/aes_cmac.ts create mode 100644 lib/mechs/aes/aes_ctr.ts create mode 100644 lib/mechs/aes/aes_ecb.ts create mode 100644 lib/mechs/aes/aes_gcm.ts create mode 100644 lib/mechs/aes/aes_kw.ts create mode 100644 lib/mechs/aes/crypto.ts create mode 100644 lib/mechs/aes/index.ts create mode 100644 lib/mechs/aes/key.ts create mode 100644 lib/mechs/des/crypto.ts create mode 100644 lib/mechs/des/des_cbc.ts create mode 100644 lib/mechs/des/des_ede3_cbc.ts create mode 100644 lib/mechs/des/index.ts create mode 100644 lib/mechs/des/key.ts create mode 100644 lib/mechs/ec/crypto.ts create mode 100644 lib/mechs/ec/ec_dh.ts create mode 100644 lib/mechs/ec/ec_dsa.ts create mode 100644 lib/mechs/ec/helper.ts create mode 100644 lib/mechs/ec/index.ts create mode 100644 lib/mechs/ec/private_key.ts create mode 100644 lib/mechs/ec/public_key.ts create mode 100644 lib/mechs/hmac/hmac.ts create mode 100644 lib/mechs/hmac/index.ts create mode 100644 lib/mechs/hmac/key.ts create mode 100644 lib/mechs/pbkdf/index.ts create mode 100644 lib/mechs/pbkdf/key.ts create mode 100644 lib/mechs/pbkdf/pbkdf2.ts create mode 100644 lib/mechs/rsa/crypto.ts create mode 100644 lib/mechs/rsa/index.ts create mode 100644 lib/mechs/rsa/private_key.ts create mode 100644 lib/mechs/rsa/public_key.ts create mode 100644 lib/mechs/rsa/rsa_oaep.ts create mode 100644 lib/mechs/rsa/rsa_pss.ts create mode 100644 lib/mechs/rsa/rsa_ssa.ts create mode 100644 lib/mechs/sha/crypto.ts create mode 100644 lib/mechs/sha/index.ts create mode 100644 lib/mechs/sha/sha_1.ts create mode 100644 lib/mechs/sha/sha_256.ts create mode 100644 lib/mechs/sha/sha_384.ts create mode 100644 lib/mechs/sha/sha_512.ts delete mode 100644 lib/types.d.ts delete mode 100644 lib/webcrypto.ts create mode 100644 rollup.config.js delete mode 100644 test/aes.js delete mode 100644 test/config.js delete mode 100644 test/crypto.js create mode 100644 test/crypto.ts delete mode 100644 test/digest.js delete mode 100644 test/ec.js delete mode 100644 test/helper.js delete mode 100644 test/hmac.js delete mode 100644 test/key_storage.js create mode 100644 test/key_storage.ts delete mode 100644 test/native.js delete mode 100644 test/native/pbkdf2.js delete mode 100644 test/native_hmac.js delete mode 100644 test/pbkdf2.js delete mode 100644 test/rsa.js delete mode 100644 test/vectors/aes_ctr.js delete mode 100644 test/vectors/aes_kw.js delete mode 100644 test/vectors/ec_secp256k1.js delete mode 100644 test/vectors/hmac.js delete mode 100644 test/vectors/pbkdf2.js delete mode 100644 test/vectors/rsa_pss.js diff --git a/.npmignore b/.npmignore index b521a0c..cb91cc1 100644 --- a/.npmignore +++ b/.npmignore @@ -8,8 +8,10 @@ build test*.js +/test # build -lib +/lib ts*.json -**/*.map \ No newline at end of file +**/*.map +rollup.config.js \ No newline at end of file diff --git a/.waiting.html b/.waiting.html deleted file mode 100644 index a964629..0000000 --- a/.waiting.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - Code coverage report for All files - - - -
This page will refresh with a coverage report, as long as you have - executed npm run dev. Please be patient.
- - \ No newline at end of file diff --git a/README.md b/README.md index 85aa70a..dfd3835 100644 --- a/README.md +++ b/README.md @@ -71,19 +71,22 @@ mocha | AES-ECB 2 | X | | X | | X | X | | | AES-GCM | X | | X | | X | X | | | AES-KW | X | | X | | | X | | +| AES-CMAC | X | | X | X | | | | | ECDSA | X | | X | X | | | | | ECDH | X | | X | | | | X | | HMAC | X | | X | X | | | | | PBKDF2 | | | X | | | | X | +| DES-CBC | X | | X | | X | X | | +| DES-EDE3-CBC | X | | X | | X | X | | 2 ECB support is not defined by the WebCrypto specifications. Use of ECB in a safe way is hard, it was added for the purpose of enabling interoperability with an existing system. We recommend against its use unless needed for interoperability. ## Using ```javascript -var WebCrypto = require("node-webcrypto-ossl"); +const { Crypto } = require("node-webcrypto-ossl"); -var webcrypto = new WebCrypto(); +const crypto = new Crypto(); ``` ## Elliptic curve secp256k1 @@ -97,9 +100,9 @@ var webcrypto = new WebCrypto(); To use KeyStorage you should init WebCrypto with `directory` option. If `directory` option is missing then `keyStorage` is `null` ```javascript -var WebCrypto = require("node-webcrypto-ossl"); +const { Crypto } = require("node-webcrypto-ossl"); -var webcrypto = new WebCrypto({ +const crypto = new Crypto({ directory: "key_storage" }) ``` @@ -110,7 +113,7 @@ KeyStorage implements interface of [W3 Storage](https://developer.mozilla.org/en var keyStorage = webcrypto.keyStorage; // generating RSA key -webcrypto.subtle.generateKey({ +crypto.subtle.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 1024, publicExponent: new Uint8Array([1, 0, 1]), diff --git a/lib/crypto.ts b/lib/crypto.ts new file mode 100644 index 0000000..851e9ee --- /dev/null +++ b/lib/crypto.ts @@ -0,0 +1,50 @@ +// Core +import * as crypto from "crypto"; +import * as os from "os"; +import * as path from "path"; +import * as core from "webcrypto-core"; + +// Local +import { CryptoKeyStorage } from "./key_storage"; +import { SubtleCrypto } from "./subtle"; + +export interface CryptoOptions { + directory?: string; +} + +/** + * OpenSSL with WebCrypto Interface + */ +export class Crypto extends core.Crypto { + + public keyStorage: CryptoKeyStorage; + + public subtle = new SubtleCrypto(); + /** + * Constructor + */ + constructor(options?: CryptoOptions) { + super(); + + this.keyStorage = new CryptoKeyStorage(this, options?.directory ?? path.join(os.homedir(), ".node-webcrypto-ossl")); + } + + /** + * Generates cryptographically random values + * @param array Initialize array + */ + // Based on: https://github.com/KenanY/get-random-values + public getRandomValues(array: T): T { + if (ArrayBuffer.isView(array)) { + if (array.byteLength > 65536) { + throw new core.OperationError(`Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (${array.byteLength}) exceeds the number of bytes of entropy available via this API (65536).`); + } + const bytes = crypto.randomBytes(array.byteLength); + (array as any).set(new (array.constructor as typeof Uint8Array)(bytes.buffer)); + return array; + } else { + throw new core.OperationError(`Failed to execute 'getRandomValues' on 'Crypto': Expected ArrayBufferView for 'array' argument.`); + } + } + +} diff --git a/lib/crypto/aes.ts b/lib/crypto/aes.ts deleted file mode 100644 index 9daad51..0000000 --- a/lib/crypto/aes.ts +++ /dev/null @@ -1,230 +0,0 @@ -// Core -import { AlgorithmError, AlgorithmNames, Base64Url, BaseCrypto, WebCryptoError } from "webcrypto-core"; - -// Local -import { CryptoKey } from "../key"; -import * as native from "../native"; - -function b64_decode(b64url: string): Buffer { - return Buffer.from(Base64Url.decode(b64url)); -} - -export class AesCrypto extends BaseCrypto { - - public static generateKey(algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - native.AesKey.generate(algorithm.length / 8, (err, key) => { - if (err) { - reject(err); - } else { - const aes = new CryptoKey(key, algorithm, "secret", extractable, keyUsages); - resolve(aes); - } - }); - }); - } - - public static importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const formatLC = format.toLocaleLowerCase(); - let raw: Buffer; - switch (formatLC) { - case "jwk": - raw = b64_decode((keyData as JsonWebKey).k!); - break; - case "raw": - raw = keyData as Buffer; - break; - default: - throw new WebCryptoError(`ImportKey: Wrong format value '${format}'`); - } - (algorithm as any).length = raw.byteLength * 8; - native.AesKey.import(raw, (err, key) => { - if (err) { - reject(err); - } else { - resolve(new CryptoKey(key, algorithm as Algorithm, "secret", extractable, keyUsages)); - } - }); - }); - } - - public static exportKey(format: "jwk", key: CryptoKey): PromiseLike; - public static exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike; - public static exportKey(format: string, key: CryptoKey): PromiseLike; - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return new Promise((resolve, reject) => { - const nativeKey = key.native as native.AesKey; - switch (format.toLocaleLowerCase()) { - case "jwk": - const jwk: JsonWebKey = { - kty: "oct", - alg: "", - key_ops: key.usages, - k: "", - ext: true, - }; - // set alg - jwk.alg = "A" + (key.algorithm as any).length + /-(\w+)$/.exec(key.algorithm.name)![1].toUpperCase(); - nativeKey.export((err, data) => { - if (err) { - reject(err); - } else { - jwk.k = Base64Url.encode(data); - resolve(jwk); - } - }); - break; - case "raw": - nativeKey.export((err, data) => { - if (err) { - reject(err); - } else { - resolve(data.buffer as ArrayBuffer); - } - }); - break; - default: throw new WebCryptoError(`ExportKey: Unknown export format '${format}'`); - } - }); - } - - public static encrypt(algorithm: AesCbcParams | AesGcmParams, key: CryptoKey, data: Buffer): PromiseLike { - if (algorithm.name.toUpperCase() === AlgorithmNames.AesKW) { - return this.WrapUnwrap(key.native as native.AesKey, data, true); - } else { - return this.EncryptDecrypt(algorithm, key, data, true); - } - } - - public static decrypt(algorithm: AesCbcParams | AesGcmParams, key: CryptoKey, data: Buffer): PromiseLike { - if (algorithm.name.toUpperCase() === AlgorithmNames.AesKW) { - return this.WrapUnwrap(key.native as native.AesKey, data, false); - } else { - return this.EncryptDecrypt(algorithm, key, data, false); - } - } - - protected static EncryptDecrypt(algorithm: AesCbcParams | AesGcmParams, key: CryptoKey, data: Buffer, type: boolean): PromiseLike { - return new Promise((resolve, reject) => { - const nativeKey = key.native as native.AesKey; - switch (algorithm.name.toLowerCase()) { - case AlgorithmNames.AesGCM.toLowerCase(): { - const algGCM = algorithm as AesGcmParams; - const iv = Buffer.from(algorithm.iv as Uint8Array); - const aad = algGCM.additionalData ? Buffer.from(algGCM.additionalData as Uint8Array) : Buffer.alloc(0); - const tagLength = algGCM.tagLength || 128; - if (type) { - nativeKey.encryptGcm(iv, data, aad || Buffer.alloc(0), tagLength / 8, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } else { - nativeKey.decryptGcm(iv, data, aad || Buffer.alloc(0), tagLength / 8, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } - break; - } - case AlgorithmNames.AesCBC.toLowerCase(): { - const algCBC = "CBC"; - const iv = Buffer.from(algorithm.iv as Uint8Array); - if (type) { - nativeKey.encrypt(algCBC, iv, data, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } else { - nativeKey.decrypt(algCBC, iv, data, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } - break; - } - case AlgorithmNames.AesCTR.toLowerCase(): { - const alg: AesCtrParams = algorithm as any; - const counter = Buffer.from(alg.counter as Uint8Array); - if (type) { - nativeKey.encryptCtr(data, counter, alg.length, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } else { - nativeKey.decryptCtr(data, counter, alg.length, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } - break; - } - case AlgorithmNames.AesECB.toLowerCase(): { - if (type) { - nativeKey.encryptEcb(data, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } else { - nativeKey.decryptEcb(data, (err, data2) => { - if (err) { - reject(err); - } else { - resolve(data2.buffer as ArrayBuffer); - } - }); - } - break; - } - default: throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, algorithm.name); - } - }); - } - - /** - * Wrap/Unwrap function for AES-KW - * - * @protected - * @param {native.AesKey} key Native key - * @param {Buffer} data Incoming data - * @param {boolean} enc Type of operation. `true` - wrap, `false` - unwrap - * @returns - * - * @memberOf AesCrypto - */ - protected static WrapUnwrap(key: native.AesKey, data: Buffer, enc: boolean) { - return new Promise((resolve, reject) => { - const fn = enc ? key.wrapKey : key.unwrapKey; - - fn.call(key, data, (err: Error, data2: Buffer) => { - if (err) { - reject(err); - } else { - resolve(new Uint8Array(data2).buffer as ArrayBuffer); - } - }); - }); - } - -} diff --git a/lib/crypto/ec.ts b/lib/crypto/ec.ts deleted file mode 100644 index eeb4698..0000000 --- a/lib/crypto/ec.ts +++ /dev/null @@ -1,357 +0,0 @@ -// Core -import * as webcrypto from "webcrypto-core"; -const AlgorithmError = webcrypto.AlgorithmError; -const WebCryptoError = webcrypto.WebCryptoError; -const AlgorithmNames = webcrypto.AlgorithmNames; -const BaseCrypto = webcrypto.BaseCrypto; -const Base64Url = webcrypto.Base64Url; - -// Local -import { CryptoKey } from "../key"; -import * as native from "../native"; -import * as aes from "./aes"; - -function nc2ssl(nc: any) { - let namedCurve = ""; - switch (nc.toUpperCase()) { - case "P-192": - namedCurve = "secp192r1"; - break; - case "P-256": - namedCurve = "secp256r1"; - break; - case "P-384": - namedCurve = "secp384r1"; - break; - case "P-521": - namedCurve = "secp521r1"; - break; - case "K-256": - namedCurve = "secp256k1"; - break; - default: - throw new WebCryptoError("Unsupported namedCurve in use"); - } - return (native.EcNamedCurves as any)[namedCurve]; -} - -function b64_decode(b64url: string): Buffer { - return Buffer.from(Base64Url.decode(b64url)); -} - -function buf_pad(buf: Buffer, padSize: number = 0) { - if (padSize && Buffer.length < padSize) { - const pad = Buffer.from(new Uint8Array(padSize - buf.length).map((v) => 0)); - return Buffer.concat([pad, buf]); - } - return buf; -} - -export class EcCrypto extends BaseCrypto { - - public static generateKey(algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const alg = algorithm as EcKeyGenParams; - const namedCurve = nc2ssl(alg.namedCurve); - - native.Key.generateEc(namedCurve, (err, key) => { - if (err) { - reject(err); - } else { - const prvUsages = ["sign", "deriveKey", "deriveBits"] - .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; - const pubUsages = ["verify"] - .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; - resolve({ - privateKey: new CryptoKey(key, algorithm, "private", extractable, prvUsages), - publicKey: new CryptoKey(key, algorithm, "public", true, pubUsages), - }); - } - }); - }); - } - - public static importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const formatLC = format.toLocaleLowerCase(); - const alg = algorithm as EcKeyImportParams; - const data: { [key: string]: Buffer } = {}; - let keyType = native.KeyType.PUBLIC; - switch (formatLC) { - case "raw": - if (!Buffer.isBuffer(keyData)) { - throw new WebCryptoError("ImportKey: keyData is not a Buffer"); - } - if (!alg.namedCurve) { - throw new WebCryptoError("ImportKey: namedCurve property of algorithm parameter is required"); - } - - let keyLength = 0; - - if (keyData.length === 65) { - // P-256 - // Key length 32 Byte - keyLength = 32; - } else if (keyData.length === 97) { - // P-384 - // Key length 48 Byte - keyLength = 48; - } else if (keyData.length === 133) { - // P-521 - // Key length: 521/= 65,125 => 66 Byte - keyLength = 66; - } - - const x = keyData.slice(1, keyLength + 1); - const y = keyData.slice(keyLength + 1, (keyLength * 2) + 1); - - data["kty"] = Buffer.from("EC", "utf-8"); - data["crv"] = nc2ssl(alg.namedCurve.toUpperCase()); - data["x"] = b64_decode(Base64Url.encode(buf_pad(x, keyLength))); - data["y"] = b64_decode(Base64Url.encode(buf_pad(y, keyLength))); - - native.Key.importJwk(data, keyType, (err, key) => { - try { - if (err) { - reject(new WebCryptoError(`ImportKey: Cannot import key from JWK\n${err}`)); - } else { - const ec = new CryptoKey(key, alg, keyType ? "private" : "public", extractable, keyUsages); - resolve(ec); - } - } catch (e) { - reject(e); - } - }); - - break; - case "jwk": - const jwk = keyData as JsonWebKey; - // prepare data - data["kty"] = jwk.kty as any; - data["crv"] = nc2ssl(jwk.crv); - data["x"] = b64_decode(jwk.x!); - data["y"] = b64_decode(jwk.y!); - if (jwk.d) { - keyType = native.KeyType.PRIVATE; - data["d"] = b64_decode(jwk.d!); - } - native.Key.importJwk(data, keyType, (err, key) => { - try { - if (err) { - reject(new WebCryptoError(`ImportKey: Cannot import key from JWK\n${err}`)); - } else { - const ec = new CryptoKey(key, alg, keyType ? "private" : "public", extractable, keyUsages); - resolve(ec); - } - } catch (e) { - reject(e); - } - }); - break; - case "pkcs8": - case "spki": - if (!Buffer.isBuffer(keyData)) { - throw new WebCryptoError("ImportKey: keyData is not a Buffer"); - } - let importFunction = native.Key.importPkcs8; - if (formatLC === "spki") { - importFunction = native.Key.importSpki; - } - importFunction(keyData as Buffer, (err, key) => { - try { - if (err) { - reject(new WebCryptoError(`ImportKey: Can not import key for ${format}\n${err.message}`)); - } else { - const ec = new CryptoKey(key, alg, format.toLocaleLowerCase() === "spki" ? "public" : "private", extractable, keyUsages); - resolve(ec); - } - } catch (e) { - reject(e); - } - }); - break; - default: - throw new WebCryptoError(`ImportKey: Wrong format value '${format}'`); - } - }); - } - - public static exportKey(format: "jwk", key: CryptoKey): PromiseLike; - public static exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike; - public static exportKey(format: string, key: CryptoKey): PromiseLike; - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return new Promise((resolve, reject) => { - const nativeKey = key.native as native.Key; - const type = key.type === "public" ? native.KeyType.PUBLIC : native.KeyType.PRIVATE; - switch (format.toLocaleLowerCase()) { - case "jwk": - nativeKey.exportJwk(type, (err, data) => { - try { - const jwk: JsonWebKey = { kty: "EC" }; - jwk.crv = (key.algorithm as any).namedCurve; - jwk.key_ops = key.usages; - // convert base64 -> base64url for all props - let padSize = 0; - switch (jwk.crv) { - case "P-256": - case "K-256": - padSize = 32; - break; - case "P-384": - padSize = 48; - break; - case "P-521": - padSize = 66; - break; - default: - throw new Error(`Unsupported named curve '${jwk.crv}'`); - } - jwk.x = Base64Url.encode(buf_pad(data.x, padSize)); - jwk.y = Base64Url.encode(buf_pad(data.y, padSize)); - if (key.type === "private") { - jwk.d = Base64Url.encode(buf_pad(data.d, padSize)); - } - resolve(jwk); - } catch (e) { - reject(e); - } - }); - break; - case "spki": - nativeKey.exportSpki((err, raw) => { - if (err) { - reject(err); - } else { - resolve(raw.buffer as ArrayBuffer); - } - }); - break; - case "pkcs8": - nativeKey.exportPkcs8((err, raw) => { - if (err) { - reject(err); - } else { - resolve(raw.buffer as ArrayBuffer); - } - }); - break; - case "raw": - nativeKey.exportJwk(type, (err, data) => { - if (err) { - reject(err); - } else { - let padSize = 0; - - const crv = (key.algorithm as any).namedCurve; - - switch (crv) { - case "P-256": - case "K-256": - padSize = 32; - break; - case "P-384": - padSize = 48; - break; - case "P-521": - padSize = 66; - break; - default: - throw new Error(`Unsupported named curve '${crv}'`); - } - - const x = Base64Url.decode(Base64Url.encode(buf_pad(data.x, padSize))); - const y = Base64Url.decode(Base64Url.encode(buf_pad(data.y, padSize))); - - const rawKey = new Uint8Array(1 + x.length + y.length); - rawKey.set([4]); - rawKey.set(x, 1); - rawKey.set(y, 1 + x.length); - - resolve(rawKey.buffer as ArrayBuffer); - } - }); - break; - default: - throw new WebCryptoError(`ExportKey: Unknown export format '${format}'`); - } - }); - } - - public static sign(algorithm: EcdsaParams, key: CryptoKey, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.sign(alg, data, (err, signature) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(signature.buffer as ArrayBuffer); - } - }); - }); - } - - public static verify(algorithm: EcdsaParams, key: CryptoKey, signature: Buffer, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.verify(alg, data, signature, (err, res) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(res); - } - }); - }); - } - - public static deriveKey(algorithm: Algorithm, baseKey: CryptoKey, derivedKeyType: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const algDerivedKeyType = derivedKeyType as AesDerivedKeyParams; - const alg = algorithm as EcdhKeyDeriveParams; - - let AesClass: typeof aes.AesCrypto; - switch (algDerivedKeyType.name.toLowerCase()) { - case AlgorithmNames.AesCBC.toLowerCase(): - case AlgorithmNames.AesGCM.toLowerCase(): - case AlgorithmNames.AesKW.toLowerCase(): - AesClass = aes.AesCrypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, algDerivedKeyType.name); - } - - // derive key - (baseKey.native as native.Key).EcdhDeriveKey((alg.public as any).native, algDerivedKeyType.length / 8, (err, raw) => { - if (err) { - reject(err); - } else { - AesClass.importKey("raw", raw, algDerivedKeyType as any, extractable, keyUsages) - .then(resolve, reject); - } - }); - }); - } - - public static deriveBits(algorithm: Algorithm, baseKey: CryptoKey, length: number): PromiseLike { - return new Promise((resolve, reject) => { - const alg = algorithm as EcdhKeyDeriveParams; - const nativeKey = baseKey.native as native.Key; - // derive bits - nativeKey.EcdhDeriveBits((alg.public as any).native, length, (err, raw) => { - if (err) { - reject(err); - } else { - resolve(raw.buffer as ArrayBuffer); - } - }); - }); - } - - public static wc2ssl(algorithm: EcdsaParams) { - const alg = (algorithm.hash as Algorithm).name.toUpperCase().replace("-", ""); - return alg; - } -} diff --git a/lib/crypto/hmac.ts b/lib/crypto/hmac.ts deleted file mode 100644 index dbf9670..0000000 --- a/lib/crypto/hmac.ts +++ /dev/null @@ -1,145 +0,0 @@ -// Core -import * as webcrypto from "webcrypto-core"; -const AlgorithmError = webcrypto.AlgorithmError; -const WebCryptoError = webcrypto.WebCryptoError; -const AlgorithmNames = webcrypto.AlgorithmNames; -const BaseCrypto = webcrypto.BaseCrypto; -const Base64Url = webcrypto.Base64Url; - -// Local -import { CryptoKey } from "../key"; -import * as native from "../native"; - -function b64_decode(b64url: string): Buffer { - return Buffer.from(Base64Url.decode(b64url)); -} - -export class HmacCrypto extends BaseCrypto { - - public static generateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const length = algorithm.length || this.getHashSize((algorithm.hash as Algorithm).name); - native.HmacKey.generate(length, (err, key) => { - if (err) { - reject(err); - } else { - resolve(new CryptoKey(key, algorithm, "secret", extractable, keyUsages)); - } - }); - }); - } - - public static importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const formatLC = format.toLocaleLowerCase(); - let raw: Buffer; - switch (formatLC) { - case "jwk": - raw = b64_decode((keyData as JsonWebKey).k!); - break; - case "raw": - raw = keyData as Buffer; - break; - default: - throw new WebCryptoError(`ImportKey: Wrong format value '${format}'`); - } - native.HmacKey.import(raw, (err, key) => { - if (err) { - reject(err); - } else { - resolve(new CryptoKey(key, algorithm as Algorithm, "secret", extractable, keyUsages)); - } - }); - }); - } - - public static exportKey(format: "jwk", key: CryptoKey): PromiseLike; - public static exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike; - public static exportKey(format: string, key: CryptoKey): PromiseLike; - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return new Promise((resolve, reject) => { - const nativeKey = key.native as native.HmacKey; - switch (format.toLocaleLowerCase()) { - case "jwk": - const jwk: JsonWebKey = { - kty: "oct", - alg: "", - key_ops: key.usages, - k: "", - ext: true, - }; - // set alg - jwk.alg = "HS" + /-(\d+)$/.exec((key.algorithm as any).hash.name)![1]; - nativeKey.export((err, data) => { - if (err) { - reject(err); - } else { - jwk.k = Base64Url.encode(data); - resolve(jwk); - } - }); - break; - case "raw": - nativeKey.export((err, data) => { - if (err) { - reject(err); - } else { - resolve(data.buffer as ArrayBuffer); - } - }); - break; - default: throw new WebCryptoError(`ExportKey: Unknown export format '${format}'`); - } - }); - } - - public static sign(algorithm: EcdsaParams, key: CryptoKey, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.sign(alg, data, (err, signature) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(signature.buffer as ArrayBuffer); - } - }); - }); - } - - public static verify(algorithm: EcdsaParams, key: CryptoKey, signature: Buffer, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.verify(alg, data, signature, (err, res) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(res); - } - }); - }); - } - - public static wc2ssl(algorithm: any) { - const alg = (algorithm.hash as Algorithm).name.toUpperCase().replace("-", ""); - return alg; - } - - protected static getHashSize(hashName: string) { - switch (hashName) { - case AlgorithmNames.Sha1: - return 160; - case AlgorithmNames.Sha256: - return 256; - case AlgorithmNames.Sha384: - return 384; - case AlgorithmNames.Sha512: - return 512; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, hashName); - } - } -} diff --git a/lib/crypto/pbkdf2.ts b/lib/crypto/pbkdf2.ts deleted file mode 100644 index e8cda4c..0000000 --- a/lib/crypto/pbkdf2.ts +++ /dev/null @@ -1,87 +0,0 @@ -// Core -import * as Core from "webcrypto-core"; - -// Local -import { CryptoKey } from "../key"; -import * as native from "../native"; -import { AesCrypto } from "./aes"; -import { HmacCrypto } from "./hmac"; - -function b64_decode(b64url: string): Buffer { - return Buffer.from(Core.Base64Url.decode(b64url)); -} - -export class Pbkdf2Crypto extends Core.BaseCrypto { - - public static importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const formatLC = format.toLocaleLowerCase(); - const alg = algorithm as any; - alg.name = alg.name.toUpperCase(); - let raw: Buffer; - switch (formatLC) { - case "jwk": - raw = b64_decode((keyData as JsonWebKey).k!); - break; - case "raw": - raw = keyData as Buffer; - break; - default: - throw new Core.WebCryptoError(`ImportKey: Wrong format value '${format}'`); - } - alg.length = raw.byteLength * 8; - native.Pbkdf2Key.importKey(raw, (err, key) => { - if (err) { - reject(err); - } else { - resolve(new CryptoKey(key, algorithm as Algorithm, "secret", extractable, keyUsages)); - } - }); - }); - } - - public static deriveKey(algorithm: Algorithm, baseKey: CryptoKey, derivedKeyType: Algorithm, extractable: boolean, keyUsages: string[]) { - return Promise.resolve() - .then(() => { - return this.deriveBits(algorithm, baseKey, (derivedKeyType as any).length); - }) - .then((raw) => { - let CryptoClass: typeof Core.BaseCrypto; - switch (derivedKeyType.name.toUpperCase()) { - case Core.AlgorithmNames.AesCBC: - case Core.AlgorithmNames.AesGCM: - case Core.AlgorithmNames.AesKW: - CryptoClass = AesCrypto; - break; - case Core.AlgorithmNames.Hmac: - CryptoClass = HmacCrypto; - break; - default: - throw new Core.AlgorithmError(Core.AlgorithmError.UNSUPPORTED_ALGORITHM, algorithm.name); - } - return CryptoClass.importKey("raw", Buffer.from(raw), derivedKeyType as any, extractable, keyUsages); - }); - } - - public static deriveBits(algorithm: Algorithm, baseKey: CryptoKey, length: number): PromiseLike { - return new Promise((resolve, reject) => { - const alg = algorithm as Pbkdf2Params; - const nativeKey = baseKey.native as native.Pbkdf2Key; - const hash = Core.PrepareAlgorithm(alg.hash); - const salt = Buffer.from(Core.PrepareData(alg.salt!, "salt")); - // derive bits - nativeKey.deriveBits(this.wc2ssl(hash), salt, alg.iterations, length, (err, raw) => { - if (err) { - reject(err); - } else { - resolve(raw.buffer as ArrayBuffer); - } - }); - }); - } - - public static wc2ssl(algorithm: Algorithm) { - const alg = (algorithm as any).name.toUpperCase().replace("-", ""); - return alg; - } -} diff --git a/lib/crypto/rsa.ts b/lib/crypto/rsa.ts deleted file mode 100644 index cc27340..0000000 --- a/lib/crypto/rsa.ts +++ /dev/null @@ -1,317 +0,0 @@ -// Core -import { Base64Url, BaseCrypto, WebCryptoError } from "webcrypto-core"; - -// Local -import { CryptoKey } from "../key"; -import * as native from "../native"; - -function b64_decode(b64url: string): Buffer { - return Buffer.from(Base64Url.decode(b64url)); -} - -export abstract class RsaCrypto extends BaseCrypto { - - public static generateKey(algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - return new Promise((resolve, reject) => { - const size = algorithm.modulusLength; - const exp = Buffer.from(algorithm.publicExponent); - // convert exp - let nExp: number = 0; - if (exp.length === 3) { - nExp = 1; - } - native.Key.generateRsa(size, nExp, (err, key) => { - try { - if (err) { - reject(new WebCryptoError(`Rsa: Can not generate new key\n${err.message}`)); - } else { - const prvUsages = ["sign", "decrypt", "unwrapKey"] - .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; - const pubUsages = ["verify", "encrypt", "wrapKey"] - .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; - resolve({ - privateKey: new CryptoKey(key, algorithm, "private", extractable, prvUsages), - publicKey: new CryptoKey(key, algorithm, "public", true, pubUsages), - }); - } - } catch (e) { - reject(e); - } - }); - }); - } - - public static importKey(format: string, keyData: JsonWebKey | Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: KeyUsage[]): PromiseLike { - let keyType = native.KeyType.PUBLIC; - const alg: any = algorithm; - return new Promise((resolve, reject) => { - const formatLC = format.toLocaleLowerCase(); - switch (formatLC) { - case "jwk": - const jwk = keyData as JsonWebKey; - const data: { [key: string]: Buffer } = {}; - // prepare data - data["kty"] = jwk.kty as any; - data["n"] = b64_decode(jwk.n!); - data["e"] = b64_decode(jwk.e!); - if (jwk.d) { - keyType = native.KeyType.PRIVATE; - data["d"] = b64_decode(jwk.d!); - data["p"] = b64_decode(jwk.p!); - data["q"] = b64_decode(jwk.q!); - data["dp"] = b64_decode(jwk.dp!); - data["dq"] = b64_decode(jwk.dq!); - data["qi"] = b64_decode(jwk.qi!); - } - native.Key.importJwk(data, keyType, (err, key) => { - try { - if (err) { - reject(new WebCryptoError(`ImportKey: Cannot import key from JWK\n${err}`)); - } else { - resolve(key); - } - } catch (e) { - reject(e); - } - }); - break; - case "pkcs8": - case "spki": - if (!Buffer.isBuffer(keyData)) { - throw new WebCryptoError("ImportKey: keyData is not a Buffer"); - } - let importFunction = native.Key.importSpki; - if (formatLC === "pkcs8") { - keyType = native.KeyType.PRIVATE; - importFunction = native.Key.importPkcs8; - } - importFunction(keyData as Buffer, (err, key) => { - try { - if (err) { - reject(new WebCryptoError(`ImportKey: Can not import key for ${format}\n${err.message}`)); - } else { - resolve(key); - } - } catch (e) { - reject(e); - } - }); - break; - default: - throw new WebCryptoError(`ImportKey: Wrong format value '${format}'`); - } - }) - .then((key: native.Key) => { - alg.modulusLength = key.modulusLength() << 3; - alg.publicExponent = new Uint8Array(key.publicExponent()); - return new CryptoKey(key, alg, keyType ? "private" : "public", extractable, keyUsages); - }); - } - - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return new Promise((resolve, reject) => { - const nativeKey = key.native as native.Key; - const type = key.type === "public" ? native.KeyType.PUBLIC : native.KeyType.PRIVATE; - switch (format.toLocaleLowerCase()) { - case "jwk": - nativeKey.exportJwk(type, (err, data) => { - try { - const jwk: JsonWebKey = { kty: "RSA" }; - jwk.key_ops = key.usages; - - // convert base64 -> base64url for all props - jwk.e = Base64Url.encode(data.e); - jwk.n = Base64Url.encode(data.n); - if (key.type === "private") { - jwk.d = Base64Url.encode(data.d); - jwk.p = Base64Url.encode(data.p); - jwk.q = Base64Url.encode(data.q); - jwk.dp = Base64Url.encode(data.dp); - jwk.dq = Base64Url.encode(data.dq); - jwk.qi = Base64Url.encode(data.qi); - } - resolve(jwk); - } catch (e) { - reject(e); - } - }); - break; - case "spki": - nativeKey.exportSpki((err, raw) => { - if (err) { - reject(err); - } else { - resolve(raw.buffer as ArrayBuffer); - } - }); - break; - case "pkcs8": - nativeKey.exportPkcs8((err, raw) => { - if (err) { - reject(err); - } else { - resolve(raw.buffer as ArrayBuffer); - } - }); - break; - default: - throw new WebCryptoError(`ExportKey: Unknown export format '${format}'`); - } - }); - } - - public static wc2ssl(algorithm: any) { - const alg = algorithm.hash.name.toUpperCase().replace("-", ""); - return alg; - } -} - -export class RsaPKCS1 extends RsaCrypto { - - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return super.exportKey(format, key) - .then((jwk: JsonWebKey) => { - if (format === "jwk") { - const reg = /(\d+)$/; - jwk.alg = "RS" + reg.exec((key.algorithm as any).hash.name)![1]; - jwk.ext = true; - if (key.type === "public") { - jwk.key_ops = ["verify"]; - } - } - return jwk; - }); - } - - public static sign(algorithm: any, key: CryptoKey, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.sign(alg, data, (err, signature) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(signature.buffer as ArrayBuffer); - } - }); - }); - } - - public static verify(algorithm: any, key: CryptoKey, signature: Buffer, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.verify(alg, data, signature, (err, res) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(res); - } - }); - }); - } - -} - -export class RsaPSS extends RsaCrypto { - - public static sign(algorithm: RsaPSS, key: CryptoKey, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.RsaPssSign(alg, (algorithm as any).saltLength, data, (err, signature) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(signature.buffer as ArrayBuffer); - } - }); - }); - } - - public static verify(algorithm: RsaPSS, key: CryptoKey, signature: Buffer, data: Buffer): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - nativeKey.RsaPssVerify(alg, (algorithm as any).saltLength, data, signature, (err, res) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err.message)); - } else { - resolve(res); - } - }); - }); - } - - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return super.exportKey(format, key) - .then((jwk: JsonWebKey) => { - if (format === "jwk") { - const reg = /(\d+)$/; - jwk.alg = "PS" + reg.exec((key.algorithm as any).hash.name)![1]; - jwk.ext = true; - if (key.type === "public") { - jwk.key_ops = ["verify"]; - } - } - return jwk; - }); - } - -} - -export class RsaOAEP extends RsaCrypto { - - public static exportKey(format: string, key: CryptoKey): PromiseLike { - return super.exportKey(format, key) - .then((jwk: JsonWebKey) => { - if (format === "jwk") { - jwk.alg = "RSA-OAEP"; - const mdSize = /(\d+)$/.exec((key.algorithm as any).hash.name)![1]; - if (mdSize !== "1") { - jwk.alg += "-" + mdSize; - } - jwk.ext = true; - if (key.type === "public") { - jwk.key_ops = ["encrypt", "wrapKey"]; - } else { - jwk.key_ops = ["decrypt", "unwrapKey"]; - } - } - return jwk; - }); - } - - public static encrypt(algorithm: RsaOaepParams, key: CryptoKey, data: Buffer): PromiseLike { - return this.EncryptDecrypt(algorithm, key, data, false); - } - - public static decrypt(algorithm: RsaOaepParams, key: CryptoKey, data: Buffer): PromiseLike { - return this.EncryptDecrypt(algorithm, key, data, true); - } - - protected static EncryptDecrypt(algorithm: RsaOaepParams, key: CryptoKey, data: Buffer, type: boolean): PromiseLike { - return new Promise((resolve, reject) => { - const alg = this.wc2ssl(key.algorithm); - const nativeKey = key.native as native.Key; - - let label: Buffer | null = null; - if (algorithm.label) { - label = Buffer.from(algorithm.label as Uint8Array); - } - - nativeKey.RsaOaepEncDec(alg, data, label, type, (err, res) => { - if (err) { - reject(new WebCryptoError("NativeError: " + err)); - } else { - resolve(res.buffer as ArrayBuffer); - } - }); - }); - } - -} diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..6a82d35 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1 @@ +export * from "./crypto"; diff --git a/lib/key.ts b/lib/key.ts deleted file mode 100644 index 0fd984b..0000000 --- a/lib/key.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as native from "./native"; - -export interface CryptoKeyPair extends NativeCryptoKeyPair { - privateKey: CryptoKey; - publicKey: CryptoKey; -} - -export type NativeKey = native.AesKey | native.Key | native.Pbkdf2Key | native.HmacKey; - -export class CryptoKey implements NativeCryptoKey { - public type: KeyType; - public extractable: boolean; - public algorithm: Algorithm; - public usages: KeyUsage[] = []; - - // tslint:disable-next-line:variable-name - private native_: NativeKey; - - get native() { - return this.native_; - } - - constructor(key: NativeKey, alg: Algorithm, type: KeyType, extractable: boolean, keyUsages: KeyUsage[]) { - this.native_ = key; - - this.extractable = extractable; - this.algorithm = alg; - // set key type - this.type = type; - // set key usages - this.usages = keyUsages; - } -} diff --git a/lib/key_storage.ts b/lib/key_storage.ts index 1597495..e74cf03 100644 --- a/lib/key_storage.ts +++ b/lib/key_storage.ts @@ -2,273 +2,140 @@ import * as fs from "fs"; import * as mkdirp from "mkdirp"; import * as path from "path"; +import { Convert } from "pvtsutils"; import * as core from "webcrypto-core"; +import { Crypto } from "./crypto"; -import { CryptoKey } from "./key"; -import * as native from "./native"; - -const JSON_FILE_EXT = ".json"; - -class KeyStorageError extends core.WebCryptoError { } - -export interface IKeyStorageItem extends NativeCryptoKey { - name: string; - keyJwk: any; - file?: string; -} - -function jwkBufferToBase64(jwk: IKeyStorageItem): IKeyStorageItem { - const cpyJwk = jwk.keyJwk as any; - - for (const i in cpyJwk) { - const attr = cpyJwk[i]; - if (Buffer.isBuffer(attr)) { - cpyJwk[i] = attr.toString("base64"); - } - } - - return jwk; -} - -function jwkBase64ToBuffer(jwk: IKeyStorageItem): IKeyStorageItem { - const cpyJwk = jwk.keyJwk as any; - - const reserved = ["kty", "usage", "alg", "crv", "ext", "alg", "name"]; - - for (const i in cpyJwk) { - const attr = cpyJwk[i]; - if (reserved.indexOf(i) === -1 && typeof attr === "string") { - try { - const buf = Buffer.from(attr, "base64"); - cpyJwk[i] = buf; - } catch (e) { - // console.log(e); - } - } - } - - return jwk; +const FILE_EXT = ".jkey"; +export interface IKeyStorageItem extends core.NativeCryptoKey { + jwk: JsonWebKey; } /** * Manage keys in folder - * - * @export - * @class KeyStorage */ -export class KeyStorage { +export class CryptoKeyStorage implements core.CryptoKeyStorage { - protected directory: string = ""; - protected keys: { [key: string]: IKeyStorageItem } = {}; - - /** - * Creates an instance of KeyStorage. - * - * @param {string} directory Path to directory - */ - constructor(directory: string) { - this.directory = directory; - - if (!fs.existsSync(directory)) { - this.createDirectory(directory); - } + public directory = ""; + public crypto: Crypto; + private items = new WeakMap(); - this.readDirectory(); + public constructor(crypto: Crypto, directory: string) { + this.crypto = crypto; + this.directory = path.normalize(directory); + if (!fs.existsSync(this.directory)) { + mkdirp.sync(this.directory); } - - /** - * Clears KeyStorage - * - be careful, removes all files from selected directory - */ - public clear(): void { - if (!this.directory) { - return; - } - this.keys = {}; // clear keys - const items = fs.readdirSync(this.directory); - items.forEach((item) => { - if (item !== "." && item !== "..") { - const file = path.join(this.directory, item); - const stat = fs.statSync(file); - if (stat.isFile) { - fs.unlinkSync(file); - } - } - }); + } + + public getItem(index: string): Promise; + public getItem(index: string, algorithm: core.ImportAlgorithms, extractable: boolean, keyUsages: KeyUsage[]): Promise; + public async getItem(index: any, algorithm?: any, extractable?: any, keyUsages?: any) { + const fileKey = this.readFile(this.getFilePath(index)); + if (!fileKey) { + throw new core.OperationError("Cannot get key form file"); } - - /** - * Returns a CryptoKey from storage by name - * - * @param {string} key Name of - * @returns {CryptoKey} - */ - public getItem(key: string): CryptoKey | null { - let item = this.getItemById(key); - if (!item) { - return null; + return this.crypto.subtle.importKey( + "jwk", + fileKey.jwk, + algorithm ?? fileKey.algorithm, + extractable ?? fileKey.extractable, + keyUsages ?? fileKey.usages); + } + + public async keys(): Promise { + const items = fs.readdirSync(this.directory); + const res: string[] = []; + items.forEach((item) => { + if (item !== "." && item !== "..") { + const file = path.join(this.directory, item); + const stat = fs.statSync(file); + if (stat.isFile()) { + const key = this.readFile(file); + if (key) { + res.push(path.parse(item).name); + } } - - item = jwkBase64ToBuffer(item); - let res: CryptoKey; - let nativeKey: native.Key; - switch (item.type.toLowerCase()) { - case "public": - nativeKey = native.Key.importJwk(item.keyJwk, native.KeyType.PUBLIC); - break; - case "private": - nativeKey = native.Key.importJwk(item.keyJwk, native.KeyType.PRIVATE); - break; - case "secret": - throw new Error("Not implemented yet"); - default: - throw new Error(`Unknown type '${item.type}'`); - } - res = new CryptoKey(nativeKey, item.algorithm as any, item.type, item.extractable, item.usages); - return res; + } + }); + return res; + } + + public async indexOf(item: globalThis.CryptoKey): Promise { + return this.items.get(item) || null; + } + + public async setItem(item: globalThis.CryptoKey): Promise { + const subtle = this.crypto.subtle as any; + const provider = subtle.getProvider(item.algorithm.name) as core.ProviderCrypto; + const jwk = await provider.onExportKey("jwk", item) as JsonWebKey; + const keyAlgorithm = item.algorithm as any; + const algorithm: any = { name: keyAlgorithm.name }; + if (keyAlgorithm.hash) { + // RSA keys + algorithm.hash = keyAlgorithm.hash; } - - public key(index: number): string { - throw new Error("Not implemented yet"); + const id = Convert.ToHex(this.crypto.getRandomValues(new Uint8Array(10))); + this.writeFile( + id, + { + algorithm, + extractable: item.extractable, + usages: item.usages, + type: item.type, + jwk, + }); + + // add to weak map + this.items.set(item, id); + + return id; + } + + public async hasItem(item: globalThis.CryptoKey): Promise { + return this.items.has(item); + } + + public async clear(): Promise { + const keys = await this.keys(); + for (const key of keys) { + this.removeItem(key); } + } - /** - * Removes key from Storage - * - * @param {string} key Name of key in Storage - */ - public removeItem(key: string): void { - const item = this.getItemById(key); - if (item) { - this.removeFile(item); - delete this.keys[key]; - } - } - - public setItem(key: string, data: CryptoKey): void { - const nativeKey = (data as CryptoKey).native; - let jwk: any = null; - switch (data.type.toLowerCase()) { - case "public": - jwk = (nativeKey as native.Key).exportJwk(native.KeyType.PUBLIC); - break; - case "private": - jwk = (nativeKey as native.Key).exportJwk(native.KeyType.PRIVATE); - break; - case "secret": - throw new Error("Not implemented yet"); - default: - throw new Error(`Unsupported key type '${data.type}'`); - } - if (jwk) { - let item: IKeyStorageItem = { - algorithm: data.algorithm, - usages: data.usages, - type: data.type, - keyJwk: jwk, - name: key, - extractable: data.extractable, - }; - item = jwkBufferToBase64(item); - this.saveFile(item); - this.keys[key] = item; - } - } - - protected createDirectory(directory: string, flags?: any) { - mkdirp.sync(directory, flags); - } - - /** - * Read JWK file. - * If file doesn't have IKeyStorageItem data returns Null - * - * @protected - * @param {string} file Path to file - * @returns {IKeyStorageItem} - */ - protected readFile(file: string): IKeyStorageItem | null { - if (!fs.existsSync(file)) { - throw new KeyStorageError(`File '${file}' is not exists`); - } - const fText = fs.readFileSync(file, "utf8"); - let json: IKeyStorageItem; - try { - json = JSON.parse(fText); - } catch (e) { - return null; - } - // Add info about file - json.file = file; - - // check JSON structure - if (json.algorithm && json.type && json.usages && json.name) { - return json; - } - return null; - } - - /** - * Read all files from folder and push Keys to internal field "keys" - * - * @protected - */ - protected readDirectory() { - if (!this.directory) { - throw new KeyStorageError("KeyStorage directory is not set"); - } - this.keys = {}; // clear keys - const items = fs.readdirSync(this.directory); - items.forEach((item) => { - if (item !== "." && item !== "..") { - const file = path.join(this.directory, item); - const stat = fs.statSync(file); - if (stat.isFile) { - const key = this.readFile(file); - if (key) { - this.keys[key.name] = key; - } - } - } - }); - } - - /** - * Save file to directory - * - * @protected - * @param {IKeyStorageItem} key - */ - protected saveFile(key: IKeyStorageItem) { - const json = JSON.stringify(key); - fs.writeFileSync(path.join(this.directory, key.name + JSON_FILE_EXT), json, { - encoding: "utf8", - flag: "w", - }); + public async removeItem(index: string): Promise { + const fileName = this.getFilePath(index); + const keyFile = this.readFile(fileName); + if (keyFile) { + fs.unlinkSync(fileName); } - - protected removeFile(key: IKeyStorageItem) { - let file = key.file; - if (!file) { - file = path.join(this.directory, key.name + JSON_FILE_EXT); - } - if (fs.existsSync(file)) { - fs.unlinkSync(file); - } + } + + private readFile(file: string) { + const json = fs.readFileSync(file, "utf8"); + let parsedJson: IKeyStorageItem; + try { + parsedJson = JSON.parse(json); + } catch (e) { + return null; } - /** - * Returns amount fo key in storage - * - * @readonly - * @type {number} - */ - get length(): number { - return Object.keys(this.keys).length; + // check JSON structure + if (parsedJson.algorithm && parsedJson.type && parsedJson.usages && parsedJson.jwk) { + return parsedJson; } - - protected getItemById(id: string): IKeyStorageItem { - return this.keys[id] || null; - } - + return null; + } + + private writeFile(name: string, key: IKeyStorageItem) { + const json = JSON.stringify(key); + fs.writeFileSync(this.getFilePath(name), json, { + encoding: "utf8", + flag: "w", + }); + } + + private getFilePath(name: string): string { + return path.join(this.directory, `${name}${FILE_EXT}`); + } } diff --git a/lib/keys/asymmetric.ts b/lib/keys/asymmetric.ts new file mode 100644 index 0000000..ec9757e --- /dev/null +++ b/lib/keys/asymmetric.ts @@ -0,0 +1,6 @@ +import { CryptoKey } from "./key"; + +export abstract class AsymmetricKey extends CryptoKey { + + public abstract type: "public" | "private"; +} diff --git a/lib/keys/index.ts b/lib/keys/index.ts new file mode 100644 index 0000000..b91fca9 --- /dev/null +++ b/lib/keys/index.ts @@ -0,0 +1,4 @@ +export * from "./key"; +export * from "./symmetric"; +export * from "./asymmetric"; +export * from "./storage"; diff --git a/lib/keys/key.ts b/lib/keys/key.ts new file mode 100644 index 0000000..b162263 --- /dev/null +++ b/lib/keys/key.ts @@ -0,0 +1,13 @@ +import * as core from "webcrypto-core"; + +export class CryptoKey extends core.CryptoKey { + public native: any; + + public algorithm: KeyAlgorithm = { name: "" }; + + public extractable = false; + + public type: KeyType = "secret"; + + public usages: KeyUsage[] = []; +} diff --git a/lib/keys/storage.ts b/lib/keys/storage.ts new file mode 100644 index 0000000..b2d30b6 --- /dev/null +++ b/lib/keys/storage.ts @@ -0,0 +1,23 @@ +import * as core from "webcrypto-core"; +import { CryptoKey as InternalCryptoKey } from "./key"; + +const keyStorage = new WeakMap(); + +export class CryptoKeyStorage { + public static getItem(key: core.CryptoKey) { + const res = keyStorage.get(key); + if (!res) { + throw new core.OperationError("Cannot get CryptoKey from secure storage"); + } + return res; + } + + public static setItem(value: InternalCryptoKey) { + const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages); + Object.freeze(key); + + keyStorage.set(key, value); + + return key; + } +} diff --git a/lib/keys/symmetric.ts b/lib/keys/symmetric.ts new file mode 100644 index 0000000..8025df1 --- /dev/null +++ b/lib/keys/symmetric.ts @@ -0,0 +1,5 @@ +import { CryptoKey } from "./key"; + +export class SymmetricKey extends CryptoKey { + public readonly type: "secret" = "secret"; +} diff --git a/lib/mechs/aes/aes_cbc.ts b/lib/mechs/aes/aes_cbc.ts new file mode 100644 index 0000000..b7d6cc7 --- /dev/null +++ b/lib/mechs/aes/aes_cbc.ts @@ -0,0 +1,61 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import type { AesKey } from "../../native"; +import { AesCrypto } from "./crypto"; +import { AesCryptoKey } from "./key"; + +export class AesCbcProvider extends core.AesCbcProvider { + + public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await AesCrypto.generateKey( + { + name: this.name, + length: algorithm.length, + }, + extractable, + keyUsages); + + return CryptoKeyStorage.setItem(key); + } + + public async onEncrypt(algorithm: AesCbcParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, true); + } + + public async onDecrypt(algorithm: AesCbcParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, false); + } + + public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { + return AesCrypto.exportKey(format, CryptoKeyStorage.getItem(key) as AesCryptoKey); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const res = await AesCrypto.importKey(format, keyData, { name: this.name }, extractable, keyUsages); + return CryptoKeyStorage.setItem(res); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + AesCrypto.checkCryptoKey(key); + } + + private async internalEncrypt(algorithm: AesCbcParams, key: AesCryptoKey, data: ArrayBuffer, encrypt: boolean): Promise { + return new Promise((resolve, reject) => { + const aesKey = CryptoKeyStorage.getItem(key).native as AesKey; + const iv = Buffer.from(core.BufferSourceConverter.toArrayBuffer(algorithm.iv)); + + const func: typeof aesKey.encrypt = encrypt + ? aesKey.encrypt.bind(aesKey) + : aesKey.decrypt.bind(aesKey); + const buf = Buffer.from(data); + func("CBC", iv, buf, (err, data2) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data2.buffer)); + } + }); + }); + } +} diff --git a/lib/mechs/aes/aes_cmac.ts b/lib/mechs/aes/aes_cmac.ts new file mode 100644 index 0000000..9d9d3c3 --- /dev/null +++ b/lib/mechs/aes/aes_cmac.ts @@ -0,0 +1,152 @@ +import * as crypto from "crypto"; +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import { AesCrypto } from "./crypto"; +import { AesCryptoKey } from "./key"; + +/** + * AES-CMAC implementation source code from https://github.com/allan-stewart/node-aes-cmac + */ + +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: 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: Buffer, b: Buffer) { + 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: Buffer, message: Buffer) { + const cipher = crypto.createCipheriv(`aes${key.length << 3}`, key, zero); + const result = cipher.update(message); + cipher.final(); + return result; +} + +function getMessageBlock(message: Buffer, blockIndex: number) { + const block = Buffer.alloc(blockSize); + const start = blockIndex * blockSize; + const end = start + blockSize; + + message.copy(block, 0, start, end); + + return block; +} + +function getPaddedMessageBlock(message: Buffer, blockIndex: number) { + 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: Buffer) { + 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: Buffer, message: Buffer) { + const subkeys = generateSubkeys(key); + let blockCount = Math.ceil(message.length / blockSize); + let lastBlockCompleteFlag: boolean; + let lastBlock: Buffer; + + 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); +} + +export class AesCmacProvider extends core.AesCmacProvider { + + public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await AesCrypto.generateKey( + { + name: this.name, + length: algorithm.length, + }, + extractable, + keyUsages); + + return CryptoKeyStorage.setItem(key); + } + + public async onSign(algorithm: AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + const raw = await this.onExportKey("raw", key); + const result = aesCmac(Buffer.from(raw), Buffer.from(data)); + return new Uint8Array(result).buffer; + } + + public async onVerify(algorithm: AesCmacParams, key: AesCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { + const signature2 = await this.sign(algorithm, key, data); + return Buffer.from(signature).compare(Buffer.from(signature2)) === 0; + } + + public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { + return AesCrypto.exportKey(format, CryptoKeyStorage.getItem(key) as AesCryptoKey); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const res = await AesCrypto.importKey(format, keyData, { name: this.name }, extractable, keyUsages); + return CryptoKeyStorage.setItem(res); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + AesCrypto.checkCryptoKey(key); + } +} diff --git a/lib/mechs/aes/aes_ctr.ts b/lib/mechs/aes/aes_ctr.ts new file mode 100644 index 0000000..27c89ce --- /dev/null +++ b/lib/mechs/aes/aes_ctr.ts @@ -0,0 +1,60 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import type { AesKey } from "../../native"; +import { AesCrypto } from "./crypto"; +import { AesCryptoKey } from "./key"; + +export class AesCtrProvider extends core.AesCtrProvider { + + public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await AesCrypto.generateKey( + { + name: this.name, + length: algorithm.length, + }, + extractable, + keyUsages); + + return CryptoKeyStorage.setItem(key); + } + + public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, true); + } + + public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, false); + } + + public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { + return AesCrypto.exportKey(format, CryptoKeyStorage.getItem(key) as AesCryptoKey); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const res = await AesCrypto.importKey(format, keyData, { name: this.name }, extractable, keyUsages); + return CryptoKeyStorage.setItem(res); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + AesCrypto.checkCryptoKey(key); + } + + private async internalEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer, encrypt: boolean): Promise { + return new Promise((resolve, reject) => { + const aesKey = CryptoKeyStorage.getItem(key).native as AesKey; + const counter = Buffer.from(core.BufferSourceConverter.toArrayBuffer(algorithm.counter)); + + const func: typeof aesKey.encryptCtr = encrypt + ? aesKey.encryptCtr.bind(aesKey) + : aesKey.decryptCtr.bind(aesKey); + func(Buffer.from(data), counter, algorithm.length, (err, data2) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data2.buffer)); + } + }); + }); + } +} diff --git a/lib/mechs/aes/aes_ecb.ts b/lib/mechs/aes/aes_ecb.ts new file mode 100644 index 0000000..32691da --- /dev/null +++ b/lib/mechs/aes/aes_ecb.ts @@ -0,0 +1,59 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import type { AesKey } from "../../native"; +import { AesCrypto } from "./crypto"; +import { AesCryptoKey } from "./key"; + +export class AesEcbProvider extends core.AesEcbProvider { + + public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await AesCrypto.generateKey( + { + name: this.name, + length: algorithm.length, + }, + extractable, + keyUsages); + + return CryptoKeyStorage.setItem(key); + } + + public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, true); + } + + public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, false); + } + + public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { + return AesCrypto.exportKey(format, CryptoKeyStorage.getItem(key) as AesCryptoKey); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const res = await AesCrypto.importKey(format, keyData, { name: this.name }, extractable, keyUsages); + return CryptoKeyStorage.setItem(res); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + AesCrypto.checkCryptoKey(key); + } + + private async internalEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer, encrypt: boolean): Promise { + return new Promise((resolve, reject) => { + const aesKey = CryptoKeyStorage.getItem(key).native as AesKey; + + const func: typeof aesKey.encryptEcb = encrypt + ? aesKey.encryptEcb.bind(aesKey) + : aesKey.decryptEcb.bind(aesKey); + func(Buffer.from(data), (err, data2) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data2.buffer)); + } + }); + }); + } +} diff --git a/lib/mechs/aes/aes_gcm.ts b/lib/mechs/aes/aes_gcm.ts new file mode 100644 index 0000000..ea26af7 --- /dev/null +++ b/lib/mechs/aes/aes_gcm.ts @@ -0,0 +1,62 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import type { AesKey } from "../../native"; +import { AesCrypto } from "./crypto"; +import { AesCryptoKey } from "./key"; + +export class AesGcmProvider extends core.AesGcmProvider { + + public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await AesCrypto.generateKey( + { + name: this.name, + length: algorithm.length, + }, + extractable, + keyUsages); + + return CryptoKeyStorage.setItem(key); + } + + public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, true); + } + + public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, false); + } + + public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { + return AesCrypto.exportKey(format, CryptoKeyStorage.getItem(key) as AesCryptoKey); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const res = await AesCrypto.importKey(format, keyData, { name: this.name }, extractable, keyUsages); + return CryptoKeyStorage.setItem(res); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + AesCrypto.checkCryptoKey(key); + } + + private async internalEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer, encrypt: boolean): Promise { + return new Promise((resolve, reject) => { + const aesKey = CryptoKeyStorage.getItem(key).native as AesKey; + const iv = Buffer.from(core.BufferSourceConverter.toArrayBuffer(algorithm.iv)); + const aad = algorithm.additionalData ? Buffer.from(algorithm.additionalData as Uint8Array) : Buffer.alloc(0); + const tagLength = algorithm.tagLength || 128; + + const func: typeof aesKey.encryptGcm = encrypt + ? aesKey.encryptGcm.bind(aesKey) + : aesKey.decryptGcm.bind(aesKey); + func(iv, Buffer.from(data), aad || Buffer.alloc(0), tagLength >> 3, (err, data2) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data2.buffer)); + } + }); + }); + } +} diff --git a/lib/mechs/aes/aes_kw.ts b/lib/mechs/aes/aes_kw.ts new file mode 100644 index 0000000..35f021c --- /dev/null +++ b/lib/mechs/aes/aes_kw.ts @@ -0,0 +1,60 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import type { AesKey } from "../../native"; +import { AesCrypto } from "./crypto"; +import { AesCryptoKey } from "./key"; + +export class AesKwProvider extends core.AesKwProvider { + + public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await AesCrypto.generateKey( + { + name: this.name, + length: algorithm.length, + }, + extractable, + keyUsages); + + return CryptoKeyStorage.setItem(key); + } + + public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, true); + } + + public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, data, false); + } + + public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { + return AesCrypto.exportKey(format, CryptoKeyStorage.getItem(key) as AesCryptoKey); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const res = await AesCrypto.importKey(format, keyData, { name: this.name }, extractable, keyUsages); + return CryptoKeyStorage.setItem(res); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + AesCrypto.checkCryptoKey(key); + } + + private async internalEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer, encrypt: boolean): Promise { + return new Promise((resolve, reject) => { + const aesKey = CryptoKeyStorage.getItem(key).native as AesKey; + + const func: typeof aesKey.wrapKey = encrypt + ? aesKey.wrapKey.bind(aesKey) + : aesKey.unwrapKey.bind(aesKey); + + func(Buffer.from(data), (err: Error, data2: Buffer) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data2)); + } + }); + }); + } +} diff --git a/lib/mechs/aes/crypto.ts b/lib/mechs/aes/crypto.ts new file mode 100644 index 0000000..efc1d02 --- /dev/null +++ b/lib/mechs/aes/crypto.ts @@ -0,0 +1,104 @@ +import { Convert } from "pvtsutils"; +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { AesCryptoKey } from "./key"; + +export class AesCrypto { + + public static generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + native.AesKey.generate(algorithm.length / 8, (err, key) => { + if (err) { + reject(err); + } else { + const secret = AesCryptoKey.create(algorithm, "secret", extractable, keyUsages); + secret.native = key; + resolve(secret); + } + }); + }); + } + + public static exportKey(format: string, key: AesCryptoKey): Promise { + return new Promise((resolve, reject) => { + const nativeKey = key.native as native.AesKey; + switch (format.toLocaleLowerCase()) { + case "jwk": + const jwk: JsonWebKey = { + kty: "oct", + alg: "", + key_ops: key.usages, + k: "", + ext: true, + }; + // set alg + jwk.alg = `A${key.algorithm.length}${/-(\w+)$/.exec(key.algorithm.name)![1].toUpperCase()}`; + nativeKey.export((err, data) => { + if (err) { + reject(err); + } else { + jwk.k = Convert.ToBase64Url(data); + resolve(jwk); + } + }); + break; + case "raw": + nativeKey.export((err, data) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data)); + } + }); + break; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + }); + } + + public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + const formatLC = format.toLocaleLowerCase(); + let raw: ArrayBuffer; + switch (formatLC) { + case "jwk": + raw = Convert.FromBase64Url((keyData as JsonWebKey).k!); + break; + case "raw": + raw = keyData as ArrayBuffer; + break; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + + // check key length + const keyLengthBits = raw.byteLength << 3; + switch (keyLengthBits) { + case 128: + case 192: + case 256: + break; + default: + throw new core.OperationError("keyData: Is wrong key length"); + } + + native.AesKey.import(Buffer.from(raw), (err, key) => { + if (err) { + reject(err); + } else { + const secret = AesCryptoKey.create({ ...algorithm, length: keyLengthBits }, "secret", extractable, keyUsages); + secret.native = key; + resolve(secret); + } + }); + }); + } + + public static checkCryptoKey(key: core.NativeCryptoKey): asserts key is AesCryptoKey { + if (!(CryptoKeyStorage.getItem(key) instanceof AesCryptoKey)) { + throw new TypeError("key: Is not a AesCryptoKey"); + } + } +} diff --git a/lib/mechs/aes/index.ts b/lib/mechs/aes/index.ts new file mode 100644 index 0000000..1d3f279 --- /dev/null +++ b/lib/mechs/aes/index.ts @@ -0,0 +1,7 @@ +export * from "./key"; +export * from "./aes_cbc"; +export * from "./aes_cmac"; +export * from "./aes_ctr"; +export * from "./aes_gcm"; +export * from "./aes_kw"; +export * from "./aes_ecb"; diff --git a/lib/mechs/aes/key.ts b/lib/mechs/aes/key.ts new file mode 100644 index 0000000..ba5ff0c --- /dev/null +++ b/lib/mechs/aes/key.ts @@ -0,0 +1,5 @@ +import { SymmetricKey } from "../../keys"; + +export class AesCryptoKey extends SymmetricKey { + public algorithm!: AesKeyAlgorithm; +} diff --git a/lib/mechs/des/crypto.ts b/lib/mechs/des/crypto.ts new file mode 100644 index 0000000..573149f --- /dev/null +++ b/lib/mechs/des/crypto.ts @@ -0,0 +1,86 @@ +import * as crypto from "crypto"; +import { Convert } from "pvtsutils"; +import * as core from "webcrypto-core"; +import { DesParams } from "webcrypto-core"; +import { CryptoKey, CryptoKeyStorage } from "../../keys"; +import { DesCryptoKey } from "./key"; + +export class DesCrypto { + + public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = DesCryptoKey.create({ + ...algorithm, + name: algorithm.name.toUpperCase(), + }, + "secret", + extractable, + keyUsages); + key.native = crypto.randomBytes(algorithm.length >> 3); + + return key; + } + + public static async exportKey(format: string, key: CryptoKey): Promise { + const desKey = CryptoKeyStorage.getItem(key) as DesCryptoKey; + switch (format.toLowerCase()) { + case "jwk": + return desKey.toJSON(); + case "raw": + return new Uint8Array(desKey.native).buffer; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + } + + public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]) { + let raw: ArrayBuffer; + switch (format.toLowerCase()) { + case "jwk": + const jwk = keyData as JsonWebKey; + raw = Convert.FromBase64Url(jwk.k!); + break; + case "raw": + raw = keyData as ArrayBuffer; + break; + default: + throw new core.OperationError("format: Must be 'jwk' or 'raw'"); + } + + const desKey = DesCryptoKey.create(algorithm, "secret", extractable, keyUsages); + desKey.algorithm.length = raw.byteLength >> 3; + desKey.native = Buffer.from(raw); + + return desKey; + } + + public static async encrypt(algorithm: DesParams, key: DesCryptoKey, data: Uint8Array): Promise { + switch (algorithm.name.toUpperCase()) { + case "DES-CBC": + case "DES-EDE3-CBC": + return this.internalEncrypt(algorithm, key, Buffer.from(data), true); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + + public static async decrypt(algorithm: DesParams, key: DesCryptoKey, data: Uint8Array): Promise { + switch (algorithm.name.toUpperCase()) { + case "DES-CBC": + case "DES-EDE3-CBC": + return this.internalEncrypt(algorithm, key, Buffer.from(data), false); + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + + public static async internalEncrypt(algorithm: DesParams, key: DesCryptoKey, data: Buffer, encrypt: boolean) { + const func = encrypt + ? crypto.createCipheriv + : crypto.createDecipheriv; + const decipher = func.call(crypto, algorithm.name.toLowerCase(), key.native, core.BufferSourceConverter.toUint8Array(algorithm.iv)); + let resMessage = decipher.update(data); + resMessage = Buffer.concat([resMessage, decipher.final()]); + return new Uint8Array(resMessage).buffer; + } + +} diff --git a/lib/mechs/des/des_cbc.ts b/lib/mechs/des/des_cbc.ts new file mode 100644 index 0000000..6318020 --- /dev/null +++ b/lib/mechs/des/des_cbc.ts @@ -0,0 +1,55 @@ +import * as core from "webcrypto-core"; +import { CryptoKey, CryptoKeyStorage } from "../../keys"; +import { DesCrypto } from "./crypto"; +import { DesCryptoKey } from "./key"; + +export type DesCbcParams = core.DesParams; + +export class DesCbcProvider extends core.DesProvider { + + public keySizeBits = 64; + public ivSize = 8; + public name = "DES-CBC"; + + public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await DesCrypto.generateKey( + { + name: this.name, + length: this.keySizeBits, + }, + extractable, + keyUsages); + + return key; + } + + public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { + const desKey = CryptoKeyStorage.getItem(key) as DesCryptoKey; + return DesCrypto.encrypt(algorithm, desKey, new Uint8Array(data)); + } + + public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { + const desKey = CryptoKeyStorage.getItem(key) as DesCryptoKey; + return DesCrypto.decrypt(algorithm, desKey, new Uint8Array(data)); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return DesCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages); + if (key.native.length !== (this.keySizeBits >> 3)) { + throw new core.OperationError("keyData: Wrong key size"); + } + return CryptoKeyStorage.setItem(key); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(CryptoKeyStorage.getItem(key) instanceof DesCryptoKey)) { + throw new TypeError("key: Is not a DES CryptoKey"); + } + } + +} diff --git a/lib/mechs/des/des_ede3_cbc.ts b/lib/mechs/des/des_ede3_cbc.ts new file mode 100644 index 0000000..c92cabd --- /dev/null +++ b/lib/mechs/des/des_ede3_cbc.ts @@ -0,0 +1,55 @@ +import * as core from "webcrypto-core"; +import { CryptoKey, CryptoKeyStorage } from "../../keys"; +import { DesCrypto } from "./crypto"; +import { DesCryptoKey } from "./key"; + +export type DesEde3CbcParams = core.DesParams; + +export class DesEde3CbcProvider extends core.DesProvider { + + public keySizeBits = 192; + public ivSize = 8; + public name = "DES-EDE3-CBC"; + + public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await DesCrypto.generateKey( + { + name: this.name, + length: this.keySizeBits, + }, + extractable, + keyUsages); + + return key; + } + + public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { + const desKey = CryptoKeyStorage.getItem(key) as DesCryptoKey; + return DesCrypto.encrypt(algorithm, desKey, new Uint8Array(data)); + } + + public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { + const desKey = CryptoKeyStorage.getItem(key) as DesCryptoKey; + return DesCrypto.decrypt(algorithm, desKey, new Uint8Array(data)); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return DesCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages); + if (key.native.length !== (this.keySizeBits >> 3)) { + throw new core.OperationError("keyData: Wrong key size"); + } + return CryptoKeyStorage.setItem(key); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(CryptoKeyStorage.getItem(key) instanceof DesCryptoKey)) { + throw new TypeError("key: Is not a DES CryptoKey"); + } + } + +} diff --git a/lib/mechs/des/index.ts b/lib/mechs/des/index.ts new file mode 100644 index 0000000..3350609 --- /dev/null +++ b/lib/mechs/des/index.ts @@ -0,0 +1,3 @@ +export * from "./key"; +export * from "./des_cbc"; +export * from "./des_ede3_cbc"; diff --git a/lib/mechs/des/key.ts b/lib/mechs/des/key.ts new file mode 100644 index 0000000..1353574 --- /dev/null +++ b/lib/mechs/des/key.ts @@ -0,0 +1,19 @@ +import { Convert } from "pvtsutils"; +import * as core from "webcrypto-core"; +import { SymmetricKey } from "../../keys"; + +export class DesCryptoKey extends SymmetricKey { + public algorithm!: core.DesKeyAlgorithm; + + public toJSON() { + return { + kty: "oct", + alg: this.algorithm.name === "DES-CBC" + ? this.algorithm.name + : "3DES-CBC", + ext: true, + k: Convert.ToBase64Url(this.native), + key_ops: this.usages, + }; + } +} diff --git a/lib/mechs/ec/crypto.ts b/lib/mechs/ec/crypto.ts new file mode 100644 index 0000000..727b6af --- /dev/null +++ b/lib/mechs/ec/crypto.ts @@ -0,0 +1,280 @@ +import { Convert } from "pvtsutils"; +import * as core from "webcrypto-core"; +import { CryptoKey, CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { EcPrivateKey } from "./private_key"; +import { EcPublicKey } from "./public_key"; + +function buf_pad(buf: Buffer, padSize: number = 0) { + if (padSize && Buffer.length < padSize) { + const pad = Buffer.from(new Uint8Array(padSize - buf.length).map((v) => 0)); + return Buffer.concat([pad, buf]); + } + return buf; +} + +export class EcCrypto { + + public static publicKeyUsages = ["verify"]; + public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"]; + + public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + const alg = algorithm as EcKeyGenParams; + const namedCurve = this.getNamedCurve(alg.namedCurve); + + native.Key.generateEc(namedCurve, (err, key) => { + if (err) { + reject(err); + } else { + const prvUsages = ["sign", "deriveKey", "deriveBits"] + .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; + const pubUsages = ["verify"] + .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; + const privateKey = EcPrivateKey.create(algorithm, "private", extractable, prvUsages); + const publicKey = EcPublicKey.create(algorithm, "public", true, pubUsages); + publicKey.native = privateKey.native = key; + resolve({ + privateKey: CryptoKeyStorage.setItem(privateKey), + publicKey: CryptoKeyStorage.setItem(publicKey), + }); + } + }); + }); + } + + public static async exportKey(format: KeyFormat, key: core.NativeCryptoKey): Promise { + return new Promise((resolve, reject) => { + const nativeKey = CryptoKeyStorage.getItem(key).native as native.Key; + const type = key.type === "public" ? native.KeyType.PUBLIC : native.KeyType.PRIVATE; + switch (format.toLocaleLowerCase()) { + case "jwk": + nativeKey.exportJwk(type, (err, data) => { + if (err) { + throw new core.CryptoError(`Cannot export JWK key\n${err}`); + } + try { + const jwk: JsonWebKey = { kty: "EC", ext: true }; + jwk.crv = (key.algorithm as EcKeyAlgorithm).namedCurve; + jwk.key_ops = key.usages; + let padSize = 0; + switch (jwk.crv) { + case "P-256": + case "K-256": + padSize = 32; + break; + case "P-384": + padSize = 48; + break; + case "P-521": + padSize = 66; + break; + default: + throw new Error(`Unsupported named curve '${jwk.crv}'`); + } + jwk.x = Convert.ToBase64Url(buf_pad(data.x, padSize)); + jwk.y = Convert.ToBase64Url(buf_pad(data.y, padSize)); + if (key.type === "private") { + jwk.d = Convert.ToBase64Url(buf_pad(data.d, padSize)); + } + resolve(jwk); + } catch (e) { + reject(e); + } + }); + break; + case "spki": + nativeKey.exportSpki((err, raw) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(raw)); + } + }); + break; + case "pkcs8": + nativeKey.exportPkcs8((err, raw) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(raw)); + } + }); + break; + case "raw": + nativeKey.exportJwk(type, (err, data) => { + if (err) { + reject(err); + } else { + let padSize = 0; + + const crv = (key.algorithm as any).namedCurve; + + switch (crv) { + case "P-256": + case "K-256": + padSize = 32; + break; + case "P-384": + padSize = 48; + break; + case "P-521": + padSize = 66; + break; + default: + throw new Error(`Unsupported named curve '${crv}'`); + } + + const x = buf_pad(data.x, padSize); + const y = buf_pad(data.y, padSize); + + const rawKey = new Uint8Array(1 + x.length + y.length); + rawKey.set([4]); + rawKey.set(x, 1); + rawKey.set(y, 1 + x.length); + + resolve(core.BufferSourceConverter.toArrayBuffer(rawKey)); + } + }); + break; + default: + throw new core.CryptoError(`ExportKey: Unknown export format '${format}'`); + } + }); + } + + public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + const formatLC = format.toLocaleLowerCase(); + const data: { [key: string]: Buffer } = {}; + let keyType = native.KeyType.PUBLIC; + switch (formatLC) { + case "raw": { + let keyLength = 0; + const rawData = Buffer.from(keyData); + + if (rawData.byteLength === 65) { + // P-256 + // Key length 32 Byte + keyLength = 32; + } else if (rawData.byteLength === 97) { + // P-384 + // Key length 48 Byte + keyLength = 48; + } else if (rawData.byteLength === 133) { + // P-521 + // Key length: 521/= 65,125 => 66 Byte + keyLength = 66; + } + + const x = Buffer.from(rawData).slice(1, keyLength + 1); + + const y = Buffer.from(rawData).slice(keyLength + 1, (keyLength * 2) + 1); + + data["kty"] = Buffer.from("EC", "utf-8"); + data["crv"] = this.getNamedCurve(algorithm.namedCurve.toUpperCase()); + data["x"] = buf_pad(x, keyLength); + data["y"] = buf_pad(y, keyLength); + + native.Key.importJwk(data, keyType, (err, key) => { + try { + if (err) { + reject(new core.CryptoError(`ImportKey: Cannot import key from JWK\n${err}`)); + } else { + const ecKey = EcPublicKey.create(algorithm, "public", extractable, keyUsages); + ecKey.native = key; + resolve(CryptoKeyStorage.setItem(ecKey)); + } + } catch (e) { + reject(e); + } + }); + + break; + } + case "jwk": { + const jwk = keyData as JsonWebKey; + // prepare data + data["kty"] = jwk.kty as any; + data["crv"] = this.getNamedCurve(jwk.crv!); + data["x"] = Buffer.from(Convert.FromBase64Url(jwk.x!)); + data["y"] = Buffer.from(Convert.FromBase64Url(jwk.y!)); + if (jwk.d) { + keyType = native.KeyType.PRIVATE; + data["d"] = Buffer.from(Convert.FromBase64Url(jwk.d!)); + } + native.Key.importJwk(data, keyType, (err, key) => { + try { + if (err) { + reject(new core.CryptoError(`ImportKey: Cannot import key from JWK\n${err}`)); + } else { + const Key: typeof CryptoKey = jwk.d ? EcPrivateKey : EcPublicKey; + const ecKey = Key.create(algorithm, jwk.d ? "private" : "public", extractable, keyUsages); + ecKey.native = key; + resolve(CryptoKeyStorage.setItem(ecKey)); + } + } catch (e) { + reject(e); + } + }); + break; + } + case "pkcs8": + case "spki": { + let importFunction = native.Key.importPkcs8; + if (formatLC === "spki") { + importFunction = native.Key.importSpki; + } + const rawData = Buffer.from(keyData); + importFunction(rawData, (err, key) => { + try { + if (err) { + reject(new core.CryptoError(`ImportKey: Can not import key for ${format}\n${err.message}`)); + } else { + const Key: typeof CryptoKey = formatLC === "pkcs8" ? EcPrivateKey : EcPublicKey; + const ecKey = Key.create(algorithm, formatLC === "pkcs8" ? "private" : "public", extractable, keyUsages); + ecKey.native = key; + resolve(CryptoKeyStorage.setItem(ecKey)); + } + } catch (e) { + reject(e); + } + }); + break; + } + default: + throw new core.CryptoError(`ImportKey: Wrong format value '${format}'`); + } + }); + } + + public static checkCryptoKey(key: any): asserts key is EcPublicKey | EcPrivateKey { + if (!(key instanceof EcPrivateKey || key instanceof EcPublicKey)) { + throw new TypeError("key: Is not EC CryptoKey"); + } + } + + private static getNamedCurve(namedCurve: string) { + switch (namedCurve.toUpperCase()) { + case "P-192": + namedCurve = "secp192r1"; + break; + case "P-256": + namedCurve = "secp256r1"; + break; + case "P-384": + namedCurve = "secp384r1"; + break; + case "P-521": + namedCurve = "secp521r1"; + break; + case "K-256": + namedCurve = "secp256k1"; + break; + default: + throw new core.CryptoError("Unsupported namedCurve in use"); + } + return (native.EcNamedCurves as any)[namedCurve]; + } + +} diff --git a/lib/mechs/ec/ec_dh.ts b/lib/mechs/ec/ec_dh.ts new file mode 100644 index 0000000..101adff --- /dev/null +++ b/lib/mechs/ec/ec_dh.ts @@ -0,0 +1,49 @@ +import * as core from "webcrypto-core"; +import { CryptoKey } from "../../keys"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { EcCrypto } from "./crypto"; + +export class EcdhProvider extends core.EcdhProvider { + + public namedCurves = ["P-256", "P-384", "P-521", "K-256"]; + + public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await EcCrypto.generateKey( + { + ...algorithm, + name: this.name, + }, + extractable, + keyUsages); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return EcCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + } + + public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise { + return new Promise((resolve, reject) => { + const nativeKey = CryptoKeyStorage.getItem(baseKey).native as native.Key; + const publicKey = CryptoKeyStorage.getItem(algorithm.public).native as native.Key; + // derive bits + nativeKey.EcdhDeriveBits(publicKey, length, (err, raw) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(raw)); + } + }); + }); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + EcCrypto.checkCryptoKey(CryptoKeyStorage.getItem(key)); + } + +} diff --git a/lib/mechs/ec/ec_dsa.ts b/lib/mechs/ec/ec_dsa.ts new file mode 100644 index 0000000..a544028 --- /dev/null +++ b/lib/mechs/ec/ec_dsa.ts @@ -0,0 +1,71 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { EcCrypto } from "./crypto"; +import type { EcPrivateKey } from "./private_key"; +import type { EcPublicKey } from "./public_key"; + +export class EcdsaProvider extends core.EcdsaProvider { + + public namedCurves = ["P-256", "P-384", "P-521", "K-256"]; + + public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await EcCrypto.generateKey( + { + ...algorithm, + name: this.name, + }, + extractable, + keyUsages); + } + + public onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const alg = this.getOsslAlgorithm(algorithm); + const nativeKey = CryptoKeyStorage.getItem(key).native as native.Key; + + nativeKey.sign(alg, Buffer.from(data), (err, signature) => { + if (err) { + reject(new core.CryptoError(`NativeError: ${err.message}`)); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(signature)); + } + }); + }); + } + + public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const alg = this.getOsslAlgorithm(algorithm); + const nativeKey = CryptoKeyStorage.getItem(key).native as native.Key; + + nativeKey.verify(alg, Buffer.from(data), Buffer.from(signature), (err, res) => { + if (err) { + reject(new core.CryptoError(`NativeError: ${err.message}`)); + } else { + resolve(res); + } + }); + }); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return EcCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + EcCrypto.checkCryptoKey(CryptoKeyStorage.getItem(key)); + } + + // @internal + private getOsslAlgorithm(algorithm: EcdsaParams) { + const alg = (algorithm.hash as Algorithm).name.toUpperCase().replace("-", ""); + return alg; + } + +} diff --git a/lib/mechs/ec/helper.ts b/lib/mechs/ec/helper.ts new file mode 100644 index 0000000..c6d88dc --- /dev/null +++ b/lib/mechs/ec/helper.ts @@ -0,0 +1,32 @@ +import * as core from "webcrypto-core"; + +const namedOIDs: { [key: string]: string } = { + // P-256 + "1.2.840.10045.3.1.7": "P-256", + "P-256": "1.2.840.10045.3.1.7", + // P-384 + "1.3.132.0.34": "P-384", + "P-384": "1.3.132.0.34", + // P-521 + "1.3.132.0.35": "P-521", + "P-521": "1.3.132.0.35", + // K-256 + "1.3.132.0.10": "K-256", + "K-256": "1.3.132.0.10", +}; + +export function getNamedCurveByOid(oid: string) { + const namedCurve = namedOIDs[oid]; + if (!namedCurve) { + throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`); + } + return namedCurve; +} + +export function getOidByNamedCurve(namedCurve: string) { + const oid = namedOIDs[namedCurve]; + if (!oid) { + throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`); + } + return oid; +} diff --git a/lib/mechs/ec/index.ts b/lib/mechs/ec/index.ts new file mode 100644 index 0000000..c2923d8 --- /dev/null +++ b/lib/mechs/ec/index.ts @@ -0,0 +1,4 @@ +export * from "./private_key"; +export * from "./public_key"; +export * from "./ec_dsa"; +export * from "./ec_dh"; diff --git a/lib/mechs/ec/private_key.ts b/lib/mechs/ec/private_key.ts new file mode 100644 index 0000000..61c5068 --- /dev/null +++ b/lib/mechs/ec/private_key.ts @@ -0,0 +1,6 @@ +import { AsymmetricKey } from "../../keys"; + +export class EcPrivateKey extends AsymmetricKey { + public readonly type: "private" = "private"; + public algorithm!: EcKeyAlgorithm; +} diff --git a/lib/mechs/ec/public_key.ts b/lib/mechs/ec/public_key.ts new file mode 100644 index 0000000..4d09e21 --- /dev/null +++ b/lib/mechs/ec/public_key.ts @@ -0,0 +1,6 @@ +import { AsymmetricKey } from "../../keys/asymmetric"; + +export class EcPublicKey extends AsymmetricKey { + public readonly type: "public" = "public"; + public algorithm!: EcKeyAlgorithm; +} diff --git a/lib/mechs/hmac/hmac.ts b/lib/mechs/hmac/hmac.ts new file mode 100644 index 0000000..77d937d --- /dev/null +++ b/lib/mechs/hmac/hmac.ts @@ -0,0 +1,122 @@ +import { Convert } from "pvtsutils"; +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { ShaCrypto } from "../sha/crypto"; +import { HmacCryptoKey } from "./key"; + +export class HmacProvider extends core.HmacProvider { + + public async onGenerateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + const length = algorithm.length || ShaCrypto.size(algorithm.hash as Algorithm); + native.HmacKey.generate(length, (err, key) => { + if (err) { + reject(err); + } else { + const hmacKey = HmacCryptoKey.create(algorithm, "secret", extractable, keyUsages); + hmacKey.native = key; + resolve(CryptoKeyStorage.setItem(hmacKey)); + } + }); + }); + } + + public async onSign(algorithm: Algorithm, key: CryptoKey, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const hmacKey = CryptoKeyStorage.getItem(key) as HmacCryptoKey; + const alg = this.getOsslAlgorithm(hmacKey.algorithm); + const nativeKey = hmacKey.native as native.Key; + + nativeKey.sign(alg, Buffer.from(data), (err, signature) => { + if (err) { + reject(new core.CryptoError(`NativeError: ${err.message}`)); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(signature)); + } + }); + }); + } + + public async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { + const signature2 = await this.sign(algorithm, key, data); + return Buffer.from(signature2).compare(Buffer.from(signature)) === 0; + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + const formatLC = format.toLocaleLowerCase(); + let raw: ArrayBuffer; + switch (formatLC) { + case "jwk": + const jwk = keyData as JsonWebKey; + raw = Convert.FromBase64Url(jwk.k!); + break; + case "raw": + raw = keyData as ArrayBuffer; + break; + default: + throw new core.CryptoError(`ImportKey: Wrong format value '${format}'`); + } + native.HmacKey.import(Buffer.from(raw), (err, key) => { + if (err) { + reject(err); + } else { + const hmacKey = HmacCryptoKey.create(algorithm, "secret", extractable, keyUsages); + hmacKey.native = key; + resolve(CryptoKeyStorage.setItem(hmacKey)); + } + }); + }); + } + + public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise { + return new Promise((resolve, reject) => { + const nativeKey = CryptoKeyStorage.getItem(key).native as native.HmacKey; + switch (format.toLocaleLowerCase()) { + case "jwk": + const jwk: JsonWebKey = { + kty: "oct", + alg: "", + key_ops: key.usages, + k: "", + ext: true, + }; + // set alg + jwk.alg = "HS" + /-(\d+)$/.exec((key.algorithm as any).hash.name)![1]; + nativeKey.export((err, data) => { + if (err) { + reject(err); + } else { + jwk.k = Convert.ToBase64Url(data); + resolve(jwk); + } + }); + break; + case "raw": + nativeKey.export((err, data) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(data)); + } + }); + break; + default: throw new core.CryptoError(`ExportKey: Unknown export format '${format}'`); + } + }); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(CryptoKeyStorage.getItem(key) instanceof HmacCryptoKey)) { + throw new TypeError("key: Is not HMAC CryptoKey"); + } + } + + private getOsslAlgorithm(algorithm: HmacKeyAlgorithm) { + const alg = algorithm.hash.name.toUpperCase().replace("-", ""); + return alg; + } + +} diff --git a/lib/mechs/hmac/index.ts b/lib/mechs/hmac/index.ts new file mode 100644 index 0000000..0188ebc --- /dev/null +++ b/lib/mechs/hmac/index.ts @@ -0,0 +1 @@ +export * from "./hmac"; diff --git a/lib/mechs/hmac/key.ts b/lib/mechs/hmac/key.ts new file mode 100644 index 0000000..60d636c --- /dev/null +++ b/lib/mechs/hmac/key.ts @@ -0,0 +1,5 @@ +import { CryptoKey } from "../../keys"; + +export class HmacCryptoKey extends CryptoKey { + public algorithm!: HmacKeyAlgorithm; +} diff --git a/lib/mechs/pbkdf/index.ts b/lib/mechs/pbkdf/index.ts new file mode 100644 index 0000000..b038b9d --- /dev/null +++ b/lib/mechs/pbkdf/index.ts @@ -0,0 +1 @@ +export * from "./pbkdf2"; diff --git a/lib/mechs/pbkdf/key.ts b/lib/mechs/pbkdf/key.ts new file mode 100644 index 0000000..9849979 --- /dev/null +++ b/lib/mechs/pbkdf/key.ts @@ -0,0 +1,4 @@ +import { CryptoKey } from "../../keys"; + +export class PbkdfCryptoKey extends CryptoKey { +} diff --git a/lib/mechs/pbkdf/pbkdf2.ts b/lib/mechs/pbkdf/pbkdf2.ts new file mode 100644 index 0000000..e37e6f9 --- /dev/null +++ b/lib/mechs/pbkdf/pbkdf2.ts @@ -0,0 +1,59 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { PbkdfCryptoKey } from "./key"; + +export class Pbkdf2Provider extends core.Pbkdf2Provider { + + public getOsslAlgorithm(algorithm: Algorithm) { + const alg = algorithm.name.toUpperCase().replace("-", ""); + return alg; + } + + public async onDeriveBits(algorithm: Pbkdf2Params, baseKey: PbkdfCryptoKey, length: number): Promise { + return new Promise((resolve, reject) => { + const nativeKey = CryptoKeyStorage.getItem(baseKey).native as native.Pbkdf2Key; + const hash = algorithm.hash as Algorithm; + const salt = Buffer.from(core.BufferSourceConverter.toArrayBuffer(algorithm.salt)); + // derive bits + nativeKey.deriveBits(this.getOsslAlgorithm(hash), salt, algorithm.iterations, length, (err, raw) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(raw)); + } + }); + }); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return new Promise((resolve, reject) => { + let raw: ArrayBuffer; + switch (format) { + case "raw": + raw = keyData as ArrayBuffer; + break; + default: + throw new core.OperationError("format: Must be 'raw'"); + } + native.Pbkdf2Key.importKey(Buffer.from(raw), (err, key) => { + if (err) { + reject(err); + } else { + const pbkdf2Key = PbkdfCryptoKey.create(algorithm, "secret", false, keyUsages); + pbkdf2Key.native = key; + resolve(CryptoKeyStorage.setItem(pbkdf2Key)); + + } + }); + }); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + if (!(CryptoKeyStorage.getItem(key) instanceof PbkdfCryptoKey)) { + throw new TypeError("key: Is not PBKDF CryptoKey"); + } + } + +} diff --git a/lib/mechs/rsa/crypto.ts b/lib/mechs/rsa/crypto.ts new file mode 100644 index 0000000..c84baea --- /dev/null +++ b/lib/mechs/rsa/crypto.ts @@ -0,0 +1,199 @@ +import { Convert } from "pvtsutils"; +import * as core from "webcrypto-core"; +import { CryptoKey, CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { RsaPrivateKey } from "./private_key"; +import { RsaPublicKey } from "./public_key"; + +export class RsaCrypto { + + public static publicKeyUsages = ["verify", "encrypt", "wrapKey"]; + public static privateKeyUsages = ["sign", "decrypt", "unwrapKey"]; + + public static async generateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: string[]): Promise { + return new Promise((resolve, reject) => { + const size = algorithm.modulusLength; + const exp = Buffer.from(algorithm.publicExponent); + // convert exp + let nExp: number = 0; + if (exp.length === 3) { + nExp = 1; + } + native.Key.generateRsa(size, nExp, (err, key) => { + try { + if (err) { + reject(new core.CryptoError(`Rsa: Can not generate new key\n${err.message}`)); + } else { + const prvUsages = ["sign", "decrypt", "unwrapKey"] + .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; + const pubUsages = ["verify", "encrypt", "wrapKey"] + .filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage)) as KeyUsage[]; + + const privateKey = RsaPrivateKey.create(algorithm, "private", extractable, prvUsages); + const publicKey = RsaPublicKey.create(algorithm, "public", true, pubUsages); + privateKey.native = publicKey.native = key; + + resolve({ + privateKey: CryptoKeyStorage.setItem(privateKey), + publicKey: CryptoKeyStorage.setItem(publicKey), + }); + } + } catch (e) { + reject(e); + } + }); + }); + } + + public static async exportKey(format: KeyFormat, key: core.CryptoKey): Promise { + return new Promise((resolve, reject) => { + const nativeKey = CryptoKeyStorage.getItem(key).native as native.Key; + const type = key.type === "public" ? native.KeyType.PUBLIC : native.KeyType.PRIVATE; + switch (format.toLocaleLowerCase()) { + case "jwk": + nativeKey.exportJwk(type, (err, data) => { + if (err) { + throw new core.CryptoError(`Cannot export JWK key\n${err}`); + } + try { + const jwk: JsonWebKey = { + kty: "RSA", + ext: true, + alg: this.getJwkAlgorithm(key.algorithm as RsaHashedKeyAlgorithm), + }; + jwk.key_ops = key.usages; + + jwk.e = Convert.ToBase64Url(data.e); + jwk.n = Convert.ToBase64Url(data.n); + if (key.type === "private") { + jwk.d = Convert.ToBase64Url(data.d); + jwk.p = Convert.ToBase64Url(data.p); + jwk.q = Convert.ToBase64Url(data.q); + jwk.dp = Convert.ToBase64Url(data.dp); + jwk.dq = Convert.ToBase64Url(data.dq); + jwk.qi = Convert.ToBase64Url(data.qi); + } + resolve(jwk); + } catch (e) { + reject(e); + } + }); + break; + case "spki": + nativeKey.exportSpki((err, raw) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(raw)); + } + }); + break; + case "pkcs8": + nativeKey.exportPkcs8((err, raw) => { + if (err) { + reject(err); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(raw)); + } + }); + break; + default: + throw new core.CryptoError(`ExportKey: Unknown export format '${format}'`); + } + }); + } + + public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + let keyType = native.KeyType.PUBLIC; + return new Promise((resolve, reject) => { + const formatLC = format.toLocaleLowerCase(); + switch (formatLC) { + case "jwk": + const jwk = keyData as JsonWebKey; + const data: { [key: string]: Buffer } = {}; + // prepare data + data["kty"] = jwk.kty as any; + data["n"] = Buffer.from(Convert.FromBase64Url(jwk.n!)); + data["e"] = Buffer.from(Convert.FromBase64Url(jwk.e!)); + if (jwk.d) { + keyType = native.KeyType.PRIVATE; + data["d"] = Buffer.from(Convert.FromBase64Url(jwk.d!)); + data["p"] = Buffer.from(Convert.FromBase64Url(jwk.p!)); + data["q"] = Buffer.from(Convert.FromBase64Url(jwk.q!)); + data["dp"] = Buffer.from(Convert.FromBase64Url(jwk.dp!)); + data["dq"] = Buffer.from(Convert.FromBase64Url(jwk.dq!)); + data["qi"] = Buffer.from(Convert.FromBase64Url(jwk.qi!)); + } + native.Key.importJwk(data, keyType, (err, key) => { + try { + if (err) { + reject(new core.CryptoError(`ImportKey: Cannot import key from JWK\n${err}`)); + } else { + resolve(key); + } + } catch (e) { + reject(e); + } + }); + break; + case "pkcs8": + case "spki": + let importFunction = native.Key.importSpki; + if (formatLC === "pkcs8") { + keyType = native.KeyType.PRIVATE; + importFunction = native.Key.importPkcs8; + } + importFunction(Buffer.from(keyData), (err, key) => { + try { + if (err) { + reject(new core.CryptoError(`ImportKey: Can not import key for ${format}\n${err.message}`)); + } else { + resolve(key); + } + } catch (e) { + reject(e); + } + }); + break; + default: + throw new core.CryptoError(`ImportKey: Wrong format value '${format}'`); + } + }) + .then((key) => { + const alg: RsaHashedKeyAlgorithm = { + ...algorithm, + modulusLength: key.modulusLength() << 3, + publicExponent: new Uint8Array(key.publicExponent()), + hash: algorithm.hash as Algorithm, + }; + const Key: typeof CryptoKey = keyType + ? RsaPrivateKey + : RsaPublicKey; + const rsaKey = Key.create(alg, keyType ? "private" : "public", extractable, keyUsages); + rsaKey.native = key; + return CryptoKeyStorage.setItem(rsaKey); + }); + } + + public static checkCryptoKey(key: any): asserts key is RsaPublicKey | RsaPrivateKey { + if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) { + throw new TypeError("key: Is not RSA CryptoKey"); + } + } + + public static getJwkAlgorithm(algorithm: RsaHashedKeyAlgorithm) { + 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]}`; + default: + throw new core.OperationError("algorithm: Is not recognized"); + } + } + +} diff --git a/lib/mechs/rsa/index.ts b/lib/mechs/rsa/index.ts new file mode 100644 index 0000000..b077c10 --- /dev/null +++ b/lib/mechs/rsa/index.ts @@ -0,0 +1,5 @@ +export * from "./private_key"; +export * from "./public_key"; +export * from "./rsa_ssa"; +export * from "./rsa_pss"; +export * from "./rsa_oaep"; diff --git a/lib/mechs/rsa/private_key.ts b/lib/mechs/rsa/private_key.ts new file mode 100644 index 0000000..7267e7b --- /dev/null +++ b/lib/mechs/rsa/private_key.ts @@ -0,0 +1,6 @@ +import { AsymmetricKey } from "../../keys"; + +export class RsaPrivateKey extends AsymmetricKey { + public readonly type: "private" = "private"; + public algorithm!: RsaHashedKeyAlgorithm; +} diff --git a/lib/mechs/rsa/public_key.ts b/lib/mechs/rsa/public_key.ts new file mode 100644 index 0000000..8a3fb06 --- /dev/null +++ b/lib/mechs/rsa/public_key.ts @@ -0,0 +1,6 @@ +import { AsymmetricKey } from "../../keys/asymmetric"; + +export class RsaPublicKey extends AsymmetricKey { + public readonly type: "public" = "public"; + public algorithm!: RsaHashedKeyAlgorithm; +} diff --git a/lib/mechs/rsa/rsa_oaep.ts b/lib/mechs/rsa/rsa_oaep.ts new file mode 100644 index 0000000..e346315 --- /dev/null +++ b/lib/mechs/rsa/rsa_oaep.ts @@ -0,0 +1,67 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { RsaCrypto } from "./crypto"; +import { RsaPrivateKey } from "./private_key"; +import { RsaPublicKey } from "./public_key"; + +export class RsaOaepProvider extends core.RsaOaepProvider { + + public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await RsaCrypto.generateKey( + { + ...algorithm, + name: this.name, + }, + extractable, + keyUsages); + } + + public async onEncrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, Buffer.from(data), true); + } + + public async onDecrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: ArrayBuffer): Promise { + return this.internalEncrypt(algorithm, key, Buffer.from(data), false); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return RsaCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + RsaCrypto.checkCryptoKey(CryptoKeyStorage.getItem(key)); + } + + private getOsslAlgorithm(algorithm: RsaHashedKeyAlgorithm) { + const alg = algorithm.hash.name.toUpperCase().replace("-", ""); + return alg; + } + + private internalEncrypt(algorithm: RsaOaepParams, key: CryptoKey, data: Buffer, encrypt: boolean): PromiseLike { + return new Promise((resolve, reject) => { + const rsaKey = CryptoKeyStorage.getItem(key) as RsaPrivateKey; + const nativeKey = rsaKey.native as native.Key; + const alg = this.getOsslAlgorithm(rsaKey.algorithm); + + let label: Buffer | null = null; + if (algorithm.label) { + label = Buffer.from(core.BufferSourceConverter.toArrayBuffer(algorithm.label)); + } + + nativeKey.RsaOaepEncDec(alg, data, label, !encrypt, (err, res) => { + if (err) { + reject(new core.CryptoError("NativeError: " + err)); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(res)); + } + }); + }); + } + +} diff --git a/lib/mechs/rsa/rsa_pss.ts b/lib/mechs/rsa/rsa_pss.ts new file mode 100644 index 0000000..d3774d4 --- /dev/null +++ b/lib/mechs/rsa/rsa_pss.ts @@ -0,0 +1,68 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { RsaCrypto } from "./crypto"; +import { RsaPrivateKey } from "./private_key"; + +export class RsaPssProvider extends core.RsaPssProvider { + + public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await RsaCrypto.generateKey( + { + ...algorithm, + name: this.name, + }, + extractable, + keyUsages); + } + + public onSign(algorithm: RsaPssParams, key: CryptoKey, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const rsaKey = CryptoKeyStorage.getItem(key) as RsaPrivateKey; + const alg = this.getOsslAlgorithm(rsaKey.algorithm); + const nativeKey = rsaKey.native as native.Key; + + nativeKey.RsaPssSign(alg, algorithm.saltLength, Buffer.from(data), (err, signature) => { + if (err) { + reject(new core.CryptoError("NativeError: " + err.message)); + } else { + resolve(core.BufferSourceConverter.toArrayBuffer(signature)); + } + }); + }); + } + public onVerify(algorithm: RsaPssParams, key: CryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const rsaKey = CryptoKeyStorage.getItem(key) as RsaPrivateKey; + const alg = this.getOsslAlgorithm(rsaKey.algorithm); + const nativeKey = rsaKey.native as native.Key; + + nativeKey.RsaPssVerify(alg, algorithm.saltLength, Buffer.from(data), Buffer.from(signature), (err, res) => { + if (err) { + reject(new core.CryptoError("NativeError: " + err.message)); + } else { + resolve(res); + } + }); + }); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return RsaCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + RsaCrypto.checkCryptoKey(CryptoKeyStorage.getItem(key)); + } + + private getOsslAlgorithm(algorithm: RsaHashedKeyAlgorithm) { + const alg = algorithm.hash.name.toUpperCase().replace("-", ""); + return alg; + } + +} diff --git a/lib/mechs/rsa/rsa_ssa.ts b/lib/mechs/rsa/rsa_ssa.ts new file mode 100644 index 0000000..856ce7e --- /dev/null +++ b/lib/mechs/rsa/rsa_ssa.ts @@ -0,0 +1,68 @@ +import * as core from "webcrypto-core"; +import { CryptoKeyStorage } from "../../keys"; +import * as native from "../../native"; +import { RsaCrypto } from "./crypto"; +import { RsaPrivateKey } from "./private_key"; + +export class RsaSsaProvider extends core.RsaSsaProvider { + + public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await RsaCrypto.generateKey( + { + ...algorithm, + name: this.name, + }, + extractable, + keyUsages); + } + + public onSign(algorithm: Algorithm, key: CryptoKey, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const rsaKey = CryptoKeyStorage.getItem(key) as RsaPrivateKey; + const alg = this.getOsslAlgorithm(rsaKey.algorithm); + const nativeKey = rsaKey.native as native.Key; + + nativeKey.sign(alg, Buffer.from(data), (err, signature) => { + if (err) { + reject(new core.CryptoError(`NativeError: ${err.message}`)); + } else { + resolve(signature.buffer as ArrayBuffer); + } + }); + }); + } + public onVerify(algorithm: Algorithm, key: CryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { + return new Promise((resolve, reject) => { + const rsaKey = CryptoKeyStorage.getItem(key) as RsaPrivateKey; + const alg = this.getOsslAlgorithm(rsaKey.algorithm); + const nativeKey = rsaKey.native as native.Key; + + nativeKey.verify(alg, Buffer.from(data), Buffer.from(signature), (err, res) => { + if (err) { + reject(new core.CryptoError(`NativeError: ${err.message}`)); + } else { + resolve(res); + } + }); + }); + } + + public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { + return RsaCrypto.exportKey(format, key); + } + + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + return await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); + } + + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { + super.checkCryptoKey(key, keyUsage); + RsaCrypto.checkCryptoKey(CryptoKeyStorage.getItem(key)); + } + + private getOsslAlgorithm(algorithm: RsaHashedKeyAlgorithm) { + const alg = algorithm.hash.name.toUpperCase().replace("-", ""); + return alg; + } + +} diff --git a/lib/mechs/sha/crypto.ts b/lib/mechs/sha/crypto.ts new file mode 100644 index 0000000..6b6e508 --- /dev/null +++ b/lib/mechs/sha/crypto.ts @@ -0,0 +1,48 @@ +import * as core from "webcrypto-core"; +import * as native from "../../native"; + +export class ShaCrypto { + + /** + * Returns size of the hash algorithm in bits + * @param algorithm Hash algorithm + * @throws Throws Error if an unrecognized name + */ + public static size(algorithm: Algorithm) { + switch (algorithm.name.toUpperCase()) { + case "SHA-1": + return 160; + case "SHA-256": + return 256; + case "SHA-384": + return 384; + case "SHA-512": + return 512; + default: + throw new Error("Unrecognized name"); + } + } + + public static digest(algorithm: Algorithm, data: ArrayBuffer) { + return new Promise((resolve, reject) => { + const algName = algorithm.name.toLowerCase(); + switch (algName) { + case "sha-1": + case "sha-256": + case "sha-384": + case "sha-512": + native.Core.digest(algName.replace("-", ""), Buffer.from(data), (err, digest) => { + if (err) { + reject(err); + } else { + resolve(digest.buffer); + } + }); + break; + default: + throw new core.AlgorithmError("Unsupported algorithm"); + } + }); + } + +} diff --git a/lib/mechs/sha/index.ts b/lib/mechs/sha/index.ts new file mode 100644 index 0000000..f85391e --- /dev/null +++ b/lib/mechs/sha/index.ts @@ -0,0 +1,4 @@ +export * from "./sha_1"; +export * from "./sha_256"; +export * from "./sha_384"; +export * from "./sha_512"; diff --git a/lib/mechs/sha/sha_1.ts b/lib/mechs/sha/sha_1.ts new file mode 100644 index 0000000..ef8f9fb --- /dev/null +++ b/lib/mechs/sha/sha_1.ts @@ -0,0 +1,12 @@ +import * as core from "webcrypto-core"; +import { ShaCrypto } from "./crypto"; + +export class Sha1Provider extends core.ProviderCrypto { + public name = "SHA-1"; + public usages = []; + + public async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise { + return ShaCrypto.digest(algorithm, data); + } + +} diff --git a/lib/mechs/sha/sha_256.ts b/lib/mechs/sha/sha_256.ts new file mode 100644 index 0000000..367d77b --- /dev/null +++ b/lib/mechs/sha/sha_256.ts @@ -0,0 +1,12 @@ +import * as core from "webcrypto-core"; +import { ShaCrypto } from "./crypto"; + +export class Sha256Provider extends core.ProviderCrypto { + public name = "SHA-256"; + public usages = []; + + public async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise { + return ShaCrypto.digest(algorithm, data); + } + +} diff --git a/lib/mechs/sha/sha_384.ts b/lib/mechs/sha/sha_384.ts new file mode 100644 index 0000000..c9d5534 --- /dev/null +++ b/lib/mechs/sha/sha_384.ts @@ -0,0 +1,12 @@ +import * as core from "webcrypto-core"; +import { ShaCrypto } from "./crypto"; + +export class Sha384Provider extends core.ProviderCrypto { + public name = "SHA-384"; + public usages = []; + + public async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise { + return ShaCrypto.digest(algorithm, data); + } + +} diff --git a/lib/mechs/sha/sha_512.ts b/lib/mechs/sha/sha_512.ts new file mode 100644 index 0000000..fb7250c --- /dev/null +++ b/lib/mechs/sha/sha_512.ts @@ -0,0 +1,12 @@ +import * as core from "webcrypto-core"; +import { ShaCrypto } from "./crypto"; + +export class Sha512Provider extends core.ProviderCrypto { + public name = "SHA-512"; + public usages = []; + + public async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise { + return ShaCrypto.digest(algorithm, data); + } + +} diff --git a/lib/native.ts b/lib/native.ts index b6fd34d..7445223 100644 --- a/lib/native.ts +++ b/lib/native.ts @@ -1,231 +1,231 @@ const native = require("../build/Release/nodessl.node"); export declare enum EcNamedCurves { - secp112r1 = 704, - secp112r2 = 705, - secp128r1 = 706, - secp128r2 = 707, - secp160k1 = 708, - secp160r1 = 709, - secp160r2 = 710, - secp192r1 = 409, - secp192k1 = 711, - secp224k1 = 712, - secp224r1 = 713, - secp256k1 = 714, - secp256r1 = 415, - secp384r1 = 715, - secp521r1 = 716, - sect113r1 = 717, - sect113r2 = 718, - sect131r1 = 719, - sect131r2 = 720, - sect163k1 = 721, - sect163r1 = 722, - sect163r2 = 723, - sect193r1 = 724, - sect193r2 = 725, - sect233k1 = 726, - sect233r1 = 727, - sect239k1 = 728, - sect283k1 = 729, - sect283r1 = 730, - sect409k1 = 731, - sect409r1 = 732, - sect571k1 = 733, - sect571r1 = 734, + secp112r1 = 704, + secp112r2 = 705, + secp128r1 = 706, + secp128r2 = 707, + secp160k1 = 708, + secp160r1 = 709, + secp160r2 = 710, + secp192r1 = 409, + secp192k1 = 711, + secp224k1 = 712, + secp224r1 = 713, + secp256k1 = 714, + secp256r1 = 415, + secp384r1 = 715, + secp521r1 = 716, + sect113r1 = 717, + sect113r2 = 718, + sect131r1 = 719, + sect131r2 = 720, + sect163k1 = 721, + sect163r1 = 722, + sect163r2 = 723, + sect193r1 = 724, + sect193r2 = 725, + sect233k1 = 726, + sect233r1 = 727, + sect239k1 = 728, + sect283k1 = 729, + sect283r1 = 730, + sect409k1 = 731, + sect409r1 = 732, + sect571k1 = 733, + sect571r1 = 734, } export declare enum RsaPublicExponent { - RSA_3, - RSA_F4, + RSA_3, + RSA_F4, } export declare enum KeyType { - PUBLIC, - PRIVATE, + PUBLIC, + PRIVATE, } export declare class Key { - /** - * Generate RSA key pair - * @param modulus modulus size of RSA key pair - * @param publicExponent public exponent of RSA key pair - * @param callback callback function (err: Error, key: Key) - */ - public static generateRsa(modulus: number, publicExponent: RsaPublicExponent, callback: (err: Error, key: Key) => void): void; - - /** - * Generate EC key pair - * @param namedCurve NID of curve name - * @param callback callback function (err: Error, raw: Key) - */ - public static generateEc(namedCurve: EcNamedCurves, callback: (err: Error, key: Key) => void): void; - - /** - * create Key from JWK data - * @param jwk key in JWK format - * @param keyType type of imported key (PRIVATE or PUBLIC) - * @param callback callback function (err: Error, key: Key) - */ - public static importJwk(jwk: object, keyType: KeyType, callback: (err: Error, key: Key) => void): void; - /** - * create Key from JWK data - * @param jwk key in JWK format - * @param keyType type of imported key (PRIVATE or PUBLIC) - */ - public static importJwk(jwk: { [key: string]: Buffer }, keyType: KeyType): any; - - /** - * create Key from SPKI - * @param raw DER data raw - * @param callback callback function (err: Error, key: Key) - */ - public static importSpki(raw: Buffer, callback: (err: Error, key: Key) => void): void; - - /** - * create Key from PKCS8 - * @param raw DER data raw - * @param callback callback function (err: Error, key: KeyPair) - */ - public static importPkcs8(raw: Buffer, callback: (err: Error, key: Key) => void): void; - - /** - * type of key - */ - public type: number; - - /** - * RSA modulus length - */ - public modulusLength(): number; - - /** - * RSA public exponent - */ - public publicExponent(): Buffer; - - /** - * Export Key to JWK data - * @param keyType type of exported key (PRIVATE or PUBLIC) - * @param callback callback function (err: Error, jwk: Object) - */ - public exportJwk(keyType: KeyType, callback: (err: Error, jwk: any) => void): void; - /** - * Export Key to JWK data - * @param keyType type of exported key (PRIVATE or PUBLIC) - */ - public exportJwk(keyType: KeyType): any; - - /** - * export Key to SPKI - * @param callback callback function (err: Error, raw: Buffer) - */ - public exportSpki(callback: (err: Error, raw: Buffer) => void): void; - - /** - * export Key to PKCS8 - * @param callback callback function (err: Error, raw: Buffer) - */ - public exportPkcs8(callback: (err: Error, raw: Buffer) => void): void; - - /** - * sign data EC, RSA - * @param digestName name of digest algorithm - * @param message message - * @param callback callback function (err: Error, signature: Buffer) - */ - public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; - - /** - * verify data RSA, EC - * @param digestName name of digest algorithm - * @param message message - * @param signature signature from message - * @param callback callback function (err: Error, valid: boolean) - */ - public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; - - /** - * encrypt/decrypt operation for RSA OAEP key - * @param digestName name of digest algorithm - * @param data incoming data - * @param label label for operation. Can be NULL - * @param decrypt type of operation - * @param callback callback function (err: Error, raw: Buffer) - */ - public RsaOaepEncDec(digestName: string, data: Buffer, label: Buffer | null, decrypt: boolean, callback: (err: Error, raw: Buffer) => void): void; - - public RsaPssSign(digestName: string, saltLength: number, data: Buffer, cb: (err: Error, signature: Buffer) => void): void; - public RsaPssVerify(digestName: string, saltLength: number, data: Buffer, signature: Buffer, cb: (err: Error, verified: boolean) => void): void; - - /** - * derives key with ECDH - * @param pubKey public key for key derivation - * @param derivedLen size of derived key (bytes) - * @param callback callback function (err: Error, raw: Buffer) - */ - public EcdhDeriveKey(pubKey: Key, derivedLen: number, callback: (err: Error, raw: Buffer) => void): void; - - /** - * derives bits with ECDH - * @param pubKey public key for key derivation - * @param lengthBits the number of bits you want to derive - * @param callback callback function (err: Error, raw: Buffer) - */ - public EcdhDeriveBits(pubKey: Key, lengthBits: number, callback: (err: Error, raw: Buffer) => void): void; + /** + * Generate RSA key pair + * @param modulus modulus size of RSA key pair + * @param publicExponent public exponent of RSA key pair + * @param callback callback function (err: Error, key: Key) + */ + public static generateRsa(modulus: number, publicExponent: RsaPublicExponent, callback: (err: Error, key: Key) => void): void; + + /** + * Generate EC key pair + * @param namedCurve NID of curve name + * @param callback callback function (err: Error, raw: Key) + */ + public static generateEc(namedCurve: EcNamedCurves, callback: (err: Error, key: Key) => void): void; + + /** + * create Key from JWK data + * @param jwk key in JWK format + * @param keyType type of imported key (PRIVATE or PUBLIC) + * @param callback callback function (err: Error, key: Key) + */ + public static importJwk(jwk: object, keyType: KeyType, callback: (err: Error, key: Key) => void): void; + /** + * create Key from JWK data + * @param jwk key in JWK format + * @param keyType type of imported key (PRIVATE or PUBLIC) + */ + public static importJwk(jwk: { [key: string]: Buffer }, keyType: KeyType): any; + + /** + * create Key from SPKI + * @param raw DER data raw + * @param callback callback function (err: Error, key: Key) + */ + public static importSpki(raw: Buffer, callback: (err: Error, key: Key) => void): void; + + /** + * create Key from PKCS8 + * @param raw DER data raw + * @param callback callback function (err: Error, key: KeyPair) + */ + public static importPkcs8(raw: Buffer, callback: (err: Error, key: Key) => void): void; + + /** + * type of key + */ + public type: number; + + /** + * RSA modulus length + */ + public modulusLength(): number; + + /** + * RSA public exponent + */ + public publicExponent(): Buffer; + + /** + * Export Key to JWK data + * @param keyType type of exported key (PRIVATE or PUBLIC) + * @param callback callback function (err: Error, jwk: Object) + */ + public exportJwk(keyType: KeyType, callback: (err: Error, jwk: any) => void): void; + /** + * Export Key to JWK data + * @param keyType type of exported key (PRIVATE or PUBLIC) + */ + public exportJwk(keyType: KeyType): any; + + /** + * export Key to SPKI + * @param callback callback function (err: Error, raw: Buffer) + */ + public exportSpki(callback: (err: Error, raw: Buffer) => void): void; + + /** + * export Key to PKCS8 + * @param callback callback function (err: Error, raw: Buffer) + */ + public exportPkcs8(callback: (err: Error, raw: Buffer) => void): void; + + /** + * sign data EC, RSA + * @param digestName name of digest algorithm + * @param message message + * @param callback callback function (err: Error, signature: Buffer) + */ + public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; + + /** + * verify data RSA, EC + * @param digestName name of digest algorithm + * @param message message + * @param signature signature from message + * @param callback callback function (err: Error, valid: boolean) + */ + public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; + + /** + * encrypt/decrypt operation for RSA OAEP key + * @param digestName name of digest algorithm + * @param data incoming data + * @param label label for operation. Can be NULL + * @param decrypt type of operation + * @param callback callback function (err: Error, raw: Buffer) + */ + public RsaOaepEncDec(digestName: string, data: Buffer, label: Buffer | null, decrypt: boolean, callback: (err: Error, raw: Buffer) => void): void; + + public RsaPssSign(digestName: string, saltLength: number, data: Buffer, cb: (err: Error, signature: Buffer) => void): void; + public RsaPssVerify(digestName: string, saltLength: number, data: Buffer, signature: Buffer, cb: (err: Error, verified: boolean) => void): void; + + /** + * derives key with ECDH + * @param pubKey public key for key derivation + * @param derivedLen size of derived key (bytes) + * @param callback callback function (err: Error, raw: Buffer) + */ + public EcdhDeriveKey(pubKey: Key, derivedLen: number, callback: (err: Error, raw: Buffer) => void): void; + + /** + * derives bits with ECDH + * @param pubKey public key for key derivation + * @param lengthBits the number of bits you want to derive + * @param callback callback function (err: Error, raw: Buffer) + */ + public EcdhDeriveBits(pubKey: Key, lengthBits: number, callback: (err: Error, raw: Buffer) => void): void; } export declare class AesKey { - /** - * generate key - * @param keySize size of generated key (should be 16, 24, 32) - * @param callback callback function (err: Error, key: KeyPair) - */ - public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; - public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; - - public encrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public encryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; - public encryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public encryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; - public decrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public decryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; - public decryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public decryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; - public export(callback: (err: Error, raw: Buffer) => void): void; - public wrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; - public unwrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; + /** + * generate key + * @param keySize size of generated key (should be 16, 24, 32) + * @param callback callback function (err: Error, key: KeyPair) + */ + public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; + public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; + + public encrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public encryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; + public encryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public encryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; + public decrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public decryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; + public decryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public decryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; + public export(callback: (err: Error, raw: Buffer) => void): void; + public wrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; + public unwrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; } export declare class HmacKey { - /** - * generate key - * @param keySize size of generated key (should be 16, 24, 32) - * @param callback callback function (err: Error, key: KeyPair) - */ - public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; - public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; - - public export(callback: (err: Error, raw: Buffer) => void): void; - /** - * sign data - * @param digestName name of digest algorithm - * @param message message - * @param callback callback function (err: Error, signature: Buffer) - */ - public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; - - /** - * verify data - * @param digestName name of digest algorithm - * @param message message - * @param signature signature from message - * @param callback callback function (err: Error, valid: boolean) - */ - public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; + /** + * generate key + * @param keySize size of generated key (should be 16, 24, 32) + * @param callback callback function (err: Error, key: KeyPair) + */ + public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; + public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; + + public export(callback: (err: Error, raw: Buffer) => void): void; + /** + * sign data + * @param digestName name of digest algorithm + * @param message message + * @param callback callback function (err: Error, signature: Buffer) + */ + public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; + + /** + * verify data + * @param digestName name of digest algorithm + * @param message message + * @param signature signature from message + * @param callback callback function (err: Error, valid: boolean) + */ + public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; } /** @@ -236,39 +236,39 @@ export declare class HmacKey { */ export declare class Pbkdf2Key { - /** - * Creates Pbkdf2Key from raw - * - * @static - * @param {Buffer} raw Raw of data - * @param {(error: Error, data: Pbkdf2Key) => void} cb - * - * @memberOf Pbkdf2Key - */ - public static importKey(raw: Buffer, cb: (error: Error, data: Pbkdf2Key) => void): void; - - /** - * Derives bits - * - * @param {string} digestName SHA digest name. SHA-1, SHA-256, SHA-384, SHA-512 - * @param {number} salt Salt - * @param {number} iterations Iterations - * @param {number} bitsLength Size of derived buffer in bits - * @param {(error: Error, data: Buffer) => void} cb Callback - * - * @memberOf Pbkdf2Key - */ - public deriveBits(digestName: string, salt: Buffer, iterations: number, bitsLength: number, cb: (error: Error, data: Buffer) => void): void; + /** + * Creates Pbkdf2Key from raw + * + * @static + * @param {Buffer} raw Raw of data + * @param {(error: Error, data: Pbkdf2Key) => void} cb + * + * @memberOf Pbkdf2Key + */ + public static importKey(raw: Buffer, cb: (error: Error, data: Pbkdf2Key) => void): void; + + /** + * Derives bits + * + * @param {string} digestName SHA digest name. SHA-1, SHA-256, SHA-384, SHA-512 + * @param {number} salt Salt + * @param {number} iterations Iterations + * @param {number} bitsLength Size of derived buffer in bits + * @param {(error: Error, data: Buffer) => void} cb Callback + * + * @memberOf Pbkdf2Key + */ + public deriveBits(digestName: string, salt: Buffer, iterations: number, bitsLength: number, cb: (error: Error, data: Buffer) => void): void; } export declare class Core { - /** - * Returns a digest generated from the hash function and text given as parameters - * @param {string} digest function name - * @param {Buffer} message for hash generation - * @param {Function} callback function (err: Error, digest: Buffer) - */ - public static digest(digestName: string, message: Buffer, callback: (err: Error, digest: Buffer) => void): void; + /** + * Returns a digest generated from the hash function and text given as parameters + * @param {string} digest function name + * @param {Buffer} message for hash generation + * @param {Function} callback function (err: Error, digest: Buffer) + */ + public static digest(digestName: string, message: Buffer, callback: (err: Error, digest: Buffer) => void): void; } module.exports = native; diff --git a/lib/subtle.ts b/lib/subtle.ts index 1cc7aed..8819b11 100644 --- a/lib/subtle.ts +++ b/lib/subtle.ts @@ -1,416 +1,64 @@ // Core -import * as webcrypto from "webcrypto-core"; -const AlgorithmError = webcrypto.AlgorithmError; -const PrepareAlgorithm = webcrypto.PrepareAlgorithm; -const BaseCrypto = webcrypto.BaseCrypto; -const AlgorithmNames = webcrypto.AlgorithmNames; - +import * as core from "webcrypto-core"; +import * as aes from "./mechs/aes"; +import * as des from "./mechs/des"; +import * as ec from "./mechs/ec"; +import * as hmac from "./mechs/hmac"; +import * as pbkdf from "./mechs/pbkdf"; +import * as rsa from "./mechs/rsa"; +import * as sha from "./mechs/sha"; // Local -import * as aes from "./crypto/aes"; -import * as ec from "./crypto/ec"; -import * as hmac from "./crypto/hmac"; -import * as pbkdf2 from "./crypto/pbkdf2"; -import * as rsa from "./crypto/rsa"; -import { CryptoKey, CryptoKeyPair } from "./key"; -import * as native from "./native"; - -/** - * Prepare array of data before it's using - * @param data Array which must be prepared - */ -function PrepareData(data: NodeBufferSource): Buffer { - return ab2b(data); -} - -/** - * Converts ArrayBuffer to Buffer - * @param ab ArrayBuffer value which must be converted to Buffer - */ -function ab2b(ab: NodeBufferSource) { - if (Buffer.isBuffer(ab)) { - return ab; - } else if (ArrayBuffer.isView(ab)) { - // NOTE: ab.buffer can have another size than view after ArrayBufferView.subarray - return Buffer.from(ab.buffer as ArrayBuffer, ab.byteOffset, ab.byteLength); - } else { - return Buffer.from(ab); - } -} - -/** - * Converts Buffer to ArrayBuffer - * @param b Buffer value which must be converted to ArrayBuffer - */ -// function b2ab(b: Buffer): ArrayBuffer { -// return b.buffer; -// } - -export class SubtleCrypto extends webcrypto.SubtleCrypto { - /** - * Computes a digest - * - * > Note: Has difference from W3 WebCrypto API - * > - Supports Buffer - * > - Supports SHA-1, SHA-224, SAH-256, SHA-384, SHA-512 algorithms - * - * @param {AlgorithmIdentifier} algorithm - * @param {NodeSourceBuffer} data - * @returns {PromiseLike} - * - * @memberOf SubtleCrypto - */ - public digest(algorithm: AlgorithmIdentifier, data: NodeBufferSource): PromiseLike { - return super.digest.apply(this, arguments) - .then(() => { - return new Promise((resolve, reject) => { - const alg = PrepareAlgorithm(algorithm); - const dataBytes = PrepareData(data); - const algName = alg.name.toLowerCase(); - switch (algName) { - case "sha-1": - case "sha-224": - case "sha-256": - case "sha-384": - case "sha-512": - native.Core.digest(algName.replace("-", ""), dataBytes, (err, digest) => { - if (err) { - reject(err); - } else { - resolve(digest.buffer); - } - }); - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, algName); - } - }); - }); - } - - public generateKey(algorithm: string, extractable: boolean, keyUsages: string[]): PromiseLike; - public generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams | DhKeyGenParams, extractable: boolean, keyUsages: string[]): PromiseLike; - public generateKey(algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike; - public generateKey(algorithm: any, extractable: boolean, keyUsages: string[]): PromiseLike { - return super.generateKey.apply(this, arguments) - .then(() => { - const alg = PrepareAlgorithm(algorithm); - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.RsaSSA.toLowerCase(): - AlgClass = rsa.RsaPKCS1; - break; - case AlgorithmNames.RsaPSS.toLowerCase(): - AlgClass = rsa.RsaPSS; - break; - case AlgorithmNames.RsaOAEP.toLowerCase(): - AlgClass = rsa.RsaOAEP; - break; - case AlgorithmNames.AesECB.toLowerCase(): - case AlgorithmNames.AesCBC.toLowerCase(): - case AlgorithmNames.AesCTR.toLowerCase(): - case AlgorithmNames.AesCTR.toLowerCase(): - case AlgorithmNames.AesGCM.toLowerCase(): - case AlgorithmNames.AesKW.toLowerCase(): - AlgClass = aes.AesCrypto; - break; - case AlgorithmNames.EcDSA.toLowerCase(): - case AlgorithmNames.EcDH.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Hmac.toLowerCase(): - AlgClass = hmac.HmacCrypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - return AlgClass.generateKey(alg as any, extractable, keyUsages); - }); - } - - public sign(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, data: NodeBufferSource): PromiseLike; - public sign(algorithm: any, key: CryptoKey, data: NodeBufferSource): PromiseLike { - return super.sign.apply(this, arguments) - .then(() => { - const alg = PrepareAlgorithm(algorithm as string); - const dataBytes = PrepareData(data); - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.RsaSSA.toLowerCase(): - AlgClass = rsa.RsaPKCS1; - break; - case AlgorithmNames.RsaPSS.toLowerCase(): - AlgClass = rsa.RsaPSS; - break; - case AlgorithmNames.EcDSA.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Hmac.toLowerCase(): - AlgClass = hmac.HmacCrypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - return AlgClass.sign(alg as any, key, dataBytes); - }); - } - - public verify(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, signature: NodeBufferSource, data: NodeBufferSource): PromiseLike; - public verify(algorithm: any, key: CryptoKey, signature: NodeBufferSource, data: NodeBufferSource): PromiseLike { - return super.verify.apply(this, arguments) - .then(() => { - const alg = PrepareAlgorithm(algorithm as string); - const signatureBytes = PrepareData(signature); - const dataBytes = PrepareData(data); - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.RsaSSA.toLowerCase(): - AlgClass = rsa.RsaPKCS1; - break; - case AlgorithmNames.RsaPSS.toLowerCase(): - AlgClass = rsa.RsaPSS; - break; - case AlgorithmNames.EcDSA.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Hmac.toLowerCase(): - AlgClass = hmac.HmacCrypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - return AlgClass.verify(alg as any, key, signatureBytes, dataBytes); - }); - } - - public encrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: NodeBufferSource): PromiseLike; - public encrypt(algorithm: any, key: CryptoKey, data: NodeBufferSource): PromiseLike { - return super.encrypt.apply(this, arguments) - .then(() => { - return this.encryptDecrypt(algorithm, key, data, true); - }); - } - - public decrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: NodeBufferSource): PromiseLike; - public decrypt(algorithm: any, key: CryptoKey, data: NodeBufferSource): PromiseLike { - return super.decrypt.apply(this, arguments) - .then(() => { - return this.encryptDecrypt(algorithm, key, data, false); - }); - } - - public wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: AlgorithmIdentifier): PromiseLike { - return super.wrapKey.apply(this, arguments) - .then(() => { - return this.exportKey(format as any, key) - .then((exportedKey) => { - const alg = webcrypto.PrepareAlgorithm(wrapAlgorithm); - let dataBytes: Buffer; - if (!(exportedKey instanceof ArrayBuffer)) { - dataBytes = Buffer.from(JSON.stringify(exportedKey)); - } else { - dataBytes = Buffer.from(exportedKey); - } - let CryptoClass: typeof BaseCrypto | undefined; - if (alg.name.toUpperCase() === webcrypto.AlgorithmNames.AesKW) { - CryptoClass = aes.AesCrypto; - } - - if (CryptoClass) { - return CryptoClass.encrypt(alg, wrappingKey, dataBytes); - } else { - return this.encryptDecrypt(alg, wrappingKey, dataBytes, true); - } - }); - }); - } - - public unwrapKey(format: string, wrappedKey: NodeBufferSource, unwrappingKey: CryptoKey, unwrapAlgorithm: AlgorithmIdentifier, unwrappedKeyAlgorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: string[]): PromiseLike { - return super.unwrapKey.apply(this, arguments) - .then(() => { - return Promise.resolve() - .then(() => { - const alg = webcrypto.PrepareAlgorithm(unwrapAlgorithm); - const dataBytes = PrepareData(wrappedKey); - - let CryptoClass: typeof BaseCrypto | undefined; - if (alg.name.toUpperCase() === webcrypto.AlgorithmNames.AesKW) { - CryptoClass = aes.AesCrypto; - } - - if (CryptoClass) { - return CryptoClass.decrypt(alg, unwrappingKey, dataBytes); - } else { - return this.encryptDecrypt(alg, unwrappingKey, dataBytes, false); - } - }) - .then((decryptedKey) => { - let keyData: JsonWebKey | Buffer; - if (format === "jwk") { - keyData = JSON.parse(Buffer.from(decryptedKey).toString()); - } else { - keyData = Buffer.from(decryptedKey); - } - return this.importKey(format as any, keyData as Buffer, unwrappedKeyAlgorithm as string, extractable, keyUsages); - }); - }); - } - - public deriveKey(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, derivedKeyType: string | AesDerivedKeyParams | HmacImportParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike; - public deriveKey(algorithm: any, baseKey: CryptoKey, derivedKeyType: any, extractable: boolean, keyUsages: string[]): PromiseLike { - return super.deriveKey.apply(this, arguments) - .then(() => { - const alg = PrepareAlgorithm(algorithm); - const algDerivedKeyType = PrepareAlgorithm(derivedKeyType); - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.EcDH.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Pbkdf2.toLowerCase(): - AlgClass = pbkdf2.Pbkdf2Crypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - return AlgClass.deriveKey(alg as any, baseKey, algDerivedKeyType, extractable, keyUsages); - }); - } - - public deriveBits(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, length: number): PromiseLike; - public deriveBits(algorithm: any, baseKey: CryptoKey, length: number): PromiseLike { - return super.deriveBits.apply(this, arguments) - .then(() => { - const alg = PrepareAlgorithm(algorithm); - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.EcDH.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Pbkdf2.toLowerCase(): - AlgClass = pbkdf2.Pbkdf2Crypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - return AlgClass.deriveBits(alg as any, baseKey, length); - }); - } - - public exportKey(format: "jwk", key: CryptoKey): PromiseLike; - public exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike; - public exportKey(format: string, key: CryptoKey): PromiseLike; - public exportKey(format: string, key: CryptoKey): PromiseLike { - return super.exportKey.apply(this, arguments) - .then(() => { - let AlgClass: typeof BaseCrypto; - switch (key.algorithm.name.toLowerCase()) { - case AlgorithmNames.RsaSSA.toLowerCase(): - AlgClass = rsa.RsaPKCS1; - break; - case AlgorithmNames.RsaPSS.toLowerCase(): - AlgClass = rsa.RsaPSS; - break; - case AlgorithmNames.RsaOAEP.toLowerCase(): - AlgClass = rsa.RsaOAEP; - break; - case AlgorithmNames.AesECB.toLowerCase(): - case AlgorithmNames.AesCBC.toLowerCase(): - case AlgorithmNames.AesCTR.toLowerCase(): - case AlgorithmNames.AesGCM.toLowerCase(): - case AlgorithmNames.AesKW.toLowerCase(): - AlgClass = aes.AesCrypto; - break; - case AlgorithmNames.EcDSA.toLowerCase(): - case AlgorithmNames.EcDH.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Hmac.toLowerCase(): - AlgClass = hmac.HmacCrypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, key.algorithm.name); - } - return AlgClass.exportKey(format, key); - }); - } - - public importKey(format: "jwk", keyData: JsonWebKey, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: string[]): PromiseLike; - public importKey(format: "raw" | "pkcs8" | "spki", keyData: NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: string[]): PromiseLike; - public importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: string[]): PromiseLike; - public importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: any, extractable: boolean, keyUsages: string[]): PromiseLike { - return super.importKey.apply(this, arguments) - .then(() => { - const alg = PrepareAlgorithm(algorithm as string); - - let dataAny = keyData; - if (format !== "jwk") { - dataAny = PrepareData(dataAny as NodeBufferSource); - } - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.RsaSSA.toLowerCase(): - AlgClass = rsa.RsaPKCS1; - break; - case AlgorithmNames.RsaPSS.toLowerCase(): - AlgClass = rsa.RsaPSS; - break; - case AlgorithmNames.RsaOAEP.toLowerCase(): - AlgClass = rsa.RsaOAEP; - break; - case AlgorithmNames.AesECB.toLowerCase(): - case AlgorithmNames.AesCBC.toLowerCase(): - case AlgorithmNames.AesCTR.toLowerCase(): - case AlgorithmNames.AesGCM.toLowerCase(): - case AlgorithmNames.AesKW.toLowerCase(): - AlgClass = aes.AesCrypto; - break; - case AlgorithmNames.EcDSA.toLowerCase(): - case AlgorithmNames.EcDH.toLowerCase(): - AlgClass = ec.EcCrypto; - break; - case AlgorithmNames.Hmac.toLowerCase(): - AlgClass = hmac.HmacCrypto; - break; - case AlgorithmNames.Pbkdf2.toLowerCase(): - AlgClass = pbkdf2.Pbkdf2Crypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - return AlgClass.importKey(format, dataAny as Buffer, alg as any, extractable, keyUsages); - }); - } - - protected encryptDecrypt(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource, encrypt: boolean) { - const alg = PrepareAlgorithm(algorithm); - const dataBytes = PrepareData(data); - - let AlgClass: typeof BaseCrypto; - switch (alg.name.toLowerCase()) { - case AlgorithmNames.RsaOAEP.toLowerCase(): - AlgClass = rsa.RsaOAEP; - break; - case AlgorithmNames.AesECB.toLowerCase(): - case AlgorithmNames.AesCBC.toLowerCase(): - case AlgorithmNames.AesCTR.toLowerCase(): - case AlgorithmNames.AesGCM.toLowerCase(): - case AlgorithmNames.AesKW.toLowerCase(): - AlgClass = aes.AesCrypto; - break; - default: - throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name); - } - if (encrypt) { - return AlgClass.encrypt(alg, key, dataBytes); - } else { - return AlgClass.decrypt(alg, key, dataBytes); - } - } +// import * as pbkdf2 from "./crypto/pbkdf2"; +// import { CryptoKey, CryptoKeyPair } from "./key"; + +export class SubtleCrypto extends core.SubtleCrypto { + + constructor() { + super(); + + //#region AES + this.providers.set(new aes.AesCbcProvider()); + this.providers.set(new aes.AesCtrProvider()); + this.providers.set(new aes.AesGcmProvider()); + this.providers.set(new aes.AesCmacProvider()); + this.providers.set(new aes.AesKwProvider()); + this.providers.set(new aes.AesEcbProvider()); + //#endregion + + //#region DES + this.providers.set(new des.DesCbcProvider()); + this.providers.set(new des.DesEde3CbcProvider()); + //#endregion + + //#region RSA + this.providers.set(new rsa.RsaSsaProvider()); + this.providers.set(new rsa.RsaPssProvider()); + this.providers.set(new rsa.RsaOaepProvider()); + //#endregion + + //#region EC + this.providers.set(new ec.EcdsaProvider()); + this.providers.set(new ec.EcdhProvider()); + //#endregion + + //#region SHA + this.providers.set(new sha.Sha1Provider()); + this.providers.set(new sha.Sha256Provider()); + this.providers.set(new sha.Sha384Provider()); + this.providers.set(new sha.Sha512Provider()); + //#endregion + + //#region PBKDF + this.providers.set(new pbkdf.Pbkdf2Provider()); + //#endregion + + //#region HMAC + this.providers.set(new hmac.HmacProvider()); + //#endregion + + //#region HKDF + // this.providers.set(new HkdfProvider()); + //#endregion + } } diff --git a/lib/types.d.ts b/lib/types.d.ts deleted file mode 100644 index 7b38cad..0000000 --- a/lib/types.d.ts +++ /dev/null @@ -1 +0,0 @@ -type NodeBufferSource = BufferSource | Buffer; diff --git a/lib/webcrypto.ts b/lib/webcrypto.ts deleted file mode 100644 index 64ff9a7..0000000 --- a/lib/webcrypto.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Core -import * as crypto from "crypto"; -import * as webcrypto from "webcrypto-core"; - -// Local -import { KeyStorage } from "./key_storage"; -import * as subtle from "./subtle"; - -const ERR_RANDOM_VALUE_LENGTH = "Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (%1) exceeds the number of bytes of entropy available via this API (65536)."; -const ERR_RANDOM_NO_VALUE = "Failed to execute 'getRandomValues' on 'Crypto': Expected ArrayBufferView but got %s."; - -export interface WebCryptoOptions { - directory?: string; -} - -/** - * OpenSSL with WebCrypto Interface - */ -class WebCrypto implements NativeCrypto { - - public keyStorage: KeyStorage; - - public subtle: SubtleCrypto; - - /** - * Constructor - */ - constructor(options?: WebCryptoOptions) { - this.subtle = new subtle.SubtleCrypto(); - if (options && options.directory) { - this.keyStorage = new KeyStorage(options.directory); - } - } - - /** - * Generates cryptographically random values - * @param array Initialize array - */ - // Based on: https://github.com/KenanY/get-random-values - public getRandomValues(array: T): T { - if (array) { - if (array.byteLength > 65536) { - const error = new webcrypto.WebCryptoError(ERR_RANDOM_VALUE_LENGTH, array.byteLength); - error.code = 22; - throw error; - } - const bytes = crypto.randomBytes(array.byteLength); - (array as Uint8Array).set(new (array.constructor as typeof Uint8Array)(bytes.buffer)); - return array; - } else { - throw new webcrypto.WebCryptoError(ERR_RANDOM_NO_VALUE, array); - } - } - -} - -module.exports = WebCrypto; diff --git a/package-lock.json b/package-lock.json index 592c92c..82df42c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,64 +1,108 @@ { "name": "node-webcrypto-ossl", - "version": "1.0.48", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/core": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.7.tgz", + "integrity": "sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.7", + "@babel/helpers": "^7.8.4", + "@babel/parser": "^7.8.7", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "@babel/generator": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", - "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.8.tgz", + "integrity": "sha512-HKyUVu69cZoclptr8t8U5b6sx6zoWjh8jiUhnuj3MpZuKT2dJ8zPTuiy31luq32swhI0SpwItCIlU8XW7BZeJg==", "dev": true, "requires": { - "@babel/types": "^7.4.0", + "@babel/types": "^7.8.7", "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "lodash": "^4.17.13", + "source-map": "^0.5.0" } }, "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.8.3" } }, "@babel/helper-split-export-declaration": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", - "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helpers": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", + "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", "dev": true, "requires": { - "@babel/types": "^7.4.0" + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3" } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", "dev": true, "requires": { "chalk": "^2.0.0", @@ -67,37 +111,37 @@ } }, "@babel/parser": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.3.tgz", - "integrity": "sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ==", + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.8.tgz", + "integrity": "sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA==", "dev": true }, "@babel/template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", - "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.0", - "@babel/types": "^7.4.0" + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.3.tgz", - "integrity": "sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/types": "^7.4.0", + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.6", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.11" + "lodash": "^4.17.13" }, "dependencies": { "debug": { @@ -112,35 +156,154 @@ } }, "@babel/types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", - "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.7.tgz", + "integrity": "sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.11", + "lodash": "^4.17.13", "to-fast-properties": "^2.0.0" } }, + "@istanbuljs/load-nyc-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", + "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, + "@peculiar/webcrypto-test": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto-test/-/webcrypto-test-1.0.1.tgz", + "integrity": "sha512-0ScgGSff7wk2tsqZ1uUDqJW7kk1wcSKNlWKhzHdd7ZBhdYH7uFj8tuZ4cLzmjyagVhM4mcpXoplDGggf7ag49w==", + "dev": true, + "requires": { + "pvtsutils": "^1.0.10", + "tslib": "^1.11.1" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/mkdirp": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz", - "integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.0.tgz", + "integrity": "sha512-ONFY9//bCEr3DWKON3iDv/Q8LXnhaYYaNDeFSN0AtO5o4sLf9F0pstJKKKjQhXE0kJEeHs8eR6SAsROhhc2Csw==", "dev": true, "requires": { "@types/node": "*" } }, + "@types/mocha": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", + "dev": true + }, "@types/node": { - "version": "10.14.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.5.tgz", - "integrity": "sha512-Ja7d4s0qyGFxjGeDq5S7Si25OFibSAHUi6i17UWnwNnpitADN7hah9q0Tl25gxuV5R1u2Bx+np6w4LHXfHyj/g==", + "version": "12.12.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.30.tgz", + "integrity": "sha512-sz9MF/zk6qVr3pAnM0BSQvYIBK44tS75QC5N+VbWSE4DjCV/pJ+UzCW/F+vVnl7TkOPcuwQureKNtSSwjBTaMg==", "dev": true }, + "@types/rimraf": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.3.tgz", + "integrity": "sha512-dZfyfL/u9l/oi984hEXdmAjX3JHry7TLWw43u1HQ8HhPv6KtfxnrZ3T/bleJ0GEvnk9t5sM7eePkgMqz3yBcGg==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -170,13 +333,23 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", "dev": true, "requires": { - "default-require-extensions": "^2.0.0" + "default-require-extensions": "^3.0.0" } }, "archy": { @@ -185,6 +358,12 @@ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -222,9 +401,9 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "dev": true }, "balanced-match": { @@ -242,6 +421,12 @@ "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -252,22 +437,37 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, "caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", "dev": true, "requires": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" } }, "camelcase": { @@ -304,23 +504,67 @@ } } }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -337,21 +581,14 @@ "dev": true }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true, - "optional": true - }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -365,12 +602,20 @@ "dev": true }, "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "core-util-is": { @@ -380,51 +625,46 @@ "dev": true }, "coveralls": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.3.tgz", - "integrity": "sha512-viNfeGlda2zJr8Gj1zqXpDMRjw9uM54p7wzZdvLRyOgnAfCe974Dq4veZkjJdxQXbmdppu6flEajFYseHYaUhg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz", + "integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==", "dev": true, "requires": { - "growl": "~> 1.10.0", - "js-yaml": "^3.11.0", - "lcov-parse": "^0.0.10", + "js-yaml": "^3.13.1", + "lcov-parse": "^1.0.0", "log-driver": "^1.2.7", "minimist": "^1.2.0", - "request": "^2.86.0" + "request": "^2.88.0" }, "dependencies": { "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, - "cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - } - }, "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "dashdash": { @@ -452,12 +692,12 @@ "dev": true }, "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", "dev": true, "requires": { - "strip-bom": "^3.0.0" + "strip-bom": "^4.0.0" } }, "define-properties": { @@ -497,42 +737,29 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -558,26 +785,17 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, "extend": { "version": "3.0.2", @@ -603,15 +821,24 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", "dev": true, "requires": { "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" } }, "find-up": { @@ -633,25 +860,13 @@ } }, "foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - } + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" } }, "forever-agent": { @@ -671,33 +886,54 @@ "mime-types": "^2.1.12" } }, + "fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -721,16 +957,25 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "growl": { @@ -739,26 +984,6 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -791,18 +1016,19 @@ "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, "hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", "dev": true, "requires": { - "is-stream": "^1.0.1" + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" } }, "he": { @@ -811,10 +1037,10 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==", "dev": true }, "http-signature": { @@ -834,6 +1060,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -845,39 +1077,42 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } }, "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", "dev": true }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true }, "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { @@ -886,28 +1121,43 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "dev": true, "requires": { - "has": "^1.0.1" + "has": "^1.0.3" } }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" } }, "is-typedarray": { @@ -916,6 +1166,12 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -929,64 +1185,94 @@ "dev": true }, "istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-LXTBICkMARVgo579kWDm8SqfB6nvSDKNqIOBEjmJRnL04JvoMHCYGWaMddQnseJYtkEuEvO/sIcOxPLk9gERug==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", "dev": true }, "istanbul-lib-hook": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.6.tgz", - "integrity": "sha512-829DKONApZ7UCiPXcOYWSgkFXa4+vNYoNOt3F+4uDJLKL1OotAoVwvThoEj1i8jmOj7odbYcR3rnaHu+QroaXg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, "requires": { - "append-transform": "^1.0.0" + "append-transform": "^2.0.0" } }, "istanbul-lib-instrument": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.2.0.tgz", - "integrity": "sha512-06IM3xShbNW4NgZv5AP4QH0oHqf1/ivFo8eFys0ZjPXHGldHJQWb3riYOKXqmOqfxXBfxu4B+g/iuhOPZH0RJg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", "dev": true, "requires": { - "@babel/generator": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "istanbul-lib-coverage": "^2.0.4", - "semver": "^6.0.0" + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + } + }, "istanbul-lib-report": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.7.tgz", - "integrity": "sha512-wLH6beJBFbRBLiTlMOBxmb85cnVM1Vyl36N48e4e/aTKSM3WbOx7zbVIH1SQ537fhhsPbX0/C5JB4qsmyRXXyA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.4", - "make-dir": "^2.1.0", - "supports-color": "^6.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "istanbul-lib-source-maps": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.5.tgz", - "integrity": "sha512-eDhZ7r6r1d1zQPVZehLc3D0K14vRba/eBYkz3rw16DLOrrTzve9RmnkcwrrkWVgO1FL3EK5knujVe5S8QHE9xw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "dev": true, "requires": { "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.4", - "make-dir": "^2.1.0", - "rimraf": "^2.6.2", + "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "dependencies": { @@ -1008,12 +1294,13 @@ } }, "istanbul-reports": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.3.tgz", - "integrity": "sha512-T6EbPuc8Cb620LWAYyZ4D8SSn06dY9i1+IgUX2lTH8gbwflMc9Obd33zHTyNX653ybjpamAHS9toKS3E6cGhTw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==", "dev": true, "requires": { - "handlebars": "^4.1.0" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, "js-tokens": { @@ -1044,12 +1331,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -1068,6 +1349,32 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "json5": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz", + "integrity": "sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1080,41 +1387,12 @@ "verror": "1.10.0" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "lcov-parse": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", + "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", "dev": true }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -1126,9 +1404,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "lodash.flattendeep": { @@ -1144,92 +1422,52 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "chalk": "^2.4.2" } }, "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", "dev": true, "requires": { - "source-map": "^0.6.1" + "semver": "^6.0.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==", "dev": true }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "dev": true, "requires": { - "mime-db": "1.40.0" + "mime-db": "1.42.0" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1242,24 +1480,23 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", + "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==" }, "mocha": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz", - "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.0.tgz", + "integrity": "sha512-MymHK8UkU0K15Q/zX7uflZgVoRWiTjy0fXE/QjKts6mowUvGxOdPhZ2qj3b0iZdUrNZlW9LAIMFHB4IW+2b3EQ==", "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", + "chokidar": "3.3.0", "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", @@ -1268,19 +1505,30 @@ "growl": "1.10.5", "he": "1.2.0", "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "log-symbols": "3.0.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "node-environment-flags": "1.0.6", "object.assign": "4.1.0", "strip-json-comments": "2.0.1", "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + } } }, "ms": { @@ -1290,95 +1538,233 @@ "dev": true }, "nan": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" - }, - "neo-async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", - "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", - "dev": true - }, - "nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" } }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", "dev": true, "requires": { - "path-key": "^2.0.0" + "process-on-spawn": "^1.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "nyc": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.0.0.tgz", - "integrity": "sha512-R1zC6UZak6pzn5BZQorkSH5GdOGafrwyeja+eimS5Tu+KJ/hCgBc8qA1QWSzxQmT2FDl2lbpqPw7tBDbSvhAHg==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.4", - "istanbul-lib-hook": "^2.0.6", - "istanbul-lib-instrument": "^3.2.0", - "istanbul-lib-report": "^2.0.7", - "istanbul-lib-source-maps": "^3.0.5", - "istanbul-reports": "^2.2.2", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.0.tgz", + "integrity": "sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", + "js-yaml": "^3.13.1", + "make-dir": "^3.0.0", + "node-preload": "^0.2.0", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.2", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "uuid": "^3.3.3", + "yargs": "^15.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + } + }, + "yargs-parser": { + "version": "18.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.1.tgz", + "integrity": "sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } } }, "oauth-sign": { @@ -1387,6 +1773,12 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -1406,13 +1798,13 @@ } }, "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, "once": { @@ -1424,55 +1816,10 @@ "wrappy": "1" } }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1487,6 +1834,15 @@ "p-limit": "^2.0.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -1494,27 +1850,17 @@ "dev": true }, "package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", "dev": true, "requires": { "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", + "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" } }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -1528,9 +1874,9 @@ "dev": true }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { @@ -1539,66 +1885,78 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", "dev": true }, "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "find-up": "^3.0.0" + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "fromentries": "^1.2.0" } }, + "psl": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", + "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", + "dev": true + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -1606,13 +1964,11 @@ "dev": true }, "pvtsutils": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.4.tgz", - "integrity": "sha512-lBDyLfPIWZjxHr6Nnl83/iaZgVLczDcpEqWdqRnghzBKXifRU/7D5T6JPYWUAm0sJdFeF9+sNTKto6dj/3P/Kg==", - "dev": true, + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.10.tgz", + "integrity": "sha512-8ZKQcxnZKTn+fpDh7wL4yKax5fdl3UJzT8Jv49djZpB/dzPxacyN1Sez90b6YLdOmvIr9vaySJ5gw4aUA1EdSw==", "requires": { - "@types/node": "^10.12.15", - "tslib": "^1.9.3" + "tslib": "^1.10.0" } }, "qs": { @@ -1621,25 +1977,13 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", "dev": true, "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" + "picomatch": "^2.0.4" } }, "release-zalgo": { @@ -1692,33 +2036,72 @@ "dev": true }, "resolve": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz", - "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, + "rollup": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.1.0.tgz", + "integrity": "sha512-gfE1455AEazVVTJoeQtcOq/U6GSxwoj4XPSWVsuWmgIxj7sBQNLDOSA82PbdMe+cP8ql8fR1jogPFe8Wg8g4SQ==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "rollup-plugin-typescript2": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.26.0.tgz", + "integrity": "sha512-lUK7XZVG77tu8dmv1L/0LZFlavED/5Yo6e4iMMl6fdox/yKdj4IFRRPPJEXNdmEaT1nDQQeCi7b5IwKHffMNeg==", + "dev": true, + "requires": { + "find-cache-dir": "^3.2.0", + "fs-extra": "8.1.0", + "resolve": "1.15.1", + "rollup-pluginutils": "2.8.2", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + } + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", "dev": true }, "safer-buffer": { @@ -1728,9 +2111,9 @@ "dev": true }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "set-blocking": { @@ -1740,18 +2123,18 @@ "dev": true }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "signal-exit": { @@ -1766,52 +2149,49 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, - "spawn-wrap": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, - "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", - "dev": true - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1845,6 +2225,26 @@ "strip-ansi": "^4.0.0" } }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -1855,15 +2255,9 @@ } }, "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "strip-json-comments": { @@ -1882,15 +2276,30 @@ } }, "test-exclude": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.2.tgz", - "integrity": "sha512-N2pvaLpT8guUpb5Fe1GJlmvmzH3x+DAKmmyEQmFP792QcLYoGE1syxztSvPD1V8yPe6VrcCt6YGQVjSRjCASsA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "to-fast-properties": { @@ -1899,6 +2308,15 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -1917,16 +2335,31 @@ } } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true + "ts-node": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.7.0.tgz", + "integrity": "sha512-s659CsHrsxaRVDEleuOkGvbsA0rWHtszUNEt1r0CgAFN5ZZTQtDzpsluS7W5pOGJIa1xZE8R/zK4dEs+ldFezg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" }, "tunnel-agent": { "version": "0.6.0", @@ -1943,32 +2376,33 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "typescript": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", - "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, - "uglify-js": { - "version": "3.5.7", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.7.tgz", - "integrity": "sha512-GCgJx3BBuaf/QMvBBkhoHDh4SVsHCC3ILEzriPw4FgJJKCuxVBSYLRkDlmT3uhXyGWKs3VN5r0mCkBIZaHWu3w==", + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, - "optional": true, "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } + "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1979,21 +2413,11 @@ } }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -2006,11 +2430,12 @@ } }, "webcrypto-core": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-0.1.26.tgz", - "integrity": "sha512-BZVgJZkkHyuz8loKvsaOKiBDXDpmMZf5xG4QAOlSeYdXlFUl9c1FRrVnAXcOdb4fTHMG+TRu81odJwwSfKnWTA==", + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.0.18.tgz", + "integrity": "sha512-wHRMXYxtDUWsTXNyRdaYlbcbq1OJF9pQov5THqvn5OBvixpCjnjU2spvEscxqRY8bLlpHk2S7RtROIMyNoEyFg==", "requires": { - "tslib": "^1.7.1" + "pvtsutils": "^1.0.10", + "tslib": "^1.11.1" } }, "which": { @@ -2037,55 +2462,41 @@ "string-width": "^1.0.2 || 2" } }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^4.1.0" } } } @@ -2097,14 +2508,15 @@ "dev": true }, "write-file-atomic": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", - "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "y18n": { @@ -2113,29 +2525,22 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { - "cliui": "^4.0.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" + "yargs-parser": "^13.1.1" }, "dependencies": { "ansi-regex": { @@ -2167,9 +2572,9 @@ } }, "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -2177,59 +2582,21 @@ } }, "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", "dev": true, "requires": { "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" - }, - "dependencies": { - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } + "lodash": "^4.17.15", + "yargs": "^13.3.0" } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 4aff7da..a4e883a 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,20 @@ { "name": "node-webcrypto-ossl", - "version": "1.0.48", + "version": "2.0.0", "repository": { "type": "git", "url": "https://github.com/PeculiarVentures/node-webcrypto-ossl.git" }, "description": "A WebCrypto Polyfill for Node in TypeScript built on OpenSSL", - "main": "buildjs/webcrypto.js", + "main": "buildjs/index.js", + "module": "buildjs/index.es.js", "types": "index.d.ts", "scripts": { - "clean": "rm -rf build/ buildjs/ coverage/ .nyc_output/ npm-debug.log npm-debug.log.*", "prepare": "npm run build", "test": "mocha", - "build": "npm run build:es5", - "build:es5": "tsc", - "build:source": "tsc --sourceMap", - "build:es2015": "tsc --module es2015 --target es2015", + "clear": "rimraf buildjs", + "build": "rollup -c", + "rebuild": "npm run clear && npm run build", "pub": "npm version patch && npm publish && git push", "sync": "git ac && git pull --rebase && git push", "coverage": "nyc npm test", @@ -38,18 +37,50 @@ "secp256k1" ], "dependencies": { - "mkdirp": "^0.5.1", - "nan": "^2.13.2", - "tslib": "^1.9.3", - "webcrypto-core": "^0.1.26" + "mkdirp": "^1.0.3", + "nan": "^2.14.0", + "tslib": "^1.11.1", + "webcrypto-core": "^1.0.18" }, "devDependencies": { - "@types/mkdirp": "^0.5.2", - "@types/node": "^10.12.18", - "coveralls": "^3.0.3", - "mocha": "^6.1.4", - "nyc": "^14.0.0", - "pvtsutils": "^1.0.4", - "typescript": "^3.4.5" + "@peculiar/webcrypto-test": "^1.0.1", + "@types/mkdirp": "^1.0.0", + "@types/mocha": "^7.0.2", + "@types/node": "^12.12.30", + "@types/rimraf": "^2.0.3", + "coveralls": "^3.0.9", + "mocha": "^7.1.0", + "nyc": "^15.0.0", + "pvtsutils": "^1.0.10", + "rimraf": "^3.0.2", + "rollup": "^2.1.0", + "rollup-plugin-typescript2": "^0.26.0", + "ts-node": "^8.7.0", + "typescript": "^3.8.3" + }, + "nyc": { + "extension": [ + ".ts", + ".tsx" + ], + "include": [ + "lib/**/*.ts" + ], + "exclude": [ + "**/*.d.ts" + ], + "reporter": [ + "text-summary", + "html" + ] + }, + "mocha": { + "require": "ts-node/register", + "extension": [ + "ts" + ], + "watch-files": [ + "test/**/*.ts" + ] } } diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..f2a39c5 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,44 @@ +import typescript from "rollup-plugin-typescript2"; +// @ts-ignore +import pkg from "./package.json"; + +const banner = [ + "/**", + " * Copyright (c) 2020, Peculiar Ventures, All rights reserved.", + " */", + "", +].join("\n"); +const input = "lib/index.ts"; +const external = Object.keys(pkg.dependencies); + + +export default [ + // main + { + input, + plugins: [ + typescript({ + check: true, + clean: true, + tsconfigOverride: { + compilerOptions: { + module: "ES2015", + } + } + }), + ], + external, + output: [ + { + banner, + file: pkg.main, + format: "cjs", + }, + { + banner, + file: pkg.module, + format: "es", + }, + ], + }, +]; diff --git a/test/aes.js b/test/aes.js deleted file mode 100644 index 4e2bc4a..0000000 --- a/test/aes.js +++ /dev/null @@ -1,296 +0,0 @@ -"use strict"; -const assert = require('assert'); -const webcrypto = require('./config'); -const checkAlgorithms = require('./helper').checkAlgorithms; - -var keys = []; - -describe("WebCrypto Aes", function () { - - let BIG_MESSAGE; - let i = 0; - while (i++ < 200) - BIG_MESSAGE += "0123456789"; - var SMALL_MESSAGE = "1234567890123456"; - let messages = [ - { name: "small", data: SMALL_MESSAGE }, - { name: "big", data: BIG_MESSAGE }, - ]; - var KEYS = [ - { alg: "AES-ECB", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, - { alg: "AES-CBC", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, - { alg: "AES-CTR", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, - { alg: "AES-GCM", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, - { alg: "AES-KW", usages: ["wrapKey", "unwrapKey"] }, - ]; - - context("Generate key", () => { - - // Keys - KEYS.forEach(key => { - // length - [128, 192, 256].forEach(length => { - var keyName = `${key.alg} l:${length}`; - var keyTemplate = { - name: keyName, - key: null, - usages: key.usages, - }; - keys.push(keyTemplate); - it(keyName, done => { - var alg = { - name: key.alg, - length: length - }; - webcrypto.subtle.generateKey(alg, true, key.usages) - .then(aesKey => { - assert.equal(!!aesKey, true, "Aes key is empty"); - keyTemplate.key = aesKey; - }) - .then(done, done); - }); - }); - }) - - }); - - context("Encrypt/Decrypt", () => { - - context("AES-ECB", () => { - - // Filter ECB - keys.filter(key => /AES-ECB/.test(key.name)) - .forEach(key => { - messages.forEach(message => { - it(`${message.name} message\t${key.name}`, done => { - var alg = { name: "AES-ECB" }; - webcrypto.subtle.encrypt(alg, key.key, Buffer.from(message.data)) - .then(enc => { - assert.equal(!!enc, true, "Encrypted message is empty"); - return webcrypto.subtle.decrypt(alg, key.key, enc); - }) - .then(dec => { - assert.equal(Buffer.from(dec).toString(), message.data, "Decrypted message is wrong"); - }) - .then(done, done); - }); - }) - }); - }); - - context("AES-CBC", () => { - - // Filter CBC - keys.filter(key => /AES-CBC/.test(key.name)) - .forEach(key => { - messages.forEach(message => - [webcrypto.getRandomValues(new Uint8Array(16))].forEach(iv => { - it(`${message.name} message iv:${iv.length}\t${key.name}`, done => { - var alg = { name: "AES-CBC", iv: iv }; - webcrypto.subtle.encrypt(alg, key.key, Buffer.from(message.data)) - .then(enc => { - assert.equal(!!enc, true, "Encrypted message is empty"); - return webcrypto.subtle.decrypt(alg, key.key, enc); - }) - .then(dec => { - assert.equal(Buffer.from(dec).toString(), message.data, "Decrypted message is wrong"); - }) - .then(done, done); - }); - }) - ) - }); - }); - - context("AES-CTR", () => { - - // Filter CBC - keys.filter(key => /AES-CTR/.test(key.name)) - .forEach(key => { - messages.forEach(message => - [webcrypto.getRandomValues(new Uint8Array(16))].forEach(iv => { - it(`${message.name} message counter:${iv.length}\t${key.name}`, done => { - var alg = { name: "AES-CTR", counter: iv, length: 64 }; - webcrypto.subtle.encrypt(alg, key.key, Buffer.from(message.data)) - .then(enc => { - assert.equal(!!enc, true, "Encrypted message is empty"); - return webcrypto.subtle.decrypt(alg, key.key, enc); - }) - .then(dec => { - assert.equal(Buffer.from(dec).toString(), message.data, "Decrypted message is wrong"); - }) - .then(done, done); - }); - }) - ) - }); - }); - - context("AES-GCM", () => { - // Filter GCM - keys.filter(key => /AES-GCM/.test(key.name)) - .forEach(key => { - messages.forEach(message => - // IV - [new Uint8Array(16)].forEach(iv => { - // AAD - [new Uint8Array([1, 2, 3, 4, 5]), null].forEach(aad => { - // Tag - [32, 64, 96, 104, 112, 120, 128].forEach(tag => { - it(`${message.name} message aad:${aad ? "+" : "-"} t:${tag}\t${key.name}`, done => { - var alg = { name: "AES-GCM", iv: iv, aad: aad, tagLength: tag }; - webcrypto.subtle.encrypt(alg, key.key, Buffer.from(message.data)) - .then(enc => { - assert.equal(!!enc, true, "Encrypted message is empty"); - return webcrypto.subtle.decrypt(alg, key.key, enc); - }) - .then(dec => { - assert.equal(Buffer.from(dec).toString(), message.data, "Decrypted message is wrong"); - }) - .then(done, done); - }); - }); - }); - }) - ) - }); - }); - - }); - - context("Export/Import", () => { - - // Keys - keys.forEach(key => { - // Format - ["jwk", "raw"].forEach(format => { - it(`${format}\t${key.name}`, done => { - webcrypto.subtle.exportKey(format, key.key) - .then(jwk => { - assert.equal(!!jwk, true, "Has no jwk value"); - if (format === "jwk") - assert.equal(!!jwk.k, true, "Has no k value"); - else - assert.equal(!!jwk.byteLength, true, "Wrong raw length"); - return webcrypto.subtle.importKey(format, jwk, key.key.algorithm, true, key.key.usages); - }) - .then(k => { - assert.equal(!!k, true, "Imported key is empty") - assert.equal(!!k.native_, true, "Has no native key value"); - checkAlgorithms(key.algorithm, k.algorithm); - }) - .then(done, done); - }); - }); - }); - }); - - context("Wrap/Unwrap", () => { - context("AES-CBC", () => { - // AES keys - keys.filter(key => /AES-CBC/.test(key.name)).forEach(key => { - ["jwk", "raw"].forEach(format => { - it(`format:${format} ${key.name}`, done => { - var _alg = { name: "AES-CBC", iv: new Uint8Array(16) } - webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) - .then(wrappedKey => { - assert.equal(!!wrappedKey, true, "Wrapped key is empty"); - - return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["encrypt", "decrypt"]); - }) - .then(key => { - assert.equal(!!key, true, "Unwrapped key is empty"); - }) - .then(done, done); - }) - - }); - }); - }); - context("AES-CTR", () => { - // AES keys - keys.filter(key => /AES-CTR/.test(key.name)).forEach(key => { - ["jwk", "raw"].forEach(format => { - it(`format:${format} ${key.name}`, done => { - var _alg = { name: "AES-CTR", counter: new Uint8Array(16), length: 64 } - webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) - .then(wrappedKey => { - assert.equal(!!wrappedKey, true, "Wrapped key is empty"); - - return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["encrypt", "decrypt"]); - }) - .then(key => { - assert.equal(!!key, true, "Unwrapped key is empty"); - }) - .then(done, done); - }) - - }); - }); - }); - context("AES-ECB", () => { - // AES keys - keys.filter(key => /AES-ECB/.test(key.name)).forEach(key => { - ["jwk", "raw"].forEach(format => { - it(`format:${format} ${key.name}`, done => { - var _alg = { name: "AES-ECB" }; - webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) - .then(wrappedKey => { - assert.equal(!!wrappedKey, true, "Wrapped key is empty"); - - return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["encrypt", "decrypt"]); - }) - .then(key => { - assert.equal(!!key, true, "Unwrapped key is empty"); - }) - .then(done, done); - }) - - }); - }); - }); - context("AES-GCM", () => { - // AES keys - keys.filter(key => /AES-GCM/.test(key.name)).forEach(key => { - ["jwk", "raw"].forEach(format => { - it(`format:${format} ${key.name}`, done => { - var _alg = { name: "AES-GCM", iv: new Uint8Array(16) } - webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) - .then(wrappedKey => { - assert.equal(!!wrappedKey, true, "Wrapped key is empty"); - - return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["encrypt", "decrypt"]); - }) - .then(key => { - assert.equal(!!key, true, "Unwrapped key is empty"); - }) - .then(done, done); - }) - - }); - }); - }); - - context("AES-KW", () => { - keys.filter(key => /AES-KW/.test(key.name)).forEach(key => { - ["raw"].forEach(format => { - it(`format:${format} ${key.name}`, done => { - var _alg = { name: "AES-KW" } - webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) - .then(wrappedKey => { - assert.equal(!!wrappedKey, true, "Wrapped key is empty"); - - return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["wrapKey"]); - }) - .then(key => { - assert.equal(!!key, true, "Unwrapped key is empty"); - }) - .then(done, done); - }) - - }); - }); - }); - }); - -}) \ No newline at end of file diff --git a/test/config.js b/test/config.js deleted file mode 100644 index 6f62243..0000000 --- a/test/config.js +++ /dev/null @@ -1,4 +0,0 @@ -"use strict"; -var WebCrypto = require("../buildjs/webcrypto.js"); - -module.exports = new WebCrypto({directory: "test_storage"}) \ No newline at end of file diff --git a/test/crypto.js b/test/crypto.js deleted file mode 100644 index f9ca599..0000000 --- a/test/crypto.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -const assert = require('assert'); -const webcrypto = require('./config'); - -describe("WebCrypto", () => { - - it("get random values", () => { - var buf = new Uint8Array(16); - var check = Buffer.from(buf).toString("base64"); - assert.notEqual(Buffer.from(webcrypto.getRandomValues(buf)).toString("base64"), check, "Has no random values"); - }) - - it("get random values with large buffer", () => { - var buf = new Uint8Array(65600); - assert.throws(() => { - webcrypto.getRandomValues(buf); - }, Error); - }) -}) \ No newline at end of file diff --git a/test/crypto.ts b/test/crypto.ts new file mode 100644 index 0000000..7d3838e --- /dev/null +++ b/test/crypto.ts @@ -0,0 +1,33 @@ +import { WebcryptoTest } from "@peculiar/webcrypto-test"; +import * as assert from "assert"; +import {Crypto} from "../lib"; + +const crypto = new Crypto() as any; +WebcryptoTest.check(crypto, { + HKDF: true, + RSAESPKCS1: true, +}); + +context("Crypto", () => { + + context("getRandomValues", () => { + + it("Uint8Array", () => { + const array = new Uint8Array(5); + const array2 = crypto.getRandomValues(array); + + assert.notEqual(Buffer.from(array).toString("hex"), "0000000000"); + assert.equal(Buffer.from(array2).equals(array), true); + }); + + it("Uint16Array", () => { + const array = new Uint16Array(5); + const array2 = crypto.getRandomValues(array); + + assert.notEqual(Buffer.from(array).toString("hex"), "00000000000000000000"); + assert.equal(Buffer.from(array2).equals(Buffer.from(array)), true); + }); + + }); + +}); diff --git a/test/digest.js b/test/digest.js deleted file mode 100644 index 9c0f036..0000000 --- a/test/digest.js +++ /dev/null @@ -1,70 +0,0 @@ -"use strict"; -var assert = require('assert'); -var webcrypto = require('./config'); - -describe("WebCrypto digest", function () { - - context("Sha", function () { - - var vector = { - data: new Uint8Array([116, 101, 115, 116]), // "test" - algs: { - "SHA-1": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", - "SHA-256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", - "SHA-384": "768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9", - "SHA-512": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff", - } - }; - - var dataList = { - ArrayBuffer: vector.data.buffer, - Buffer: Buffer.from(vector.data), - Uint8Array: vector.data, - Uint16Array: new Uint16Array(vector.data.buffer), - Uint32Array: new Uint32Array(vector.data.buffer), - }; - - ["SHA-1", "SHA-256", "SHA-384", "SHA-512"].forEach(digestAlg => { - context(digestAlg, () => { - for (const type in dataList) { - (() => { - const data = dataList[type]; - - it(type, done => { - webcrypto.subtle.digest(digestAlg, data) - .then(function (hash) { - assert.equal(Buffer.from(hash).toString("hex").toLowerCase(), vector.algs[digestAlg]); - }) - .then(done, done); - }); - })(); - } - }); - }); - - context("Array", () => { - - it("subarray", (done) => { - const data = new Uint8Array([116, 101, 115, 116, 1, 2, 3, 4, 5]) - - webcrypto.subtle.digest("SHA-256", data.subarray(0, 4)) - .then(function (hash) { - assert.equal(Buffer.from(hash).toString("hex").toLowerCase(), vector.algs["SHA-256"]); - }) - .then(done, done); - }); - - it("slice", (done) => { - const data = new Uint8Array([116, 101, 115, 116, 1, 2, 3, 4, 5]) - - webcrypto.subtle.digest("SHA-256", data.slice(0, 4)) - .then(function (hash) { - assert.equal(Buffer.from(hash).toString("hex").toLowerCase(), vector.algs["SHA-256"]); - }) - .then(done, done); - }); - - }); - - }); -}); \ No newline at end of file diff --git a/test/ec.js b/test/ec.js deleted file mode 100644 index 5762a83..0000000 --- a/test/ec.js +++ /dev/null @@ -1,217 +0,0 @@ -"use strict"; -const assert = require('assert'); -const webcrypto = require('./config'); -const checkAlgorithms = require('./helper').checkAlgorithms; - -describe("WebCrypto EC", () => { - - var TEST_MESSAGE = Buffer.from("1234567890123456"); - var KEYS = [ - { alg: "ECDSA", usages: ["sign", "verify"] }, - { alg: "ECDH", usages: ["deriveKey", "deriveBits"] }, - ]; - var DIGEST = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]; - var NAMED_CURVES = ["P-256", "P-384", "P-521", "K-256"]; - - var keys = []; - - context("Generate key", () => { - - it("Params", done => { - webcrypto.subtle.generateKey( - { name: "ECDSA", namedCurve: "P-256" }, - false, - ["sign"] - ) - .then(keyPair => { - let pkey = keyPair.privateKey; - assert.equal(pkey.type, "private"); - assert.equal(pkey.algorithm.name, "ECDSA"); - assert.equal(pkey.algorithm.namedCurve, "P-256"); - assert.equal(pkey.extractable, false); - assert.equal(pkey.usages.toString(), "sign"); - - let pubKey = keyPair.publicKey; - assert.equal(pubKey.type, "public"); - assert.equal(pubKey.algorithm.name, "ECDSA"); - assert.equal(pubKey.algorithm.namedCurve, "P-256"); - assert.equal(pubKey.extractable, true); - assert.equal(pubKey.usages.toString(), ""); - }) - .then(done, done); - }); - - // Keys - KEYS.forEach(key => { - // namedCurve - NAMED_CURVES.forEach(namedCurve => { - var keyName = `${key.alg} crv:${namedCurve}` - var keyTemplate = { - name: keyName, - privateKey: null, - publicKey: null, - usages: key.usages, - } - keys.push(keyTemplate); - it(keyName, done => { - var alg = { - name: key.alg, - namedCurve: namedCurve - }; - webcrypto.subtle.generateKey(alg, true, key.usages) - .then(keyPair => { - assert.equal(!!(keyPair.privateKey || keyPair.publicKey), true, "KeyPair is empty"); - // save keys for next tests - keyTemplate.privateKey = keyPair.privateKey; - keyTemplate.publicKey = keyPair.publicKey; - - return Promise.resolve(); - }) - .then(done, done); - }); - }); - }); - }); - - context("Sign/Verify", () => { - - keys.filter(key => key.usages.some(usage => usage === "sign")) - .forEach(key => { - // Hash - DIGEST.forEach(hash => { - it(`${hash}\t${key.name}`, done => { - var alg = { name: key.privateKey.algorithm.name, hash: { name: hash } }; - webcrypto.subtle.sign(alg, key.privateKey, TEST_MESSAGE) - .then(sig => { - assert.equal(!!sig, true, "Has no signature value"); - assert.notEqual(sig.length, 0, "Has empty signature value"); - return webcrypto.subtle.verify(alg, key.publicKey, sig, TEST_MESSAGE) - }) - .then(v => assert.equal(v, true, "Signature is not valid")) - .then(done, done); - }); - }); - }); - }); - - context("Derive key", () => { - - keys.filter(key => key.usages.some(usage => usage === "deriveKey")) - .forEach(key => { - // AES alg - ["AES-CBC", "AES-GCM"].forEach(aesAlg => { - // AES length - [128, 192, 256].forEach(aesLength => { - it(`${aesAlg}-${aesLength}\t${key.name}`, done => { - var alg = { - name: key.privateKey.algorithm.name, - public: key.publicKey - }; - webcrypto.subtle.deriveKey(alg, key.privateKey, { name: aesAlg, length: aesLength }, true, ["encrypt"]) - .then(aesKey => { - assert.equal(!!aesKey, true, "Has no derived key"); - assert.equal(aesKey.algorithm.length, aesLength, "Has wrong derived key length"); - assert.equal(aesKey.usages.length, 1, "Has wrong key usages length"); - assert.equal(aesKey.usages[0], "encrypt", "Has wrong key usage"); - }) - .then(done, done); - }); - }); - }); - }); - }); - - context("Derive bits", () => { - - keys.filter(key => key.usages.some(usage => usage === "deriveBits")) - .forEach(key => { - // length - [56, 96, 128, 192, 256].forEach(bitsLength => { - it(`bits:${bitsLength} \t${key.name}`, done => { - var alg = { - name: key.privateKey.algorithm.name, - public: key.publicKey - }; - webcrypto.subtle.deriveBits(alg, key.privateKey, bitsLength) - .then(bits => { - assert.equal(!!bits, true, "Has no derived bits"); - assert.equal(bits.byteLength, bitsLength / 8, "Has wrong derived bits length"); - }) - .then(done, done); - }); - }); - }); - }); - - context("Export/Import", () => { - - // Keys - keys.forEach(key => { - // Format - ["jwk", "spki", "pkcs8", "raw"].forEach(format => { - it(`${format}\t${key.name}`, done => { - var promise = Promise.resolve(); - // Check public and private keys - [key.privateKey, key.publicKey].forEach(_key => { - if ( - (format === "raw" && _key.type === "public") || - (format === "spki" && _key.type === "public") || - (format === "pkcs8" && _key.type === "private") || - (format === "jwk") - ) - promise = promise.then(() => { - return webcrypto.subtle.exportKey(format, _key) - .then(jwk => { - assert.equal(!!jwk, true, "Has no jwk value"); - if(format === "raw") { - // TODO assert JWK params - } - return webcrypto.subtle.importKey(format, jwk, _key.algorithm, true, _key.usages); - }) - }) - .then(k => { - assert.equal(!!k, true, "Imported key is empty"); - checkAlgorithms(_key.algorithm, k.algorithm); - }) - }); - promise.then(done, done); - }); - }); - }); - }); - - context("Combined test", () => { - ["jwk", "spki", "raw"].forEach(format => { - it(`${format}\tECDH generateKey + exportKey + importKey + deriveBits`, done => { - - webcrypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) - .then(function(key1){ - webcrypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) - .then(function(key2){ - webcrypto.subtle.exportKey(format ,key1.publicKey) - .then(function(keyData1){ - webcrypto.subtle.exportKey(format ,key2.publicKey) - .then(function(keyData2){ - webcrypto.subtle.importKey(format , keyData1, { name: "ECDH", namedCurve: "P-256" }, true, []) - .then(function(pub1){ - webcrypto.subtle.importKey(format , keyData2, { name: "ECDH", namedCurve: "P-256" }, true, []) - .then(function(pub2){ - webcrypto.subtle.deriveBits({ name: "ECDH", namedCurve: "P-256", public: pub1 }, key2.privateKey, 128) - .then(function(bits1){ - webcrypto.subtle.deriveBits({ name: "ECDH", namedCurve: "P-256", public: pub2 }, key1.privateKey, 128) - .then(function(bits2){ - assert.deepEqual(new Uint8Array(bits1), new Uint8Array(bits2), "derive Bits not equal"); - }).then(done, done); - }); - }); - }); - }); - }); - }); - }); - - }); - }); - }); - -}); diff --git a/test/helper.js b/test/helper.js deleted file mode 100644 index 30d61f8..0000000 --- a/test/helper.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict" -const assert = require("assert"); - -function checkAlgorithms(alg1, alg2) { - assert.equal(!!alg2, true, "Empty CryptoKey algorithm"); - for (let i in alg1) { - if (ArrayBuffer.isView(alg1[i])) - checkBuffers(alg1[i], alg2[i]); - else - assert.equal(alg1[i], alg2[i]); - } -} - -exports.checkAlgorithms = checkAlgorithms; - -function checkBuffers(buf1, buf2) { - let _buf1 = new Uint8Array(buf1); - let _buf2 = new Uint8Array(buf2); - - assert.equal(_buf1.length, _buf2.length); - // check values - _buf1.forEach((v, i) => { - assert.equal(v, _buf2[i], "Buffers have different values"); - }); -} - -exports.checkBuffers = checkBuffers; - -function PromiseThrows(promise, done) { - promise - .then(() => { - return true; - }) - .catch((e) => { - assert.equal(!!e, true); - return false; - }) - .then((error) => { - if (error) - throw new Error("Must be error"); - }) - .then(done, done); -} - -exports.PromiseThrows = PromiseThrows; \ No newline at end of file diff --git a/test/hmac.js b/test/hmac.js deleted file mode 100644 index e5c38a2..0000000 --- a/test/hmac.js +++ /dev/null @@ -1,104 +0,0 @@ -"use strict"; -const assert = require('assert'); -const webcrypto = require('./config'); -const checkAlgorithms = require('./helper').checkAlgorithms; -const subtle = webcrypto.subtle; - -const keys = []; -const message = Buffer.from("test message"); -const message_error = Buffer.from("test message!!!"); - -describe("WebCrypto", function () { - - context("HMAC", () => { - - context("generate", () => { - - // key length - [0, 128, 256, 512].forEach(length => { - // hash - ["SHA-1", "SHA-256", "SHA-384", "SHA-512"].forEach(hash => { - - let hmac = { key: null, name: `length:${length ? length : "default"} hash:${hash}`, length: length }; - keys.push(hmac); - - it(`${hmac.name}`, done => { - const alg = { name: "HMAC", hash: hash }; - if (length) - alg.length = length; - else - hmac.length = hash === "SHA-1" ? 160 : hash === "SHA-256" ? 256 : hash === "SHA-384" ? 384 : 512; - - subtle.generateKey(alg, true, ["sign", "verify"]) - .then(key => { - assert(!!key, true); - assert(!!key.native, true); - hmac.key = key; - }) - .then(done, done); - }); - }); - }); - - }); - - context("export/import", () => { - keys.forEach(hmac => { - // format - ["jwk", "raw"].forEach(format => { - it(`${hmac.name} format:${format}`, done => { - subtle.exportKey(format, hmac.key) - .then(data => { - switch (format) { - case "raw": - assert.equal(data.byteLength * 8, hmac.length); - break - case "jwk": - assert.equal(data.alg === "HS" + /(\d+)/.exec(hmac.key.algorithm.hash.name)[1], true); - break - } - // console.log(hmac.key); - return subtle.importKey(format, data, hmac.key.algorithm, true, hmac.key.usages) - }) - .then(k => { - assert.equal(!!k, true); - assert.equal(!!k.native, true); - checkAlgorithms(hmac.key.algorithm, k.algorithm); - done(); - }) - .catch(done); - }); - }); - }); - }); - - context("sign/verify", () => { - keys.forEach(hmac => { - const alg = { name: "HMAC" }; - - it(hmac.name, done => { - let sig; - subtle.sign(alg, hmac.key, message) - .then(signature => { - assert.equal(!!signature, true); - sig = signature; - return subtle.verify(alg, hmac.key, signature, message) - }) - .then(res => { - assert.equal(res, true); - return subtle.verify(alg, hmac.key, sig, message_error) - }) - .then(res => { - assert.equal(res, false); - done(); - }) - .catch(done); - - }); - - }); - }); - - }); // HMAC - -}); // WebCrypto \ No newline at end of file diff --git a/test/key_storage.js b/test/key_storage.js deleted file mode 100644 index e37b1b6..0000000 --- a/test/key_storage.js +++ /dev/null @@ -1,129 +0,0 @@ -"use strict"; - -var assert = require("assert"); -var fs = require("fs"); -var webcrypto = require("./config"); - -var deleteFolderRecursive = function (path) { - if (fs.existsSync(path)) { - fs.readdirSync(path).forEach(function (file, index) { - var curPath = path + "/" + file; - if (fs.lstatSync(curPath).isDirectory()) { // recursion - deleteFolderRecursive(curPath); - } else { // delete file - fs.unlinkSync(curPath); - } - }); - fs.rmdirSync(path); - } -}; - -describe("Key storage", function () { - - var TEST_MESSAGE = Buffer.from("This is test message for crypto functions"); - var KEYS = [{ name: "private" }, { name: "public" }, { name: "secret" }]; - - before((done) => { - // Generate keys for storeKey - webcrypto.subtle.generateKey({ - name: "RSASSA-PKCS1-v1_5", - modulusLength: 1024, - publicExponent: new Uint8Array([1, 0, 1]), - hash: { - name: "SHA-1" - }, - }, - true, - ["sign", "verify"] - ) - .then((keyPair) => { - KEYS[0].key = keyPair.privateKey; - KEYS[1].key = keyPair.publicKey; - - return webcrypto.subtle.generateKey({ - name: "AES-CBC", - length: 128, - }, - true, - ["encrypt", "decrypt"] - ) - }) - .then((key) => { - KEYS[2].key = key; - }) - .then(done, done); - }); - - after(function () { - deleteFolderRecursive("test_storage"); - }) - - KEYS.forEach(key => { - it(`Set/get key from storage ${key.name}`, () => { - if (key.name === "secret") - return console.log(`Not implemented test`); - webcrypto.keyStorage.setItem(key.key.type, key.key); - var exists = fs.existsSync(webcrypto.keyStorage.directory + `/${key.key.type}.json`); - assert.equal(exists, true, "File with key is not created"); - - var storeKey = webcrypto.keyStorage.getItem(key.key.type); - }) - }); - - it("Set secret key", () => { - const key = { type: "secret" }; - assert.throws(() => { - webcrypto.keyStorage.setItem("secret_key", key) - }); - }); - - it("Set unknown key type", () => { - const key = { type: "wrong type" }; - assert.throws(() => { - webcrypto.keyStorage.setItem("secret_key", key) - }); - }) - - it("Get non-existent item, must be null", () => { - assert.equal(webcrypto.keyStorage.getItem("null"), null); - }) - - it("read storage from folder", () => { - let WebCrypto = require("../buildjs/webcrypto"); - let crypto = new WebCrypto({ directory: "test_storage" }); - assert.equal(crypto.keyStorage.length, 2); - }); - - it("Remove key from storage", function (done) { - var key = null; - webcrypto.subtle.generateKey({ - name: "RSASSA-PKCS1-v1_5", - modulusLength: 1024, - publicExponent: new Uint8Array([1, 0, 1]), - hash: { - name: "SHA-1" - }, - }, - true, - ["sign", "verify"] - ) - .then(function (keyPair) { - webcrypto.keyStorage.setItem("remove_key", keyPair.privateKey); - var exists = fs.existsSync(webcrypto.keyStorage.directory + "/remove_key.json"); - assert.equal(exists, true, "File with key is not created"); - assert.equal(webcrypto.keyStorage.length, 3); - - webcrypto.keyStorage.removeItem("remove_key"); - var exists = fs.existsSync(webcrypto.keyStorage.directory + "/remove_key.json"); - assert.equal(exists, false, "File with key is not removed"); - assert.equal(webcrypto.keyStorage.length, 2); - return Promise.resolve(); - }) - .then(done, done); - }); - - it("Clear key storage", function () { - webcrypto.keyStorage.clear(); - assert.equal(webcrypto.keyStorage.length, 0); - }); -}); \ No newline at end of file diff --git a/test/key_storage.ts b/test/key_storage.ts new file mode 100644 index 0000000..f3c7f9d --- /dev/null +++ b/test/key_storage.ts @@ -0,0 +1,76 @@ +import * as assert from "assert"; +import * as os from "os"; +import * as path from "path"; +import * as rimraf from "rimraf"; +import { Crypto } from "../lib"; + +const tmpDir = path.join(os.tmpdir(), "node-webcrypto-test"); +const crypto = new Crypto({ + directory: tmpDir, +}); + +context("Crypto key storage", () => { + + after((done) => { + rimraf(tmpDir, done); + }); + + context("Set/get item", () => { + it("asymmetric", async () => { + const alg: EcKeyGenParams = { name: "ECDSA", namedCurve: "P-256" }; + const keys = await crypto.subtle.generateKey(alg, false, ["sign", "verify"]) as CryptoKeyPair; + + const index1 = await crypto.keyStorage.setItem(keys.privateKey); + const index2 = await crypto.keyStorage.setItem(keys.publicKey); + + const indexes = await crypto.keyStorage.keys(); + assert.equal(indexes.includes(index1), true); + assert.equal(indexes.includes(index2), true); + }); + + it("symmetric", async () => { + const alg: AesKeyGenParams = { name: "AES-CBC", length: 128 }; + const key = await crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]) as CryptoKey; + + const index = await crypto.keyStorage.setItem(key); + + const indexes = await crypto.keyStorage.keys(); + assert.equal(indexes.includes(index), true); + + crypto.keyStorage.hasItem(key); + }); + }); + + it("remove", async () => { + const alg: AesKeyGenParams = { name: "AES-CBC", length: 128 }; + const key = await crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]) as CryptoKey; + + const index = await crypto.keyStorage.setItem(key); + await crypto.keyStorage.removeItem(index); + + const indexes = await crypto.keyStorage.keys(); + assert.equal(indexes.includes(index), false); + }); + + it("clear", async () => { + const alg: RsaHashedKeyGenParams = { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, + publicExponent: new Uint8Array([1, 0, 1]), + hash: "SHA-256", + }; + const keys = await crypto.subtle.generateKey(alg, false, ["sign", "verify"]) as CryptoKeyPair; + + const index1 = await crypto.keyStorage.setItem(keys.privateKey); + await crypto.keyStorage.setItem(keys.publicKey); + + const index = await crypto.keyStorage.indexOf(keys.privateKey); + assert.equal(index, index1); + + await crypto.keyStorage.clear(); + + const indexes = await crypto.keyStorage.keys(); + assert.equal(indexes.length, 0); + }); + +}); diff --git a/test/native.js b/test/native.js deleted file mode 100644 index 775cace..0000000 --- a/test/native.js +++ /dev/null @@ -1,509 +0,0 @@ -"use strict"; -var assert = require('assert'); -var native = require("../buildjs/native"); - -describe("native", function () { - - var TEST_MESSAGE = Buffer.from("Hello world"); - - function test_export(key, spki, done) { - var export_fn, import_fn, error_text; - if (spki) { - export_fn = key.exportSpki; - import_fn = native.Key.importSpki; - error_text = "SPKI"; - } - else { - export_fn = key.exportPkcs8; - import_fn = native.Key.importPkcs8; - error_text = "PKCS8" - } - - export_fn.call(key, function (err, rawA) { - assert.equal(!err, true, `${error_text}::Export: ${err}`); - import_fn(rawA, function (err, key) { - assert.equal(!err, true, `${error_text}::Import: ${err}`); - export_fn.call(key, function (err, rawB) { - assert.equal(!err, true, `${error_text}::Export: ${err}`); - assert.equal(Buffer.compare(rawA, rawB), 0, `${error_text}::Export: export values are different`); - done(); - }); - }) - }) - } - - it("generate RSA 1024,3", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - done(); - }) - }) - - it("generate RSA 2048,F4", function (done) { - native.Key.generateRsa(2048, native.RsaPublicExponent.RSA_F4, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - done(); - }) - }).timeout(30e3) - - it("generate RSA error", function (done) { - native.Key.generateRsa(1024, 3, function (err, key) { - assert.equal(err != null, true, "Must be error on key generation"); - done(); - }) - }) - - it("jwk RSA private", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - key.exportJwk(native.KeyType.PRIVATE, function (err, jwk) { - assert.equal(jwk != null, true, "Error on key export"); - assert.equal(jwk.kty, "RSA"); - assert.equal(jwk.d != null, true, "Key is not private"); - native.Key.importJwk(jwk, native.KeyType.PRIVATE, function (err, key) { - assert.equal(key != null, true, "Error on key import"); - done(); - }) - }) - }) - }) - - it("jwk RSA public", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - key.exportJwk(native.KeyType.PUBLIC, function (err, jwk) { - assert.equal(jwk != null, true, "Error on key export"); - assert.equal(jwk.kty, "RSA"); - assert.equal(jwk.d == null, true, "Key is private"); - native.Key.importJwk(jwk, native.KeyType.PUBLIC, function (err, key) { - assert.equal(key != null, true, "Error on key import"); - done(); - }) - }) - }) - }) - - it("spki RSA", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - test_export(key, true, done); - }) - }) - - it("pkcs8 RSA", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - test_export(key, false, done); - }) - }) - - function test_sign(key, md, done) { - var message = Buffer.from("This is test message for crypto functions"); - - key.sign(md, message, function (err, sig) { - assert.equal(sig != null, true, "Error on sign"); - key.verify(md, message, sig, function (err, v) { - assert.equal(v, true, "Signature is not valid"); - done(); - }) - }) - } - - it("sign RSA sha1", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - assert.equal(err == null, true, "error on sign"); - test_sign(key, "sha1", done); - }); - }) - - function test_rsa_oaep_enc_dec(md, message, label, done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - key.RsaOaepEncDec(md, message, label, false, function (err, dec) { - assert.equal(dec != null, true, "Error on encrypt"); - key.RsaOaepEncDec(md, dec, label, true, function (err, msg) { - assert.equal(msg != null, true, "Error on decrypt"); - assert.equal(Buffer.compare(msg, message) === 0, true, "Wrong result value"); - done(); - }) - }) - }) - } - - it("encrypt RSA OAEP without label", function (done) { - test_rsa_oaep_enc_dec("sha1", Buffer.from("Hello world"), null, done); - }) - - it("encrypt RSA OAEP with label", function (done) { - test_rsa_oaep_enc_dec("sha1", Buffer.from("Hello world"), Buffer.from("1234567890"), done); - }) - - it("generate EC secp256k1", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - done(); - }) - }) - - function test_sign_ec(curve, md, done) { - native.Key.generateEc(native.EcNamedCurves[curve], function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - test_sign(key, md, done); - }) - } - - it("sign EC secp256r1 sha256", function (done) { - test_sign_ec("secp256r1", "sha256", done); - }) - - it("sign EC secp384r1 sha256", function (done) { - test_sign_ec("secp384r1", "sha256", done); - }) - - it("sign EC secp521r1 sha256", function (done) { - test_sign_ec("secp521r1", "sha256", done); - }) - - function test_derive_key_ec(curve, keySize, done) { - native.Key.generateEc(native.EcNamedCurves[curve], function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - key.EcdhDeriveKey(key, keySize, function (err, b) { - assert.equal(b != null, true, "Error on key derive"); - // console.log(b.toString("hex")); - done(); - }) - }) - } - - it("deriveKey EC secp256r1 -> AES 256", function (done) { - test_derive_key_ec("secp256r1", 32, done); - }) - - it("deriveKey EC secp384r1 -> AES 256", function (done) { - test_derive_key_ec("secp384r1", 32, done); - }) - - it("deriveKey EC secp521r1 -> AES 256", function (done) { - test_derive_key_ec("secp521r1", 32, done); - }) - - function jwk_equal(a, b) { - var json1 = JSON.stringify(a); - var json2 = JSON.stringify(b); - return json1 == json2; - } - - function test_ec_jwk(curveName, keyType, done) { - - var curve = native.EcNamedCurves[curveName] - assert.equal(curve != null, true, "Unknown curve name"); - - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - key.exportJwk(keyType, function (err, jwkA) { - assert.equal(!err, true, "Export: " + err); - assert.equal(jwkA.kty, "EC", "Export: Wrong key type value"); - assert.equal(jwkA.crv == curve, true, "Export: Wrong curve name value"); - assert.equal(jwkA.x != null, true, "Export: X is missing"); - assert.equal(jwkA.y != null, true, "Export: Y is missing"); - assert.equal(jwkA.d != null, keyType == native.KeyType.PRIVATE, "Export: Key is missing"); - native.Key.importJwk(jwkA, keyType, function (err, key) { - assert.equal(!err, true, "Import: " + err); - key.exportJwk(keyType, function (err, jwkB) { - assert.equal(!err, true, "Export: " + err); - assert.equal(jwk_equal(jwkA, jwkB), true, "export values are different"); - done(); - }); - }) - }) - }) - } - - it("jwk EC private secp256k1", function (done) { - test_ec_jwk("secp256k1", native.KeyType.PRIVATE, done); - }) - - it("jwk EC public secp256k1", function (done) { - test_ec_jwk("secp256k1", native.KeyType.PUBLIC, done); - }) - - it("spki EC", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - test_export(key, true, done); - }) - }) - - it("pkcs8 EC", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - test_export(key, false, done); - }) - }) - - it("AES generate 128", function (done) { - native.AesKey.generate(16, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - done(); - }); - }) - - it("AES generate 196", function (done) { - native.AesKey.generate(24, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - done(); - }); - }) - - it("AES generate 256", function (done) { - native.AesKey.generate(32, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - done(); - }); - }) - - it("AES CBC encrypt 256", function (done) { - var msg = Buffer.from("Hello world"); - native.AesKey.generate(32, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - key.encrypt("CBC", Buffer.from("1234567890123456"), msg, function (err, data) { - assert.equal(!err, true, `encrypt: ${err}`); - key.decrypt("CBC", Buffer.from("1234567890123456"), data, function (err, m) { - assert.equal(!err, true, `decrypt: ${err}`); - assert.equal(msg.toString(), m.toString()); - done(); - }); - }); - }); - }) - - it("AES CBC encrypt 256 error", function (done) { - var msg = Buffer.from("Hello world"); - native.AesKey.generate(32, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - key.encrypt("CBC", Buffer.from("1234567890123456"), msg, function (err, data) { - assert.equal(!err, true, `encrypt: ${err}`); - data[0] += 1; - key.decrypt("CBC", Buffer.from("1234567890123456"), data, function (err, m) { - assert.equal(!!err, true, `must be error`); - done(); - }); - }); - }); - }) - - it("AES export", function (done) { - var raw; - native.AesKey.generate(32, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - key.export(function (err, r) { - assert.equal(!err, true, `export: ${err}`); - assert.equal(r.length, 32, `export: wrong key length`); - raw = r; - native.AesKey.import(r, function (err, key) { - assert.equal(!err, true, `import: ${err}`); - key.export(function (err, r) { - assert.equal(!err, true, `export: ${err}`); - assert.equal(Buffer.compare(raw, r) == 0, true, "exported data is not equal"); - done(); - }); - }); - }); - }); - }) - - context("AES-KW", () => { - - it("WrapKey small data", done => { - native.AesKey.generate(32, (err, key) => { - assert.equal(!err, true, `generate: ${err}`); - key.wrapKey(Buffer.from("123456789012345"), (err, data) => { - assert.equal(!!err, true); - done(); - }); - }); - }); - - it("UnwrapKey small data", done => { - native.AesKey.generate(32, (err, key) => { - assert.equal(!err, true, `generate: ${err}`); - key.unwrapKey(Buffer.from("12345678901234567890123"), (err, data) => { - assert.equal(!!err, true); - done(); - }); - }); - }); - - it("WrapKey data is not % 8", done => { - native.AesKey.generate(32, (err, key) => { - assert.equal(!err, true, `generate: ${err}`); - key.wrapKey(Buffer.from("12345678901234567"), (err, data) => { - assert.equal(!!err, true); - done(); - }); - }); - }); - - it("UnwrapKey data is not % 8", done => { - native.AesKey.generate(32, (err, key) => { - assert.equal(!err, true, `generate: ${err}`); - key.unwrapKey(Buffer.from("1234567890123456789012346"), (err, data) => { - assert.equal(!!err, true); - done(); - }); - }); - }); - - [128, 192, 256].forEach(length => { - it(`wrap/unwrap length:${length}`, done => { - let MSG = Buffer.alloc(length / 8); - native.AesKey.generate(length / 8, (err, key) => { - assert.equal(!err, true, `generate: ${err}`); - key.wrapKey(MSG, (err, data) => { - assert.equal(!err, true, "Cannot wrap key"); - key.unwrapKey(data, (err, data) => { - assert.equal(!err, true, "Cannot unwrap key"); - assert.equal(data.toString("hex"), MSG.toString("hex"), "Cannot unwrap key"); - done(); - }); - }); - }); - }); - }); - - }); - - function test_encrypt_gcm(keySize, aad, tag, done) { - var msg = Buffer.from("Hello world"); - native.AesKey.generate(keySize, function (err, key) { - assert.equal(!err, true, `generate: ${err}`); - key.encryptGcm(Buffer.from("1234567890123456"), msg, aad, tag, function (err, data) { - assert.equal(!err, true, `encrypt: ${err}`); - key.decryptGcm(Buffer.from("1234567890123456"), data, aad, tag, function (err, m) { - assert.equal(!err, true, `decrypt: ${err}`); - assert.equal(Buffer.compare(msg, m) == 0, true, "Decrypt: Decrypted data is not equal"); - done(); - }); - }); - }); - } - - it("AES GCM encrypt 192 AAD, tag(16)", function (done) { - test_encrypt_gcm(24, Buffer.from("1234567890123456"), 16, done); - }) - - it("AES GCM encrypt 192 no AAD, tag(4)", function (done) { - test_encrypt_gcm(24, Buffer.from(""), 4, done); - }) - - it("AES GCM encrypt 256 AAD, tag(16)", function (done) { - test_encrypt_gcm(32, Buffer.from("1234567890123456"), 16, done); - }) - - it("AES GCM encrypt 256 no AAD, tag(13)", function (done) { - test_encrypt_gcm(32, Buffer.from(""), 13, done); - }) - - function test_digest(md, mdLen, done) { - native.Core.digest(md, TEST_MESSAGE, function (err, digest) { - assert.equal(!err, true, err); - assert.equal(digest.length, mdLen, "Wrong digest length"); - done() - }); - } - - it("digest sha1", function (done) { - test_digest("sha1", 20, done); - }) - - it("digest sha256", function (done) { - test_digest("sha256", 32, done); - }) - - it("digest sha512", function (done) { - test_digest("sha512", 64, done); - }) - - it("digest wrong name", function (done) { - native.Core.digest("wrong name", TEST_MESSAGE, function (err, digest) { - assert.equal(err != null, true, "Error is NULL"); - done() - }); - }) - - it("native RSA Key export/import jwk sync", function (done) { - native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { - assert.equal(err == null, true, "error on key generation"); - // export key PRIVATE - var jwk = key.exportJwk(native.KeyType.PRIVATE); - assert.equal(!!jwk, true, "Can not export jwk"); - // import key PRIVATE - var new_key = native.Key.importJwk(jwk, native.KeyType.PRIVATE); - assert.equal(!!new_key, true, "Can not import jwk"); - - // export key PUBLIC - var jwk = key.exportJwk(native.KeyType.PUBLIC); - assert.equal(!!jwk, true, "Can not export jwk"); - // import key PUBLIC - var new_key = native.Key.importJwk(jwk, native.KeyType.PUBLIC); - assert.equal(!!new_key, true, "Can not import jwk"); - done(); - }) - }); - - it("native EC Key export/import jwk sync", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - assert.equal(err == null, true, "error on key generation"); - // export key PRIVATE - var jwk = key.exportJwk(native.KeyType.PRIVATE); - assert.equal(!!jwk, true, "Can not export jwk"); - // import key PRIVATE - var new_key = native.Key.importJwk(jwk, native.KeyType.PRIVATE); - assert.equal(!!new_key, true, "Can not import jwk"); - - // export key PUBLIC - var jwk = key.exportJwk(native.KeyType.PUBLIC); - assert.equal(!!jwk, true, "Can not export jwk"); - // import key PUBLIC - var new_key = native.Key.importJwk(jwk, native.KeyType.PUBLIC); - assert.equal(!!new_key, true, "Can not import jwk"); - done(); - }) - }); - - it("EC deriveBits P-256 256", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - key.EcdhDeriveBits(key, 256, function (err, bits) { - if (!err) - assert.equal(bits.length, 256 / 8); - done(err); - }); - }) - }); - - it("EC deriveBits P-256 128", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - key.EcdhDeriveBits(key, 128, function (err, bits) { - if (!err) - assert.equal(bits.length, 128 / 8); - done(err); - }); - }) - }); - - it("EC deriveBits P-256 512, error", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - key.EcdhDeriveBits(key, 512, function (err, bits) { - assert.equal(!!err, true, "Should be error"); - done(); - }); - }) - }); - - it("EC deriveBits P-521 528, error", function (done) { - native.Key.generateEc(native.EcNamedCurves.secp521r1, function (err, key) { - assert.equal(key != null, true, "Error on key generation"); - key.EcdhDeriveBits(key, 528, function (err, bits) { - if (!err) - assert.equal(bits.length, 528 / 8); - done(err); - }); - }) - }); - -}) \ No newline at end of file diff --git a/test/native/pbkdf2.js b/test/native/pbkdf2.js deleted file mode 100644 index ada3f7b..0000000 --- a/test/native/pbkdf2.js +++ /dev/null @@ -1,70 +0,0 @@ -"use strict"; - -var assert = require('assert'); -var native = require("../../buildjs/native"); - -describe("native", () => { - - context("importKey", () => { - - [0, 8, 16, 32, 33].forEach(length => { - it(`raw length:${length}`, done => { - native.Pbkdf2Key.importKey(Buffer.alloc(length), (err, key) => { - assert.equal(!err, true); - assert.equal(!!key, true); - assert.equal(key instanceof native.Pbkdf2Key, true); - done(); - }); - }); - }); - - }); - - context("deriveBits", () => { - - ["sha1", "sha256", "sha384", "sha512"].forEach(hash => { - it(hash, done => { - native.Pbkdf2Key.importKey(Buffer.from("123456"), (err, key) => { - assert.equal(!err, true); - key.deriveBits(hash, Buffer.from("salt"), 8, 128, (err, bits) => { - assert.equal(!err, true); - assert.equal(!!bits, true); - assert.equal(bits.byteLength, 16); - done() - }); - }); - }); - }); - - it("Wrong hash", done => { - native.Pbkdf2Key.importKey(Buffer.from("123456"), (err, key) => { - assert.equal(!err, true); - key.deriveBits("wrong", Buffer.from("salt"), 8, 128, (err, bits) => { - assert.equal(!err, false); - done() - }); - }); - }); - - it("Iterations 0", done => { - native.Pbkdf2Key.importKey(Buffer.from("123456"), (err, key) => { - assert.equal(!err, true); - key.deriveBits("sha1", Buffer.from("salt"), 0, 128, (err, bits) => { - assert.equal(!err, false); - done() - }); - }); - }); - - it("Bits length 0", done => { - native.Pbkdf2Key.importKey(Buffer.from("123456"), (err, key) => { - assert.equal(!err, true); - key.deriveBits("sha1", Buffer.from("salt"), 8, 0, (err, bits) => { - assert.equal(!err, false); - done() - }); - }); - }); - - }); -}); \ No newline at end of file diff --git a/test/native_hmac.js b/test/native_hmac.js deleted file mode 100644 index 02fe0f7..0000000 --- a/test/native_hmac.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; -var assert = require('assert'); -var native = require("../buildjs/native"); - -describe("native", function () { - - var TEST_MESSAGE = Buffer.from("Hello world"); - var TEST_MESSAGE_WRONG = Buffer.from("Hello world!!!"); - - context("HMAC", () => { - - let keys = []; - - [0, 128, 256, 512].forEach((length, index) => { - let hmac = { - length: length, - key: null - } - if (length) - keys.push(hmac) - it(`generate length:${length}`, done => { - native.HmacKey.generate(length, (err, data) => { - assert.equal(!!err, !length, err); - assert.equal(!!data, !!length, "Data is empty"); - if (length) - hmac.key = data; - done(); - }); - }); - }); - - context("export/import", () => { - keys.forEach(hmac => { - it(`length:${hmac.length}`, done => { - hmac.key.export((err, data) => { - assert.equal(!!data, true); - assert.equal(data.length * 8, hmac.length); - native.HmacKey.import(data, (err, key) => { - assert.equal(!!data, true); - key.export((err, data2) => { - assert.equal(!!data2, true); - assert.equal(data2.length * 8, hmac.length); - assert.equal(data2.toString("hex"), data.toString("hex")); - done(); - }); - }); - }); - }); - - }); - }); - - context("sign/verify", () => { - keys.forEach(hmac => { - it(`length:${hmac.length}`, done => { - hmac.key.sign("sha1", TEST_MESSAGE, (err, signature1) => { - assert.equal(!!err, false, err); - assert.equal(signature1.length > 0, true); - hmac.key.verify("sha1", TEST_MESSAGE, signature1, (err, res) => { - assert.equal(!!err, false, err); - assert.equal(res, true); - hmac.key.verify("sha1", TEST_MESSAGE_WRONG, signature1, (err, res) => { - assert.equal(!!err, false, err); - assert.equal(res, false); - done(); - }); - }); - }); - }); - }); - }); - - }); - -}); \ No newline at end of file diff --git a/test/pbkdf2.js b/test/pbkdf2.js deleted file mode 100644 index d57aa39..0000000 --- a/test/pbkdf2.js +++ /dev/null @@ -1,77 +0,0 @@ -"use strict"; - -const assert = require('assert'); -const webcrypto = require('./config'); -const checkAlgorithms = require('./helper').checkAlgorithms; -const subtle = webcrypto.subtle; - -context("WebCrypto", () => { - - context("import", () => { - ["", "password"].forEach(psw => { - it(`value: ${psw || "empty"}`, done => { - webcrypto.subtle.importKey("raw", Buffer.from(psw), "pbkdf2", false, ["deriveBits"]) - .then(key => { - assert.equal(!!key, true); - assert.equal(!!key.algorithm, true); - assert.equal(key.algorithm.name, "PBKDF2"); - assert.equal(key.algorithm.length, psw.length * 8); - assert.equal(key.extractable, false); - assert.equal(key.type, "secret"); - assert.equal(key.usages.length, 1); - assert.equal(key.usages[0], "deriveBits"); - }) - .then(done, done) - }); - }); - }); - - context("deriveBits", () => { - [8, 16, 128, 256, 512].forEach(length => { - it(`length:${length}`, done => { - webcrypto.subtle.importKey("raw", Buffer.from("password"), "pbkdf2", false, ["deriveBits"]) - .then(key => { - assert.equal(!!key, true); - return webcrypto.subtle.deriveBits( - { name: "PBKDF2", salt: Buffer.from("salt"), iterations: 8, hash: "SHA-1" }, - key, - length - ); - }) - .then(raw => { - assert.equal(raw.byteLength * 8, length) - }) - .then(done, done); - }); - }); - }); - - context("deriveKey", () => { - ["AES-CBC", "AES-GCM", "AES-KW", "HMAC"].forEach(name => { - context(name, () => { - [128, 192, 256].forEach(length => { - it(`length:${length}`, done => { - webcrypto.subtle.importKey("raw", Buffer.from("password"), "pbkdf2", false, ["deriveKey"]) - .then(key => { - assert.equal(!!key, true); - return webcrypto.subtle.deriveKey( - { name: "PBKDF2", salt: Buffer.from("salt"), iterations: 8, hash: "SHA-256" }, - key, - { name, length }, - true, - name === "HMAC" ? ["sign"] : ["wrapKey"] - ); - }) - .then(key => { - assert.equal(!!key, true); - assert.equal(key.algorithm.name, name); - assert.equal(key.algorithm.length, length); - }) - .then(done, done); - }); - }); - }); - }); - }); - -}); \ No newline at end of file diff --git a/test/rsa.js b/test/rsa.js deleted file mode 100644 index 9e6b441..0000000 --- a/test/rsa.js +++ /dev/null @@ -1,242 +0,0 @@ -"use strict"; -const assert = require('assert'); -const webcrypto = require('./config'); -const checkAlgorithms = require('./helper').checkAlgorithms; - -describe("WebCrypto RSA", () => { - - var TEST_MESSAGE = Buffer.from("1234567890123456"); - var KEYS = [ - { alg: "RSASSA-PKCS1-v1_5", usages: ["sign", "verify"] }, - { alg: "RSA-PSS", usages: ["sign", "verify"] }, - { alg: "RSA-OAEP", usages: ["encrypt", "decrypt"] }, - { alg: "RSA-OAEP", usages: ["wrapKey", "unwrapKey"] }, - ]; - var DIGEST = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]; - var PUBLIC_EXPONENT = [new Uint8Array([3]), new Uint8Array([1, 0, 1])]; - var MODULUS_LENGTH = [1024, 2048, /*4096*/]; - - var keys = []; - - context("Generate key", () => { - - it("Params", done => { - webcrypto.subtle.generateKey( - { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256", modulusLength: 1024, publicExponent: new Uint8Array([1, 0, 1]) }, - false, - ["sign"] - ) - .then(keyPair => { - let pkey = keyPair.privateKey; - assert.equal(pkey.type, "private"); - assert.equal(pkey.algorithm.name, "RSASSA-PKCS1-v1_5"); - assert.equal(pkey.algorithm.hash.name, "SHA-256"); - assert.equal(pkey.algorithm.modulusLength, 1024); - assert.equal(pkey.algorithm.publicExponent.length, 3); - assert.equal(pkey.algorithm.publicExponent[0], 1); - assert.equal(pkey.extractable, false); - - let pubkey = keyPair.publicKey; - assert.equal(pubkey.type, "public"); - assert.equal(pubkey.algorithm.name, "RSASSA-PKCS1-v1_5"); - assert.equal(pubkey.algorithm.hash.name, "SHA-256"); - assert.equal(pubkey.algorithm.modulusLength, 1024); - assert.equal(pubkey.algorithm.publicExponent.length, 3); - assert.equal(pubkey.algorithm.publicExponent[0], 1); - assert.equal(pubkey.extractable, true); - }) - .then(done, done); - }); - - // Keys - KEYS.forEach(key => { - // Digest - DIGEST.forEach(digest => { - // publicExponent - PUBLIC_EXPONENT.forEach(pubExp => { - // modulusLength - MODULUS_LENGTH.forEach(modLen => { - var keyName = `${key.alg} ${digest} e:${pubExp.length === 1 ? 3 : 65535} n:${modLen}` - var keyTemplate = { - name: keyName, - privateKey: null, - publicKey: null, - usages: key.usages, - } - keys.push(keyTemplate); - it(keyName, done => { - var alg = { - name: key.alg, - hash: { name: digest }, - modulusLength: modLen, - publicExponent: pubExp - }; - webcrypto.subtle.generateKey(alg, true, key.usages) - .then(keyPair => { - assert.equal(!!(keyPair.privateKey || keyPair.publicKey), true, "KeyPair is empty"); - // save keys for next tests - keyTemplate.privateKey = keyPair.privateKey; - keyTemplate.publicKey = keyPair.publicKey; - - return Promise.resolve(); - }) - .then(done, done); - }).timeout(modLen === 2048 ? 4000 : 2000); - }); - }); - }); - }); - }); - - context("Sign/Verify", () => { - - keys.filter(key => key.usages.some(usage => usage === "sign")) - .forEach(key => { - it(key.name, done => { - // TODO: Add label - webcrypto.subtle.sign({ name: key.privateKey.algorithm.name, saltLength: 8 }, key.privateKey, TEST_MESSAGE) - .then(sig => { - assert.equal(!!sig, true, "Has no signature value"); - assert.notEqual(sig.length, 0, "Has empty signature value"); - return webcrypto.subtle.verify({ name: key.publicKey.algorithm.name, saltLength: 8 }, key.publicKey, sig, TEST_MESSAGE) - }) - .then(v => assert.equal(v, true, "Signature is not valid")) - .then(done, done); - }); - }); - }); - - context("Encrypt/Decrypt", () => { - // Select keys for encrypt - keys.filter(key => key.usages.some(usage => usage === "encrypt")) - .forEach(key => { - // Label - [null, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8])].forEach(label => { - it(`${label ? "label\t" : "no label"}\t${key.name}`, done => { - webcrypto.subtle.encrypt({ name: key.privateKey.algorithm.name, label: label }, key.publicKey, TEST_MESSAGE) - .catch(e => { - if (e.message.indexOf("RSA_padding_add_PKCS1_OAEP_mgf1") > -1) - return Promise.reject(); - return Promise.reject(e); - }) - .then(enc => { - assert.equal(!!enc, true, "Has no encrypted value"); - assert.notEqual(enc.length, 0, "Has empty encrypted value"); - return webcrypto.subtle.decrypt({ name: key.publicKey.algorithm.name, label: label }, key.privateKey, enc) - }) - .then(dec => { - assert.equal(Buffer.from(dec).toString(), TEST_MESSAGE.toString(), "Decrypted message is not valid") - }) - .then(done, done); - }); - }); - }); - }); - - context("Export/Import", () => { - - // Keys - keys.forEach(key => { - // Format - ["jwk", "spki", "pkcs8"].forEach(format => { - it(`${format}\t${key.name}`, done => { - var promise = Promise.resolve(); - // Check public and private keys - [key.privateKey, key.publicKey].forEach(_key => { - if ((format === "spki" && _key.type === "public") || (format === "pkcs8" && _key.type === "private") || format === "jwk") - promise = promise.then(() => { - return webcrypto.subtle.exportKey(format, _key) - .then(jwk => { - assert.equal(!!jwk, true, "Has no jwk value"); - // TODO assert JWK params - return webcrypto.subtle.importKey(format, jwk, _key.algorithm, true, _key.usages); - }) - }) - .then(k => { - assert.equal(!!k, true, "Imported key is empty"); - checkAlgorithms(_key.algorithm, k.algorithm); - }); - }); - promise.then(done, done); - }); - }); - }); - }); - - context("Wrap/Unwrap", () => { - - var aesKeys = [{}, {}, {}]; - - before(done => { - var promise = Promise.resolve(); - [128, 192, 256].forEach((length, index) => { - var keyTemplate = aesKeys[index]; - promise = promise.then(() => { - return webcrypto.subtle.generateKey({ name: "AES-CBC", length: length }, true, ["encrypt", "decrypt"]) - .then(key => { - keyTemplate.key = key; - // return Promise.resolve(); - }); - }); - }); - promise.then(done, done); - }); - - // Keys - keys.filter(key => key.usages.some(usage => "wrapKey" === usage)) - .forEach(key => { - // AES keys - aesKeys.forEach(aes => { - // Format - ["raw"].forEach(format => { - [null, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8])].forEach(label => { - it(`${label ? "label\t" : "no label"}\t${key.name}`, done => { - var _alg = { name: key.publicKey.algorithm.name, label: label }; - webcrypto.subtle.wrapKey(format, aes.key, key.publicKey, _alg) - .catch(e => { - if (e.message.indexOf("RSA_padding_add_PKCS1_OAEP_mgf1") > -1) - return Promise.reject(); - return Promise.reject(e); - }) - .then(enc => { - assert.equal(!!enc, true, "Has no encrypted value"); - return webcrypto.subtle.unwrapKey(format, enc, key.privateKey, _alg, aes.key.algorithm, true, aes.key.usages); - }) - .then(key => { - assert.equal(!!key, true, "Has no unwrapped key"); - }) - .then(done, done); - }); - }); - }); - }); - }); - }); - - context("Algorithm parameters", () => { - - it("modulusLength/publicExponent for imported key", (done) => { - webcrypto.subtle.generateKey({ name: "RSASSA-PKCS1-v1_5", hash: "SHA-1", publicExponent: new Uint8Array([1, 0, 1]), modulusLength: 2048 }, true, ["sign", "verify"]) - .then((keyPair) => { - const key = keyPair.privateKey; - assert.equal(ArrayBuffer.isView(key.algorithm.publicExponent), true); - assert.equal(key.algorithm.publicExponent.length === 3, true); - assert.equal(key.algorithm.modulusLength === 2048, true); - assert.equal(key.type === "private", true); - return webcrypto.subtle.exportKey("pkcs8", key); - }) - .then((raw) => { - return webcrypto.subtle.importKey("pkcs8", raw, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["sign"]); - }) - .then((key) => { - assert.equal(ArrayBuffer.isView(key.algorithm.publicExponent), true); - assert.equal(key.algorithm.publicExponent.length === 3, true); - assert.equal(key.algorithm.modulusLength === 2048, true); - assert.equal(key.type === "private", true); - }) - .then(done, done); - }); - - }); - -}); \ No newline at end of file diff --git a/test/vectors/aes_ctr.js b/test/vectors/aes_ctr.js deleted file mode 100644 index 7ea5be2..0000000 --- a/test/vectors/aes_ctr.js +++ /dev/null @@ -1,62 +0,0 @@ -const assert = require('assert'); -const crypto = require('../config'); - -let subtle = crypto.subtle; - -const vectors = [ - { - jwk: { "alg": "A128CTR", "ext": true, "k": "wblpP75XB3KdwybPxRGc2Q", "key_ops": ["encrypt", "decrypt"], "kty": "oct" }, - cases: [ - { "alg": { "name": "AES-CTR", "counter": [72, 6, 215, 190, 52, 28, 93, 142, 75, 91, 144, 228, 113, 9, 208, 133], "length": 1 }, "enc": [193, 189, 162, 32, 223, 172, 222, 52, 187, 167, 39, 181, 208, 44, 126, 93, 176, 4, 79, 4, 130, 166, 226, 189, 149, 29, 237, 84, 44, 220, 252, 10] }, - { "alg": { "name": "AES-CTR", "counter": [104, 47, 145, 47, 244, 208, 205, 182, 73, 234, 98, 184, 169, 170, 111, 165], "length": 64 }, "enc": [110, 228, 115, 255, 104, 191, 247, 184, 208, 161, 78, 2, 51, 217, 163, 78, 206, 163, 189, 182, 175, 118, 209, 195, 193, 242, 102, 82, 75, 5, 234, 102] }, - { "alg": { "name": "AES-CTR", "counter": [210, 96, 48, 120, 7, 80, 60, 108, 216, 204, 177, 31, 55, 33, 117, 203], "length": 128 }, "enc": [241, 215, 176, 82, 243, 175, 69, 36, 77, 40, 161, 159, 68, 203, 131, 141, 149, 166, 197, 190, 152, 241, 169, 193, 56, 31, 39, 76, 140, 234, 222, 101] }, - ], - }, - { - jwk: { "alg": "A256CTR", "ext": true, "k": "cHH9uWDZf4cVmB4witwb2SAuz5YxkjfCvwOA_7ABg1Q", "key_ops": ["encrypt", "decrypt"], "kty": "oct" }, - cases: [ - { "alg": { "name": "AES-CTR", "counter": [134, 8, 205, 173, 139, 24, 215, 128, 242, 111, 73, 240, 184, 89, 70, 218], "length": 1 }, "enc": [168, 195, 174, 76, 227, 188, 11, 95, 94, 72, 155, 252, 50, 64, 164, 87, 149, 244, 159, 147, 59, 96, 215, 165, 141, 30, 23, 4, 213, 197, 190, 120] }, - { "alg": { "name": "AES-CTR", "counter": [42, 70, 216, 161, 245, 141, 42, 24, 185, 40, 27, 88, 195, 14, 43, 81], "length": 64 }, "enc": [18, 38, 41, 103, 213, 43, 195, 238, 29, 58, 109, 12, 102, 45, 65, 221, 215, 169, 237, 87, 25, 117, 205, 7, 37, 116, 2, 80, 78, 223, 235, 254] }, - { "alg": { "name": "AES-CTR", "counter": [117, 196, 244, 158, 61, 217, 68, 197, 73, 221, 65, 221, 0, 103, 191, 156], "length": 128 }, "enc": [108, 251, 65, 164, 220, 203, 47, 24, 177, 179, 214, 59, 87, 131, 144, 119, 42, 118, 246, 141, 124, 161, 213, 237, 231, 22, 191, 99, 31, 54, 21, 46] } - ] - } -]; - -// Data for encryption is empty array of 16 bytes -const data = new Uint8Array(32); - -context("Vectors", () => { - - context("AES-CTR", () => { - - vectors.forEach((vector) => { - context(vector.jwk.alg, () => { - vector.cases.forEach((item) => { - it(`length: ${item.alg.length}`, (done) => { - crypto.subtle.importKey("jwk", vector.jwk, { name: "AES-CTR" }, true, ["encrypt", "decrypt"]) - .then((key) => { - const alg = { name: "AES-CTR", counter: new Uint8Array(item.alg.counter), length: item.alg.length }; - return crypto.subtle.encrypt(alg, key, data) - .then((enc) => { - assert.equal(Buffer.compare( - Buffer.from(item.enc), - Buffer.from(enc) - ), 0) - return crypto.subtle.decrypt(alg, key, enc) - }) - .then((dec) => { - assert.equal(Buffer.compare( - Buffer.from(data), - Buffer.from(dec) - ), 0) - }) - .then(done, done); - }) - }); - }) - }) - }) - - }); - -}); diff --git a/test/vectors/aes_kw.js b/test/vectors/aes_kw.js deleted file mode 100644 index 284dba1..0000000 --- a/test/vectors/aes_kw.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; - -const assert = require('assert'); -const crypto = require('../config'); - -let subtle = crypto.subtle; - -const vectors = [ - { "algorithm": { "name": "AES-KW", "length": 128 }, "key": { "alg": "A128KW", "ext": true, "k": "7VztW2VAIOEw8ppK-ri4XQ", "key_ops": ["wrapKey", "unwrapKey"], "kty": "oct" }, "wrappedKey": "cYy3JTFpcHn93ulowQlMeW3HB9H71w1/" }, - { "algorithm": { "name": "AES-KW", "length": 256 }, "key": { "alg": "A256KW", "ext": true, "k": "HKbFtGHXDt9IhtbY-NWgMJGCK3wLNKxb_5BXjAibT44", "key_ops": ["wrapKey", "unwrapKey"], "kty": "oct" }, "wrappedKey": "6EqFFsbyZyO2arJtuN4PD72a2M/LSykCk3nYWpagObyNqiK05gZwnw==" } -]; - -context("Vectors", () => { - - context("AES-KW", () => { - - vectors.forEach(vector => { - it(`length:${vector.algorithm.length}`, done => { - subtle.importKey("jwk", vector.key, vector.algorithm, true, ["unwrapKey"]) - .then(key => { - assert.equal(!!key, true, "Imported key is empty"); - assert.equal(key.extractable, true); - assert.equal(key.type, "secret"); - assert.equal(key.algorithm.name, "AES-KW"); - assert.equal(key.algorithm.length, vector.algorithm.length); - assert.equal(key.usages.length, 1); - assert.equal(key.usages[0], "unwrapKey"); - - const wrappedKey = Buffer.from(vector.wrappedKey, "base64"); - return subtle.unwrapKey("raw", wrappedKey, key, { name: "AES-KW" }, vector.algorithm, true, ["wrapKey"]) - }) - .then(key => { - assert.equal(!!key, true, "Imported key is empty"); - assert.equal(key.extractable, true); - assert.equal(key.type, "secret"); - assert.equal(key.algorithm.name, "AES-KW"); - assert.equal(key.algorithm.length, vector.algorithm.length); - assert.equal(key.usages.length, 1); - assert.equal(key.usages[0], "wrapKey"); - - return subtle.exportKey("jwk", key) - }) - .then(jwk => { - assert.equal(!!jwk, true); - assert.equal(jwk.alg, `A${vector.algorithm.length}KW`); - assert.equal(jwk.k, vector.key.k); - }) - .then(done, done); - }); - }); - - }); - -}); \ No newline at end of file diff --git a/test/vectors/ec_secp256k1.js b/test/vectors/ec_secp256k1.js deleted file mode 100644 index f2024be..0000000 --- a/test/vectors/ec_secp256k1.js +++ /dev/null @@ -1,170 +0,0 @@ -const assert = require('assert'); -const { Convert } = require('pvtsutils'); -const webcrypto = require('../config'); -const subtle = webcrypto.subtle; - -function h2a(hex) { - return Convert.FromHex(hex); -} - -function h2b(hex) { - return Convert.ToBase64Url(Convert.FromHex(hex)); -} - -const vectors = { - "SHA-1": [ - { - m: h2a("ebf748d748ebbca7d29fb473698a6e6b4fb10c865d4af024cc39ae3df3464ba4f1d6d40f32bf9618a91bb5986fa1a2af048a0e14dc51e5267eb05e127d689d0ac6f1a7f156ce066316b971cc7a11d0fd7a2093e27cf2d08727a4e6748cc32fd59c7810c5b9019df21cdcc0bca432c0a3eed0785387508877114359cee4a071cf"), - d: h2b("b4a57a9bfbf35d0e352f3481523921ad4fb8dd1b40bb059ed5b150812f9dbd33"), - x: h2b("70da923e655efcc13e08fefe4549a50dfa4078d7e3ac94678a97bd7eb85c3350"), - y: h2b("d51218a754c00cf928046e37144af9bd61b6f4430cd8455f528aabab17ce3792"), - s: h2a("2a8d2020b14e5d83ce6dd41733fd7db42b0076211f4321e52203dfb02fbf489b9570682ef8580c4c9d76f48c50a8c888549e00ea87b428add75ffbc614058eb8"), - }, - { - m: h2a("0dcb3e96d77ee64e9d0a350d31563d525755fc675f0c833504e83fc69c030181b42fe80c378e86274a93922c570d54a7a358c05755ec3ae91928e02236e81b43e596e4ccbf6a9104889c388072bec4e1faeae11fe4eb24fa4f9573560dcf2e3abc703c526d46d502c7a7222583431cc8178354ae7dbb84e3479917707bce0968"), - d: h2b("5ac81c3e88a5ee67b14960c065f4ea20479c10bc55ad4dd70f134f1b249099b8"), - x: h2b("e01e546d8c99e51d6cfafae9c22df4b4123320af8f2b517c194e2000df7c73a8"), - y: h2b("84f96476d2a7e9a2c1ab27d75df64d3415a9fa013909e4700688edeb4555b328"), - s: h2a("6a116702f85a9b2056526352ef3f12b70b665ee0c0a66d70e63d0842936c588627670b8730ce89319cf56474dcdce9c3e82fa2a9bdbcf9e0001202bba652ae9e"), - }, - { - m: h2a("9408392847e3a387307fbc6789669974fbdaa49b5f2bd5510895105a11dff9c1caab7e327cec80c281e3d9ff13b9e37bbbd2342da7543733bff9aabbfeacc75a40c75a2c5d2b159290428761b64689e5d51224da41da22482c95965422946a644a8becec98f55f1403f23dc794ee889bf02eb7d833f4d465713201e8460a66ce"), - d: h2b("3b69ee4dcacceeaa6c968598d46c1d0155cefb3d869634b58021380520f0d240"), - x: h2b("6561ed684fb1eaabab55e75c3db13c1d398e93999d81c0c1d11abc44a56aca05"), - y: h2b("5b5e6dfe8a23a3cd71c2d8b84d8912e62e01e55b2219fadae3a90575e69f9f73"), - s: h2a("8a67f3d7cb4bb0d718d1d2c6a2a4669f7378b854df67eac2744353fee62472a7c6a58c91e507dff45711caa8746df93eeedfa490a30488e04d367dde3829fa43"), - }, - ], - "SHA-256": [ - { - m: h2a("5c868fedb8026979ebd26f1ba07c27eedf4ff6d10443505a96ecaf21ba8c4f0937b3cd23ffdc3dd429d4cd1905fb8dbcceeff1350020e18b58d2ba70887baa3a9b783ad30d3fbf210331cdd7df8d77defa398cdacdfc2e359c7ba4cae46bb74401deb417f8b912a1aa966aeeba9c39c7dd22479ae2b30719dca2f2206c5eb4b7"), - d: h2b("42202a98374f6dca439c0af88140e41f8eced3062682ec7f9fc8ac9ea83c7cb2"), - x: h2b("131ca4e5811267fa90fc631d6298c2d7a4ecccc45cc60d378e0660b61f82fe8d"), - y: h2b("cf5acf8ed3e0bbf735308cc415604bd34ab8f7fc8b4a22741117a7fbc72a7949"), - s: h2a("d89f9586070230bb03e625cca18c89bb3117cd472ff6ee2a50809f0e8903930945972842e92e3a41abeea1089d812eb5343ca8f075ac9c66e13f3db287048638"), - }, - { - m: h2a("17cd4a74d724d55355b6fb2b0759ca095298e3fd1856b87ca1cb2df5409058022736d21be071d820b16dfc441be97fbcea5df787edc886e759475469e2128b22f26b82ca993be6695ab190e673285d561d3b6d42fcc1edd6d12db12dcda0823e9d6079e7bc5ff54cd452dad308d52a15ce9c7edd6ef3dad6a27becd8e001e80f"), - d: h2b("d89996aada18436e87a5feaccf3fece96977cde0b89d44aedd914ee76e94da1c"), - x: h2b("54ed69e1bbde38e60c7fb764479e0c2db60f2b853a537818c48d03c524e5245e"), - y: h2b("5099022ebd231b34098761351e9fabe15c84ad44710a1a66ed57174eb021cfd1"), - s: h2a("40927e35b7b847a198e130312d5d9264325895892d4a9c262c323ecf500a5759b2a9f6e8660e5bc6eb78a81b76c1eb9c56d8d6860eaabfe9cb58a3587594cdfe"), - }, - { - m: h2a("18e55ac264031da435b613fc9dc6c4aafc49aae8ddf6f220d523415896ff915fae5c5b2e6aed61d88e5721823f089c46173afc5d9b47fd917834c85284f62dda6ed2d7a6ff10eb553b9312b05dad7decf7f73b69479c02f14ea0a2aa9e05ec07396cd37c28795c90e590631137102315635d702278e352aa41d0826adadff5e1"), - d: h2b("14c93e4ba36110e6e062c21a648967e6a5da3bc341b3e19d108eaf3be7459cb6"), - x: h2b("3b7abc1da3dd104beb2e378c484bb23295027a4f039635891a486f7338d10d73"), - y: h2b("421f2fb7fc03b792d411c391ce888058a15ae7f4ae9a2da72bb5b817785e8271"), - s: h2a("df8152746377bd5967b9ca0b3048cd29ce12a97603dced5db3f80d44150abd08b1fae910ce6aa7f23829b3fa362c8c66e15c1a39211a0bbd9ce230c1ef9d79ac"), - } - ], - "SHA-384": [ - { - m: h2a("d68f654acefe2db8103663dffea796579c48cb0f7d74b281621528696a7bb40fdcc9f99ae1155f317e274ef8eab53f1c3c180db019abf38dfa037e70c1a90a154dbd887c66f20fbc8797c6811fb9a36926fc460b50777e79a4ce8265d5083375c44fb21900ba5516e5537f46766a31e19884d824c9e339947179e5c011307bad"), - d: h2b("292efd39a4e53efb580ba4ba3e5bb47d6e7463cddab04335aa061d554c74bcc8"), - x: h2b("58ac983601b7b87eda2afdbe72643d036e12673e0badc67ff44380a7bec59f14"), - y: h2b("34ebd172659000d2fffc63b7bc7eb6ac43d3f4b6995fe1151c458651e3539328"), - s: h2a("9ae57e4e4eca88939152ee38a07860ae03cff51d84708eeceabc70d615b7d31b808cddd65562c77c81a1c8d45e229f53edf19864069f8d62c3c3fa1f8c8c3c66"), - }, - { - m: h2a("fe01dfb11658d15f2911d6927fbaaec2397aa371b6b853df134fca396f1fa194afb83db9dad7a97a46de8b9329ea647ba11f88b2ec796f615683d2b47be96a7822c694772aac37a91bb8e9c363717e44086d32e425e9c56acce66808b687661a5c191da3ebb17fcf5884ea23f3fbc812c225743de3670704eec735dffcdd9e2a"), - d: h2b("576314d4c6ad800d5726b0cdd0e6e9429568ff96ffbd83aea38f6c9a3e6409d3"), - x: h2b("2193d52e689bf775545a425d58bc1a959749717596715aaa2a8ecb8351868d16"), - y: h2b("9c3e3f504bbbfddf939e65678c2ec307c012df7c7f2b113044af7a01f5c46cc7"), - s: h2a("41ee804ccacefd441972ca8d92c72c4b361c39eee5cb1f474de7f09d4b83f2121614e19bab04de9ef3658bf6702d599bb518f598a122e1df92160bd5584dd42b"), - }, - { - m: h2a("46b0de23fa820910d5854c6e49bc788bedb2a79f50031ff02b89e12f356089f11864cab92094968cb7663f119ba70c4d1631cb3355958bee7c4064d75967fd22797d1f534196ef0bd99fac3c73382bf7a7c550a8f8460a93e7bf30a60d974cea49af280738f150eff1c5bf9c6805c9b057de5330c471c8f16824d491c88bcba4"), - d: h2b("634ccc8392372f66e9086c540f868a9ce93d5452aa1e0e1a5448ed15f4252c85"), - x: h2b("ac9369648d379af84e90e233696c4708423af95890ce41226e49a524ddfbed83"), - y: h2b("1b7f0c6bc6a2c65aa3a66dba5722c26d362a2a8a445a70e4e0e9c08851e3daa5"), - s: h2a("c7700bcd35c0f82ca14c1c3d5a3b3b444a187593ebafcd5ec401f8a49b0245533dbd18cf865697dfa6733dd0676063b769a1fd94f2d2a3b92e2680d4291c6128"), - }, - ], - "SHA-512": [ - { - m: h2a("975ac93690f0f7b9fea8fbd2d8f13fbdfa59e196cbc27795c0a28c7d1bb0636f7f630eca630ef89e901451a17335d9ca2b10b42947e9add0aa0b3e00ab7a4eb64c3c9fdca43ae7ff515ce09e08ba7b0bfed5bde17c4e0f4c84f9037d1da1cd50c546c29aafe79651d2e6a8e956695255d463772bc50dc8c12be8c8a5a7ea5a8a"), - d: h2b("fc280d9b8f1e9e51566ea4813f48535fdcc84fe988789bc991dd5aea42282f39"), - x: h2b("55dffb031040816b472348ffc77f0359c2dd5791bdb6925d0c95792b67454a75"), - y: h2b("ccb56932797a4c72eae2eba99010ce477c26ba0f65a9f3de484a95f7e8aa6218"), - s: h2a("2a82d76047c17cdc9ca7b467304e3eea8294446d948c6d0c44bf23b9167c17d77aecd4ca2262f8f09b334d21b55835f882810a05ef52d4f6507c36eba72cbfb9"), - }, - { - m: h2a("5b8a6a9c878e401fbb13066324d040b4cd21466d334248a9537c22cee41d9307b6000820e1ed44678c9401dbf722caaa62c453afc4e970cb772b688c436f1397c61f402ddd359e8e40551d43ae26d90a996bf7a0aae0878149f21e07f0e8f25ceb88cf5f2dbb9197c6420129e973caecdad9b7fd9974556db402310ea0871149"), - d: h2b("5246fe281b4aceb74b66fb48dcf1489971e6b98ad242b92b5e2042829cbe359c"), - x: h2b("c8921271d9380dc4d580bf1a34913e965865310107c4501944ff6b8ec4848a49"), - y: h2b("583e75db8c93fa90044ab456f127d0043d31cfd0adcb34c52b733fbb00f6f629"), - s: h2a("91c38ee963e0dd72bd688be55a17cfa66c94e66a3bf92f5dccdee2b6ba86ddfd23b344220f12b9f80e0cc2b814e5af78ddcf7b767171f36fd2eb60a2eafabc47"), - }, - { - m: h2a("bb643b8b0e42e21dfe53651b420fc2af8954cbb588ff80d8358a672ddeaaf94e0b09e081f532dd115419406ec598cb6ca896cc208942a5d6c22ae8729b6a6c73d7142e363bd29b7578a44d21847781f1381787a12971f72a78182dad7413363d925f89b00a0c44eff53983cd01ad50ec8e7b1336542cea128258664509c73ea5"), - d: h2b("ac19fe78ee61d116055a71f567f67767b6cccb52774817d728b440dd39af5232"), - x: h2b("9ed0a911e63dc4dcc7a27126d7a3d7b7d7f8821bc491fe79d710c381b4e719b2"), - y: h2b("fc9a1cf569c6d2a6e045f3f7d753ea63360cdae0bb0a1f13044c3c92a999e32a"), - s: h2a("d60b181450ef7a04a6c94bb6eaf414864f271fb4e8c1ed8a5e77d285d61792cffdc58064546e725145572de5366110da589345301e5ee9c861ee3b879e9ffe49"), - }, - ], -}; - -describe("EC secp256k1 vectors", () => { - for (i in vectors) { - context(i, () => { - const hash = i; - const tests = vectors[hash]; - let index = 1; - tests.forEach((test) => { - it(`#${index++}`, (done) => { - const alg = { - name: "ECDSA", - namedCurve: "K-256", - hash, - }; - const jwkBase = { - kty: "EC", - crv: "K-256", - } - const jwkPrv = Object.assign({}, jwkBase, { - x: test.x, - y: test.y, - d: test.d, - }); - const jwkPub = Object.assign({}, jwkBase, { - x: test.x, - y: test.y, - }) - let privateKey, publicKey; - Promise.resolve() - .then(() => { - return subtle.importKey("jwk", jwkPrv, alg, false, ["sign"]) - .then((key) => { - privateKey = key; - }) - }) - .then(() => { - return subtle.importKey("jwk", jwkPub, alg, true, ["verify"]) - .then((key) => { - publicKey = key; - }) - }) - .then(() => { - return subtle.sign(alg, privateKey, test.m) - .then((signature) => { - return subtle.verify(alg, publicKey, signature, test.m) - }) - .then((ok) => { - assert.equal(ok, true, "Native signed data has wrong signature"); - }) - }) - .then(() => { - return subtle.verify(alg, publicKey, test.s, test.m) - .then((ok) => { - assert.equal(ok, true, "Wrong signature for data from test vector"); - }) - }) - .then(done, done); - }); - }); - }); - } - -}) \ No newline at end of file diff --git a/test/vectors/hmac.js b/test/vectors/hmac.js deleted file mode 100644 index fe161d6..0000000 --- a/test/vectors/hmac.js +++ /dev/null @@ -1,86 +0,0 @@ -"use strict"; -const assert = require('assert'); -const webcrypto = require('../config'); -const subtle = webcrypto.subtle; - -// Chrome vectors -const vectors = [ - { - alg: { name: "HMAC", hash: "SHA-1", length: 128 }, - jwk: { alg: "HS1", ext: true, k: "-Dq509EtZLK74okYtquhbA", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "c56c7d4180cc686b4ae4ad1c802b172f5be506cb" - }, - { - alg: { name: "HMAC", hash: "SHA-1", length: 256 }, - jwk: { alg: "HS1", ext: true, k: "dnUKLkxLZxej051UJuzsZc1slDGGjXGGpkN1Cb3v-v0", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "a7cbad583bf770ad72b6946034f7dd46a7c9fa39" - }, - { - alg: { name: "HMAC", hash: "SHA-1", length: 512 }, - jwk: { alg: "HS1", ext: true, k: "qpMW7xZOo9nsyNudtzEm6TjwSSWUJNrtPc50J25mhsbMHTx10za768wmUE__VjAF1ngU08EdrAHUzAiwbpIXSQ", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "a7c1bb7bb4165bf1c793d9ec19bc08d15e7608ff" - }, - { - alg: { name: "HMAC", hash: "SHA-256", length: 128 }, - jwk: { alg: "HS256", ext: true, k: "QOqmJzfzNTH9iIIT6ipz_Q", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "f2607dd928f7e40d896948e44c2facbf3a6e1870394d44f24c990e12ce4bd6fd" - }, - { - alg: { name: "HMAC", hash: "SHA-256", length: 256 }, - jwk: { alg: "HS256", ext: true, k: "om_Vtxu9zWdRWMmfsBxO3P7J3miVQfqMumYMC2Qs4Yk", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "1c9f203b417791c39faf7e2c6b4d471bdb9ee4f83d61ef806435b324d8083f31" - }, - { - alg: { name: "HMAC", hash: "SHA-256", length: 512 }, - jwk: { alg: "HS256", ext: true, k: "Jf__Ri3OoD4b-oTa6HCE7n_3Bv946gPGQBOalZlbKib8JmY4h6zi5s9fLRqL0t-3eDHdWQFTXG4mgytsdde0Jg", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "ff5df6b852cee090b7b4b749a27f96f44c4d0f040737b6acb37ff5f7831a682a" - }, - { - alg: { name: "HMAC", hash: "SHA-384", length: 128 }, - jwk: { alg: "HS384", ext: true, k: "U2RQ9yrjnY1wQVWx216QzQ", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "d9e5c53a1eecc191c4d938ed271e443600b66d8f9e33f4d10f16c43d87c1c483d4f3ff8c8d179a607542c74ddd57534a" - }, - { - alg: { name: "HMAC", hash: "SHA-384", length: 256 }, - jwk: { alg: "HS384", ext: true, k: "TT1ZRmZQfPK0bmyVrlOWUrSV--Ser8dzLYn1vu55qSc", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "f8d367f33da05b9502f5d2cceff51b4255d396993c2613d3007eb6712fdff67ca906f450bc2bcb7354e512dc8620c63d" - }, - { - alg: { name: "HMAC", hash: "SHA-384", length: 512 }, - jwk: { alg: "HS384", ext: true, k: "vF09sr6-5FTeUZHrhhC5V0X8WdAYoh7KwTxnTV0KnewEf628v8oQ49bshNMW77gHkZ945mM4Md9m7Fits7KNlw", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "266816cf3991a64b42e3404e66ee0bf9cbff71acb7bd6191fb0767259d4c2a720e821d7b207efadbcf75f30de5244e09" - }, - { - alg: { name: "HMAC", hash: "SHA-512", length: 128 }, - jwk: { alg: "HS512", ext: true, k: "Yn_jCCwZ4INOs134rrDVWg", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "90e83fe5a36476b7b8b1d146902aa2b8f86b434cc52fb613ea707055af5ab6746409cb8879013df6d419124c277822162c789ba0f8f0d62bc21c695ccf80b7f8" - }, - { - alg: { name: "HMAC", hash: "SHA-512", length: 256 }, - jwk: { alg: "HS512", ext: true, k: "Y_dUCka9YT5G2bnyST_7UoopFHmAhAWRXdLUo0b4PZw", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "af50024232800369d95afa6800ca913c784e98da06dee591cc5e119a08b1f38ad5a41e41c5789fa4f414b54a92104b522c15ef8d09ee49fc1f016170d7daef4e" - }, - { - alg: { name: "HMAC", hash: "SHA-512", length: 512 }, - jwk: { alg: "HS512", ext: true, k: "YMhyJ0EPxePMgJJ7_gtzPMvX-_7lhesoF9kg9pLSPFqcMYqk13uwtM_EWi-jm_tE3va4rK9Qd8oTHp8UH2xnpw", key_ops: ["sign", "verify"], kty: "oct" }, - signature: "2bcdf62e54131a83a8fb27c3405ee79463802491b10c1d6421f3aba3255f28685f74e717ea8ee13cb5c688898856dce92cd91512d1276167b5db6b16baf6d187" - } -] - -describe("WebCrypto", () => { - context("HMAC", () => { - vectors.forEach(vector => - it(`hash:${vector.alg.hash} length:${vector.alg.length}`, done => { - subtle.importKey("jwk", vector.jwk, vector.alg, true, ["sign", "verify"]) - .then(key => { - return subtle.verify(vector.alg, key, Buffer.from(vector.signature, "hex"), Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])) - }) - .then(res => { - assert.equal(res, true); - done(); - }) - .catch(done); - }) - ); - }); -}); \ No newline at end of file diff --git a/test/vectors/pbkdf2.js b/test/vectors/pbkdf2.js deleted file mode 100644 index 993adfe..0000000 --- a/test/vectors/pbkdf2.js +++ /dev/null @@ -1,81 +0,0 @@ -"use strict"; - -const assert = require('assert'); -const crypto = require('../config'); - -let subtle = crypto.subtle; - -const vectors = [ - { "algorithm": { "name": "PBKDF2", "hash": "SHA-1" }, "password": "", "derivedBits": "MZjBCKYUvm9T9Ux3/5HgHw==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-256" }, "password": "", "derivedBits": "GlOzGKZYUz1EYCdJtZeRXg==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-384" }, "password": "", "derivedBits": "CdVn/cAjFqdLrCV+dz/LpA==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-512" }, "password": "", "derivedBits": "WGqAJBM7TF6Sn+Am3+6RoA==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-1" }, "password": "password", "derivedBits": "yvcSWNZgau4mEfezNj+rtg==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-256" }, "password": "password", "derivedBits": "Sj4bTP75DW4A/IN08TwLDg==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-384" }, "password": "password", "derivedBits": "n4dQaniQ+UlRohiDSL3dKQ==" }, - { "algorithm": { "name": "PBKDF2", "hash": "SHA-512" }, "password": "password", "derivedBits": "jTNIFwT5oHTGb2G2b6gJ8w==" } -]; - -const vectorsKey = [{ "algorithm": { "name": "PBKDF2", "hash": "SHA-1" }, "password": "", "key": { "alg": "A128CBC", "ext": true, "k": "MZjBCKYUvm9T9Ux3_5HgHw", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "PZySgqtYaAzTLv+eevqUFQ==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-256" }, "password": "", "key": { "alg": "A128CBC", "ext": true, "k": "GlOzGKZYUz1EYCdJtZeRXg", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "BOAUIe71oASqkAkEaexcew==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-384" }, "password": "", "key": { "alg": "A128CBC", "ext": true, "k": "CdVn_cAjFqdLrCV-dz_LpA", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "u1+ZPiMlJ9nsXVxeQ+Aq5w==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-512" }, "password": "", "key": { "alg": "A128CBC", "ext": true, "k": "WGqAJBM7TF6Sn-Am3-6RoA", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "Nk9mDREG3cxn1SxlsJQUIg==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-1" }, "password": "password", "key": { "alg": "A128CBC", "ext": true, "k": "yvcSWNZgau4mEfezNj-rtg", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "s9bk3ikb7xRwHFKvkBensA==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-256" }, "password": "password", "key": { "alg": "A128CBC", "ext": true, "k": "Sj4bTP75DW4A_IN08TwLDg", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "EXGntv99x28t9rI4uuYGoA==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-384" }, "password": "password", "key": { "alg": "A128CBC", "ext": true, "k": "n4dQaniQ-UlRohiDSL3dKQ", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "9QNeVgy/CmNRZ6rztCX4iQ==" }, { "algorithm": { "name": "PBKDF2", "hash": "SHA-512" }, "password": "password", "key": { "alg": "A128CBC", "ext": true, "k": "jTNIFwT5oHTGb2G2b6gJ8w", "key_ops": ["encrypt"], "kty": "oct" }, "encrypted": "NNQ94K7/yvygm2pQRKM8xw==" }]; - -context("PBKDF2", () => { - - context("deriveBits", () => { - vectors.forEach(vector => { - it(`password:${vector.password || "empty"} hash:${vector.algorithm.hash}`, done => { - const raw = Buffer.from(vector.password); - subtle.importKey("raw", raw, vector.algorithm, false, ["deriveBits"]) - .then((key) => { - return crypto.subtle.deriveBits( - { name: "PBKDF2", salt: new Uint8Array([1, 2, 3, 4, 5]), iterations: 1000, hash: vector.algorithm.hash }, - key, 128) - }) - .then(dBits => { - assert.equal(!!dBits, true); - assert.equal(dBits instanceof ArrayBuffer, true); - assert.equal(dBits.byteLength, 128 / 8); - assert.equal(Buffer.from(dBits).toString("base64"), vector.derivedBits); - }) - .then(done, done); - }); - }); - }); - - context("deriveKey", () => { - vectorsKey.forEach(vector => { - it(`AES-CBC password:${vector.password || "empty"} hash:${vector.algorithm.hash}`, done => { - const raw = Buffer.from(vector.password); - let aes; - subtle.importKey("raw", raw, vector.algorithm, false, ["deriveKey"]) - .then((key) => { - return crypto.subtle.deriveKey( - { name: "PBKDF2", salt: new Uint8Array([1, 2, 3, 4, 5]), iterations: 1000, hash: vector.algorithm.hash }, - key, - { name: "AES-CBC", length: 128 }, - true, - ["encrypt"] - ) - }) - .then(aesKey => { - aes = aesKey - return crypto.subtle.exportKey("jwk", aesKey); - }) - .then(jwk => { - assert.equal(jwk.k, vector.key.k); - return crypto.subtle.encrypt( - { name: "AES-CBC", iv: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]) }, - aes, - new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) - ) - }) - .then(enc => { - assert.equal(!!enc, true); - assert.equal(enc instanceof ArrayBuffer, true); - assert.equal(Buffer.from(enc).toString("base64"), vector.encrypted); - }) - .then(done, done); - }); - }); - }) - -}); \ No newline at end of file diff --git a/test/vectors/rsa_pss.js b/test/vectors/rsa_pss.js deleted file mode 100644 index 546a253..0000000 --- a/test/vectors/rsa_pss.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; - -const assert = require('assert'); -const crypto = require('../config'); - -let subtle = crypto.subtle; -const MSG = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); - -const vectors = [{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"AGWO2llbGApZnDlY5ewtFJzj9jJs+v1l98H2AEltYjGUSaXECumdQBGjnUAUV/MTTWGxdLS9AZNhwJYvEUsKhRLmkuVOPOHfdC8N/A01AW5u/6uEqCjRlebwLpYJQBU17FFTq5GSdYrNHpZqIMy8Cnd6N1Il6juCCPTmCVYNkR8="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"q5/cgRVZjqBmIYA9TlULuba7wyiikkjhD6e1jyZ2gXRJE4O8E+9PbL1j+SgW8jxPByoUVcYEQAweyJDsefqIu7+phIAwFBSAdddCKaXyt4xXNkn50ALPKDFmrZmx6zn3rrirJQYAXDACsyLNQwUh8MGG/lrMvqDiI9WwWuVlNHM="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"YqJUsm7V/mjAB2bxXbIMBVfHL9dkRbeQhLTBREk9xuvbJZCGbKUrUJ1KWCJRlaQ/G3NrSMLXc9SP7AvWBP5rE9o/KERA7pWpJx8dU+JTME65oZiZt85nwUupH7XmgFQxeIpLAB8LIO/8PTesqYItunPZhQgMkUCcwm/YUtUOIPk="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-1","modulusLength":1024,"publicExponent":3},"jwk":{"alg":"PS1","d":"eUT7Uii7k3eIl3YtsyEb4XYNNaFhCdQspoZM1OIKDSz6-nxaFaC-IVjevbGVtdXPx_qLOPqCIl0xtmp7PO9CrZUTaZ7prYxgIZNvC_B9rPedZLqdIuLxxQJ1jpgRJoNDUM2SKO02R9iFINtzXOvtWqjGMsFtgVF2TO3aNBSppQM","dp":"lBLyC_ckaz5-gYy1lCwYaju4J8c1GFF_xFSpOulH4P9AOKIK8TQEz5sBShKrp1dSJOvXtUruHRzjHNN7SKjF5w","dq":"i8W57fzvPdM6w0Tag-t-LNX8BlosgDmQ_fbAyIc4uffcaUKXf61GUwvU7s0HEUHHSn3c2TBDVAokXKpMgSGpBw","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"ted4-z0ZXTNM4zFEjLGp0jET0HIRjr5C-clzP1MPE8N4d7qHIHEdMgVOHIpgkMC3q_fQ1XfDM4vKkZ-422bkBg9iIGVModAqyERg6gzf5VYGpV0dxrk7QKchdOlCeq1XpCcyMQ0jXHjB8p58l3bJriRH2vfdDCPr_psD-c2uHek","p":"3hxrEfK2oN29wlMQXkIkn1mUO6rPpHo_pn792F3r0X7gVPMQac4HN2iB7xwBewL7N2HDj_BlK6tUqz047P0o2w","q":"0aiW5Ptm3LzYJOdHxeE9Q0D6CYdCwFZZfPIhLMrVFvPKnePjP4PpfJG_ZjOKmeKq77zLRchk_g82iv9ywbJ9iw","qi":"3OAeU1kEszoZ1qrxDCBCA7bjzlIQKOh0jx-4MTg4SZSFw3XrwFl-h7bLp7KfbtXh6dF8cNmj1JDyi4qjVf3bxg"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"FhEY8HR+EyZOX889RYNyv1uGMLpm90OYv9jVIjv8mIGJFCJEdx8e6KrB0eDJdep0TT4S2EgEldFdzeVBi/HjNS5lhksS/9rIu0KeAPB0USaEp6+bCNP6RzU/J89Q+woJSwgM6R9LmxjJB9ZaPhC6G6QHDB1/pniulalMxcHGuWM="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"od1I0wJG0ugZ0hxRpJ1OmGxDW1+f/XlDr58bgIp23UCOMs+LIyOsKM5y3tlI/diQlBXG2bajaPbWK2VfuJtXZexy7J/UFr39pGaNZBMVsIrXnQP45ZKAY5XSwwQ672J0eSH05wqZUIpLCkZ/S4wntceY126BddMHW+gjodpGw+U="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"lfB98gSY3F3jc+fuOsD3xEVyaf+r3uOehvr5vSY3ieHQBus5+gUKNPVcUNAmQ6i3drVgfbUCTNy7RO+et+2ndumHv3aYH1iguW1UnteSh43CU5SKcyl3IhUBCCmlHh3rKHGslXDeNKfyPfGw3M+D6+1gAM6rA1RJF4/+mComEKA="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-1","modulusLength":1024,"publicExponent":65537},"jwk":{"alg":"PS1","d":"Cf1JIfJfdkKtwb9Mnyqppe-rJxDQEjEEZbR0f1wOuj0Ouu6S3GjTlOqiWvtvd4LJhlEpjUlbPTTrbINGOTO-qMiNxOSlsmpYnrx8CxBJL3qukZINSBxHzN-DpqqEiRukWbtDFv-3jtu0fpqKLJw8jzeTgf9cHPzB5kPKBtm_G3k","dp":"MvKjUYvfxO9yyWWnQRaQtpjUw63ep3JeubWlS-KU8AsmECQH1iya9-dwYUa85LTQdG5eAajxKD-W8BN_bdNQ5Q","dq":"r5Gcab5rrkizvqL20n7tl57WYRO8cVNBo8DL2bAwZ66ZCKTO7zHXRcB5D_E7k7qB4lwcGu7AcycvcH5fdipkZQ","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"v7SrwjFud_O1EYuvOXF7D1D3lYykPsBAEqeiIcZvRJNM_JMQCniwvpK5R9_MpWNndRHBqgKWkZc_mfPC3ZbkFcPQaPTLj-cYRgiwpN0wf-JfWqT5wa4thODDC4j52K5bKuOykqtclqNaFpRiORUQ3QN6brv5ml8OXwZPMtTrGDs","p":"6ugotPQ-sNkg5vk0K-f4dOEeX-9UD29zl55LKsEokhod9N8KYLAXInF4gKaG_vx0cRWMX6cB28bIxiiM7_K4pw","q":"0Otw3pG_GuHiaAx7iZvn6mDn46yjBt-QjMvU0gZXMMJ7-5VeQG_ib32fH751QphikIpl2zo05WpLFey6c43CTQ","qi":"Z7CUJcDXYBUrV6_O2sr75Mpohj2E_p-C-gusDNRQna8tXHA5QP87LOV27hchAmhSRNdCHQF3Do7YjNaCMT3WXQ"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"hMLS77KCrFqYSl9Uu9rdpsv5nu7ChefZdT8Ga1UgMYmYejNsQGnN/VNNo20y/SHGEcvRIlpnC7J5kHYx3JaIgoF8hrYt7vApwJNEkPqFoBxCPN+DtYE9P26wfy0T3StRRrYkgewYlEeajBvfE2a22Z9VXwn3OOt7fCLT2RUfEBwxo58dassjxnQgokZSRl7Qu/fqpaKWZbfAxExe2o3wfvnsNXoy5mdDG4PKjutvsEw2zQ1wlyQp2gRQ/0jgYWcvMq6nUoicVmFlcI9A/d2fZeHrZpvrnCpro92Xs8MEHIFEMpn7cjxgTo1c60QD9fKUDC69vIJ5A1YFU4vsgNDNHA=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"FKboWw9kutcjIqZc144MSDjTy9ObL9mV8zHZOulClp0MYk5Vcs9Y14pcqvIh1XW1XAR79iLPBrcFqXm5QHr6+Z7/HTtHXigh6Tm+me4FyCYWIV87dzuumYHE602z8PTTKdmpZRRC0nfEwFwCqTiGaZJ8L3xMhCStTVJzeq2te5vWLCSC8oUNGs12/2CMx3FbWgA7sGCoHLIRz01ebLblh1eFTf8uDP8PqAGJeB/jniySRqn9I/n2AnVEimlfe8Gyrlk2oO9WcHhAs1oDbHabol9AsmzyrQX9BP5IOlROcsvJ/9GX3vXKtayNEK70raaQcZ2cMf6vsYRwXswJpnYpJA=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"Jp5CR41JuDK4VpPIyxlrHHcV3iRC5Y0ahxRVotsVe2y2xkqwQj8TWj8UE0zquYL2tIi5BczXIlW/c+MZRU/a62GE8Q3Nm4LA3LbXNAnOHyef6WYA7anG32TkZy0WpGHoSdt6XQHKEXCKuI3GPa1pTtbBphLAscHljvvoYn2zthkyGCRVc7ohnoTOqbhb+7KhrEnzzZaprS6g3RSLt2hhHcjvxZIBgrwZHPWrjVmiODaSn3aNrBr1Oc0Wbg6DCAVQt8d9f+oT1e7X3Fl9fGqggUcZjFmLWrTXiJNBEbP6LaTmdpob66NTk6xPcNNySdh+2lKpDJ9cc0LEGeVLju7BUQ=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-1","modulusLength":2048,"publicExponent":3},"jwk":{"alg":"PS1","d":"f5p9-fPtlDxFxW7KIdK4bi1bzuG0qqA6lfINyw-fWKo5t2iUxBkK4L0TUpeW0K4gXiP4gnb8EBddB-5sjz3i8YoEpUBeNykt1PjkFMLYkA49xc8pozKfz7qC3lewi6_jKyW7Rj3Xj9zZykSxamnOTWEmyfHAKkJ_jtWCXzFTDYiK7WIcHuLheIBZ30uok-VFu74sZ3V7IHS_q9CocqzY-0G0DF5Ehq7AHHFO3D9NO3QHwcHaMXRMNaKryc7dEKZFSRzpBZI0Y6d_xuFKoMMVH1__o7MsdNZKSthS9mL-q31lZW6fAXkhA0VrTloIIOqKpfzqmQ6fCyR56y1qUUDMKw","dp":"mDkWcLU07KJuzcihk9QjBwGhBp6zse-NBJJugNxWEIBQzFObSu2L8fpm8ijho299l2Qt48RIOhRQue-GQa8iPyAcXvfdP0nEGa_xGrGO-f5JIDcmVL3ko1ns-pnBEhkT2LsWi4OYzXRCg0qiCbBh4WUYP1Dt90ZFC37GRZ9ob4s","dq":"jxBvWyGhYNGDYXWe-rwguQi-Y9Qip-mhL7r6pYiyg9wGBBNT2g3MlQlGOqwr98sk1EKiScU6QXb474xrmQJauHLCoeACJj0gFaBVsc-rEcC5rU7GAwBeexZNixT8csTVShpMVbLFRrkEOao6NKHwyQgQMpzbLOBl3nD7-jWjUWM","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"v2e89u3kXlpoqCYvMrwUpUQJtlKO__BX4OsUsJdvBP9WkxzfJiWQURuc--NiOQUwjTX0w7J6GCMLi-Wi1tzUak8G9-CNUr3Ev3VWHyRE2BVcqLa-dMvvt5fETYOI0YfUwLiY6VzDV8tGr2cKH561dBG6LuqgP2O_VkBDjsn8lE6LUlvb8JXGYqvNrFJStj2IqSxiR3G_dnRt9da2Q5AkA2TGrPQeQwrqsC25ifNcsSGtHNsLmHIroWJ_6KETozTbSfnezCpm39GGorwisvuxTZQzvm9GTKYdGJxE97DFThnMWDpAU8LPyNI8ZNFprNvPnLgKykOkyrcVyGd_OXLTpQ","p":"5FWhqQ_PYvOmNKzyXb40ioJxie4NiudThtulwUqBGMB5Mn1o8GRR6veaaz1SdSc8YxZE1aZsVx55FudJYoazXrAqjnPL3u6mJofpqApWdv1tsFK5fxzW9Qbjd-ahmyWdxRih0UVlNC5jxO_zDoiS0hekXvlk8ulnkT4paG8cp1E","q":"1pinCLJyETpFEjBueBoxFY0dlb4z-95xx5h3-E0LxcoJBhz9xxSy343pWAJB87C3PmPzbqfXYjJ1Z1KhZYOIFKwj8tADOVuwIHCAireAmqEWg_YpBICNuKF0UJ96rCc_7ydygIwn6hWGVn9XTvLpLYwYS-tIw1CYzal591B0-hU","qi":"JKf6J-_qPn6zAgDda1L1Y2u0bHjceBa3LUlPlUSEi7to9I-VnJckE8dSmpusxhnHQ98J4kTZmfTtaZDab_Qe_ajmYxxopjQ6_JwEnlXyKG54O4iNkQPr7z1_7IxphlJLPdm93nu7Wro25WJ2IWeb-a6SPBdTEUhy96Iar3FWGss"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"lukqxhLTeTv2GPeQIrhHbcdTVZ8dSsXORXezdejKqXDxd1KbuvVAMjWTfeo7twDV0emXMiT+tRh+rfui6kpcEi4z3+86UaXTOFl52Xb1I3MDCNqilbpWYuJc3PmIhFdws8LoMy+KGDTM4/ZskVrZp9T9qvud3nZJ2TxKnBZ5aYxXMB+8bW6qIEdTbShrrGNUFu6JBxOGROejPdOaxxZBN74aj5MYhjwEWEMSZGNqYgGXKQdH2L0KDJDhn18+7bnMq18vwKEgtol17XjE1rRL8zL/pXHqkasv8D4cXzwwuhFdOhl/PlJLh2gYljoQI6W7CpRm1ZtomLqv09RwbbZkvg=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"nILlT8NqtcqStdOmzoAHYaF4BCcEuzwP8skDHY/GkLqgtVssk7IF0a7erQBfDumutF5NJ6wM/nrejAsNt5i9GNpwngaWW75B735dJb9jgaE7I/pZhlTP1RvQym1kKUHeg4v4MScYjyImUMsSpdfaJnutaytGOWwyp/hxi6fbmIQ9jHQ7ZXe8BPft6Y1kDFdovAIMlfDZN1u89V3MeASivikDx0t+URctxp9ICRUkRfOSnp1XRoHO0ZSU5OZfnQKvjBOolqSP+6pLeANOvFRBO0+f365JFNqm6nBeUho8GHzT29vLfDtTUtUar3twQPyIkzboiffD5rysW1wfFHYblA=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"E7hINaUiYZL4GyyKLIZSfKyv2KFG3nL6MSs/Th1rw7rTIxJLTcjecDtCV3vIRqCKQSjMpYTel41MhWRhueTcx6JUy3GVZNcCuzRAXNJiIf0D2HIAXvgvw1bVlb20POtGCSTeAnxN8MKUUP9hZY/7Z/rB6aA8wpMdQXLnikDTgl+7mbDDfCPS9Kt7Q4B38HK4uIaAEmON75j8kJtok5rEq0laR+L+RZsJQ0zZCd9sZaSL1mo5h6ttZiKIVlqZPKDR3T31gM122CmqTk9j3SWEPfh+7+rbumSN7SaaSfPHV16FZRQeb8wKmqOGzmpSlXs1smI8bJsGNo8X2/r08XbnVQ=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-1","modulusLength":2048,"publicExponent":65537},"jwk":{"alg":"PS1","d":"PAd4bugqKbFRzisBVbbn9nn_bAY7T_n3h5avQ480Vkca0THNC6_-0lvyMl5vhFXyBg_snnYwQqJVLHncTADvrAiP8Dl5jf_3slTJ90n1IdpbNNr1jXhcaDY9cCihAmMnPSvvB6wnnfE5FD_nvZAi16Vyh6NNCySdnD14PbtAXuzxNv-M7dEdw13BljI0rmjqEgaUUTtem0cRwVVUUefneLEwS6mjvXel6IZWxV2ZdHaGmWr3HMbRe4Mk1_zo9H72CXI2bfZokThc1TnV04KWs-YXMAlMzu_9jb_P3dnQGPPcjMNCArygOHSWJ_AT6_sF_UstwVPaaDRmLy-UZNQTQQ","dp":"jUTb9BMA2zKs9s7_7hWK47sxUS6u4NN7oVZ5UtFvXeg6TQ-Ga95IJoZDRnCdCIpFav_-FSZRvtenIwGX6XiPDwJg5fseTMdFD2lClGczx6Sf2K3_rpKXwOra72mu3M85aeNnzyzsDCbKkTUdhzpjDnCi4OHr_cBWB-paDaDUzuc","dq":"hV2XgaIhccwVMOWHKcoQ-GHcFUX0K39mE-L_L82VyocqB5SwyiWxksiW-YY-Dp5_upJD3Wn0EcpVwG_Hk89z0nNaN6CBrBHmLCbYvoLePcnxtbTvhpwdxeWjRS6SUqsOEj1UDnWOCqxhaX2Nd5vRbVqs0wmXbCpRkX73Ls928hk","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"tuozNZGOnVh0KasnGLZqI7shcki9j_0K03aVVQ-pmuq7NPMsAnDFUxzbv6N33iqjouXMd3CVOFqNY1nZgWtPPCJr_UFj1RLfszXl9UlrgGYKj2FL2SAQYn1INKJE-bem4KmjM_sKQtrOBt4Z9ww9muEge6pbfP8auDFgo6FUDtQ6aMAB8QnaJfdjQcu710H96qtNz-s6EMsu57upo-VYWQnd9Ni8qnkpCiBDnlPiJrfBPyjs6vsX91_35cs_IV5gufMqO5NQxRwi1N83tezS4XD75Y9g4l1KSXPoSBCgf_fRZK0nPiOQ6tfcz6QhDv9x6kXScUG1hSdGLmJNO3fWrw","p":"5xVHYmZa1glRLUHmnVWlcRPb9wdrMgoV8nrwwZjzDovr0Sm6LuQ5dekFi1ZxFz9TxQUjRYcqUCXDM1um8sUmDCL9K_RLx7rz6KeF3eDIEHZVGvGrn1OskvPJ2ylSyx0bK1vZS6Azr6MClnkz9Md_mXunZgPtxlRUKmdoy8VBs-c","q":"yqNN6vCj7Yn3za-snoXUcFVNbjWsjH5teaWaOqfRwQ7DlC_KuCh51tW8CBQ5dQnD7lM8oyfZ8UJw6h1ItXeAbgI5RJi7Ae0mxkZoaDHiIF8N2Db3dObzOMQaiO804ikQSanMx0-unmxK-9JLFheduJ_t2UIH854m377oUsyF7fk","qi":"cZh_OQk07ATamnFcNSNKkZu4Pm4J4xlx3pxjVvah46I-OBJi5xLf9F72DI4IF6iava0PTIOKZpAEfw9BGyZZiZ6ft1EQzIJhZAa9ZEHD9xvQB_MZP9SnVqyw95ETLzX21Rc-71Ev1CSvbDiR8VPDHTzZ-s3lGaK4po7X1IvllyY"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"v1fQSl/XdTKOsEN9Q9YdWb7sH/Kztlk422+H41mlxvmn5PpeMwvG/gSbTXZvxnAcdHS2cpquo9jGum1Kxm7LkQ1dQJZat7yV+mY32q5Ld6YhcpEjRU7f7rjsh9bum2HEu1UeCnVl784Rm6Pwkrie8pqMkob9T2PnqtBQoxTsDjI="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"pL8Q6MDoBO9ej4qsEqDaFFwvFv3T0MjTYQfwdZ1aohvXZO41/qSp9rbV/MY37Kh/fBELLvhMFgcHK/i/8/rjfSbhsns2W2kVuDlVepRXqfk/UdHvqoiI7TnI04sZGP457Ela9JFgRSjMbpRXt09sle0qHxvklnLWVggC28gvUmE="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"4afqrXdAA5Jtcj5cK7kdukYHS/giCYP+khFWwyfvz7Rpg9iyoYvO6PvGPg4/JTPwubSQeL8O3BUsfPUgEX7d6qLcut5vc5P9GbFoxXSIr8cBbOPiFxukCvgC8UaDMqZRRLY35tX+N8gVeO8urueJTIM3xuOM37NRZKH6/5O6ilA="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-256","modulusLength":1024,"publicExponent":3},"jwk":{"alg":"PS256","d":"mTZV9AilUaPQvHRGLitlDsuoROgd8hNJkOEkRfIflMaWpqUmAB-SVED71SbKYGSCF_gtUtjxUmRWRgnRVlfNTnjSptOrbKgnR5Ray_G1XRTnjRhbd7Ubuw0PcZMPCRloagDDkItzahvW7EKi2ghpIAdZrcESjMQm4ZFS7QjASDs","dp":"qDY33-TLCGnqRAQ-iEA5LhCEnxjjzxwB5avgXv3PhCYRe6KeXyn_ih2LgvimDNlBrKs3CWd_F2ux1u8y7tyt1w","dq":"m3K-vDesS_rBpFGNtpfdF2HJvszkI01iX5uS2e-SSHdpT34nycBEGfqoFe_UTTtkdt_NlSY_c_Wety2fLVJ-cw","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"5dGA7gz3-nW5Gq5pRUEXljF8Z1ws6xzuWVG2aOsvXynh-fe5AC9bfmF5v7ovkJbDI_RD_EVp-5aBaQ66AYOz95q5bCer1frR7TsI5EjULQeGyTFh33tHrvuCVzH6oFkI1zHWgg6MhJ_mr8lQ_pO8qUBXC49wcPdMSy8nnrdnLsc","p":"_FFTz9cwjJ7fZgZdzGBVxRjG7qVVtqoC2IHQjny3RjkaOXPtjr7_TyxRRHT5E0XigwDSjhs-oyGKwmbMZksEww","q":"6SweGlOCcfgidnpUkePLoxKunjNWNPQTj2lcRudbbLMd9z07rqBmJvf8IOe-c9kWsk-0X7lfLfBuEsRuw_u9rQ","qi":"eMn16035jVgEwZ6tpmpZzwa94M1npbQaqp0HfSopoWgRALqeIuS26GZg1syIZJ29rS9BWQ3URXoXT7_t5RLN0Q"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"OKPC6vzFEqHKgCC3OKROfTRF4/7/CEALXRxQCfTvoMNCe9pdOvi3L/Aqsc2Sq9nCF+KuaheeDbByk+98wfcywYHmPt6RcfZH9lz1L+MQq3fc0BBgVqkNaPtGOFBlb5z0eqTgb24Kn0gxDZ05der10hf4yi5U/pVrnEwNvAFfrfU="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"TBhqgw9XhrXdPOiuJ2ZOPhtDoklIO79fbxgvq95UN7K7EQW0ZfWY9sIxEP/3gzbgFuOiBVSsTWUBGvYbhFJn8HczZo7GKD4i9KpzUssSBJ5IpFJ1QYcM7vAT7PTkB+GcAhT6/6CR/ZEbEIDmJNzaTX6Qes1UIlVlXJXi1MmEGQs="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"Px5PRO61YPjXDhvmaPxsh5WJoCijnizOflcer2iNMGHNennc6DDkTI9SWk3sARAcyDG8sw/xdxR5+AqIeEVO0iXVWMG9r6j1F81RvqMbPpey5ttEfBBpbpm57T2igt4QCFVjvmr/UNekaq3fukiqGA3d9KpDvfe239IxaCL6/cs="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-256","modulusLength":1024,"publicExponent":65537},"jwk":{"alg":"PS256","d":"bOaX257xOnR03rYUklaXxrL61Q3aXE-1C84g2_2C3g9D-t-Uozau5NVTrKRpEXj2x0DZ4dzWqEpQWTJPe6Qv3Xq_Zpx5qwU6l1Banofy-CtL6T6teeAKbDYF3ZEFwKr4s5vYQAbWis36PeEWwuCLeS0o6jlzvX1ATxxXviTTK9E","dp":"iWsv48NtAal9qcJM6dRlAVgnHqS529hItmIGz9OvwMgeM-vh0ABefd0UpSrOFt_o5EbMBHD35kcNJV_h-NyWHQ","dq":"RbU3PxEOG9j3VY0JEe2k0exNSDjTJChzFlR4PRccU5s9TnUR_FFh_UDmlWbMYRqDpFH6wK_5FdnzLude8rnMdQ","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"tWQ3WDtRU2jkNlxIJTyxN1XNlrsynuY0XDP6Lx8h0T77ZPaQBHIpYJ8E6yrIuJYQlGUkfg8tH2FM8PYnXQAChBJ3Tu1euegOZqdG9iSwUrWl-X7MA0bEv1NJ27wfhUMNU-x-iw3qM1UE5xAKPahpxyHp6_n_38rUYvF4DVTl_Qs","p":"8AadCoXiFRmBik4_vWr-p3RFcseZVW4JLKkbBjgROVvZWw0sUEdiTF88m-lzxlHU5P_3x7RgvijBeLXBk3dKXQ","q":"wXaiAuieKJ9Eej9XCs4uyQE6LbqGF6wgKbYiqjJypAqtbnPUkHBhpCSN3nN_d7zsfsVXCftK403fGIzSxbR-hw","qi":"KhP48qtZZGKn3nvwkRENCWjR5X1err1pPyneg7rLHxeB0EcOan_E3iABHSDA42xrV2jteG-Pw3Npotbhk1rOFw"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"qFZ6gkpGxCXrX1PbPLeJ6jh1HWxuNL57fQ1LcF+IiBmbAJ4W801UG8F3XHnYefHOl19Oyv5l3LQ9o3+O+6TW3wuXuhEgfUsxPe1TNQ7sLqFGA35AtLo4gApUDxPDGqOpyqxruGiI42rY888CkN/lyaXIQ0gv0vcx1Cnug9dABanXU0i87OpOrp8NnVcAx084ShpdYIv0QZHl1oUNF+s9H7rV8UgfhT4AKNif+yKEcHlm2Ubt5UcW3Zd9d3fmYlvlEklmPu32/Bh+ReqfuPW0LuwkwVI+txrOUQHpYsKSzratVQTlJWpFGPSb2Guur5L88bQLtU6vwtFwDGvj3PkWOA=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"T/qZyWO5tZIVVpUdkMgnrJ0VP/7sbs/fp4TlAOfPNCkyfybEpDBO/z3QW0lT8wSpqntFMSYRSlD1jnxZ5Yqe/TK7xgU1gL09rDLm1TChlHRm+lRHhww0M9u9VTOEegEsTwEYffCvVBgJBjNNLFDu9F7cH1fdaslPf/3o8ulbAPgRoi/BgtnXvb6LFMf6JDzD6EGUtvwAHs/zOGQgFVl9jDrzm9UtKgvcWpZZ4P/PBN2UKRcGleO9zVMMv6AYX/O5oT7YHGHOvIEHCF1/ZiQRRgQbIAQTsxMuqwU8L1OnOUSPFz0dJHh6z+6MdLS+ltYvPwpViupB8jjo387ujMq9zw=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"B2kysuBNkSt/FlEfc7ivCTkYv8dIrTnsWov0axx7i9k1XxleppGgTfS619RGkCnLICD5wKTgy6sjUiZPFOovJjTsh7vaYSN3vKvQkBN5RXI1VMP2M6b/4VangJv3XnGyqoMnUwFd7/6EGgf03vc5q/15n6DiHca8QHA/JRNagoJISCI7YyUBZ2Sp0YpnkqDuGAfvcBk6RcpzgSky5ZXSAn1ey8O1CmU1rh6uk3Xuqw2Yfi2FGcdr/Qu6pEINe8cAP/Wa2Fbx5aNyH6cy1+TtLYHRpOgOp2T6JuBKmKJxUPGdXRR1655h8G704dtg+RFkyhhx+NGX9mw0cll3hIrIGw=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-256","modulusLength":2048,"publicExponent":3},"jwk":{"alg":"PS256","d":"idkwPLdFGbPISXH_H3LmTbyRdywJTefQLO6_VXh4ANAKK-SS-L45EZ-XxyUZK5LK395TIOw0NrCOLB0G07sUkJEAL9eGqD2maZ901A9BktOyZQQnHeI0UZ5euaxOof6JRnet-yowMLeverPLrMDsDCN3P98bJGpU_216PyPFplmE9X9dE3zFrv1Ee2ta_dUCy69KkLPPd_ZGUXdWcTyMLvwBz-mXejhyywOaeMABZSMET4HLFakwfpzMzp8y6_mgcE9yy216zvgjebSSfdBlVzRUpHnRruwhzLxr29JOXMXtvQ80cPxiOZE-Lhk69wi7KtFUz5QHUaQi1Y6L1fO-0w","dp":"nyKoK56_6N4XwDTF0GdZ8-B2xd26M9MeyfIAcUzPz4G5qd_e6i8T0Pl7Ze0O_w0W8AuvVKtYIBCZzSJY8RVG3P2cW8i0RS6g5eCWHhz1TYQaSMiwckSVwwaafgtOe_-r3sB3nGi252nvVy75iDmsFVuAONZRqmRc2wwFYz7KcO8","dq":"k9ZRbtBB3VQxCBqRJlhY03HmscZ_IGFUoeVLpc5Zzfc3qMbbeGtCjmiZtpebmXLscSh-eEkDZgfnwIw9A3MOHwE3rCNn1on_Y3tN16_-Yb_AwSAtgEQFPia6OHcXnxVyXjJ5Nk1FaTU9WPhbB90aqEBQuDeI-0Kq9U7jn2f4ikc","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"zsXIWxLnpo2sbir-ryxZdJraMsIN9Nu4Q2YfADS0ATgPQdbcdR1Vmm9jqrelwVwwT818sWJOUgjVQiuKPZie2NmAR8NJ_Fx5nm8vPhbiXD2Ll4Y6rNNOem2OFoJ18v3N6bOE-L9ISROHOA2xgyFiEjUy386otp9_fyQ3XrWoeYgT5bVzQ73R0ekTMCN6nEuvLRMjT2O1gp6LPSUkUpk-e-P-sfX3HtY7Q6USfB_m17mYRYdkDwcR4q2Hu8-7LnXqprU4E05hy2SjQGTMcCYe6JcN1AOmU0q0dxmzjVSeKtZACAAKunUMRRzlgCSwlLc1KfNozCYDdQHsyLNVuxIXDQ","p":"7rP8QW4f3U0joE8ouJsG7dCyKMyXTbyuLusAqfM3t0KWfs_OX0aduXY5GOOWfpOiaBGG_wEEMBjms7OFaZ_qS3xqia0OZ8XxWNDhLStv9EYnbS0Iq2bgpInnvRD1uf-BziCzap0SWx7nAsZ2TFaCIAlAVUF6f5aLSJIIFN4vqWc","q":"3cF6Jjhiy_5JjCfZuYSFPSraCqm-sJH-8tfxeLWGtPLTfSpJNKDj1ZzmkeNpZixiqby9tG2FGQvboNJbhSyVLoHTgjUbwc7_FTj0w4f9kp-hIbBEQGYH3ToXVLKjbqArjUu10XPoHc_cBXSIi8un_GB5FFNNeOQAb_ZVbxv0z2s","qi":"lgh5cQ9ps3PZdvAe2FW1oegUzZF3x94YP1l3cL9NCfnUQjsp-viB3i5VpVbJlhrAi5CD4sMrtUjNWcLYOquKLySs_pj2GukpMR5AzF39pGreUer6qVtnmO1_2LtIvYAVUVgUrwJFRCS-1OrmUvQfxteFghV6-6c1dlSjRC9O_ug"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"oqPWmSZeKEo/EPsp85cgICwd8Px4EzE0TDKD6G4yqWjmoS3lhjQg5A/083FQ1tY3RIcsZBk1XP3pk2wVRHLihWHKi3jok0cBAA5Rl6kXVwREnJm0YH5gXwnBu7Q/8yIBbiki/00tPNRFfttxx9sv7ZZhfansWqFeH4w++XHNZLLAn4fDFM/CABbPzafSLvpv57Lbc6zZExqqRf6XPcGYXp0dZRAoar6UwOvU7mUKpW7qyccMTXyn3Qdbi2qgY0BtMDJ808hE9P7UgqnY16YcSknJLBmHMqQVlocU4ZpHqtY0CQ9lJDYfvQinmzYRHjLm4mCHR73HW6CuUDdWWBYoSA=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"LqF/tgZ2CxA0My+tZ8d3wOYNk7tgL1feeUiVVYkdqn8ra4r83D74gPkxnSn2+z7PaHYMSo5Uhwjo3n96YA/DOq9qD9AahOJJFpUQGNCmXKmRZSOkkWpClt+AXFVYVJTfilgZuFM0Z5Rj2qyFatupetvIZM02kh650TQxm2HjTIvBiaGsjoI3JhmBbQ5NceDO7jtAHUwCKUQC1Wt8WwDFQIyyNhBKfflC082x2uR4Jqhzjy0TnFw52Dp1jcR0L3DtpzsZ+8Ma/yCnstPzDzLZfCo+UUnlj3J/WJ8woGbbcWjuAZF3j/sMfcYGOuJeQKW2DET1YCcjCiIDfXRSjV9yfw=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"B0JPoW/TApP5d3fqB4WW9gxlq7NEqbduOxCqYzG0JuGwpnORxBGZ0GLCstsQgy1eqfuzSxPdAwYM+0xT54KNfqDM/mxzJgBohCnOaSazqU/spPHNU0j4Nh1zPQxVI+AIkr5UIAfiS511IwwgV8IdLGsDOVRVwwu3wpr9UR4LWXiuHGYESiBvfVYKqEmszmU3wK2DDF21N5/Av0E4L9a4rU97olxsLRf2Q4lYW5IH+dMjpPy6/KC9Twyoe05zKK3eNKsYFkU9R71bCPfnrS8vispCIhY3ctOkqVyvNCHQpi5A9pqf7qmHAZwiIxtnEN1NezmPjzpBZ/wKb+ATwf1Oxg=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-256","modulusLength":2048,"publicExponent":65537},"jwk":{"alg":"PS256","d":"jVi6l3q32HdwqTuz0XqS0lYHav-h-RsMlO_fhxIk-kYYiWoc11_r8wmdWmywlc9XkQ6z5p-DY6bxEOyacVwaostqsUf-82oCFQc1aAIeSIaLpKGee6PPD5VYUPi8NefFGlXvhh4Ihg5kaMYOiJFDYDIUMUDm6SGM7s8b1MCXYqZYqrAOG5orhQOtAvkUM3QPL3OVT9MYIb8DaEy5Yprzsn21UnTGwgBPyDf79QrTd2tt0EQu6SALeBdkZfQdPUbWUeZUOkr49W_rpDScpUg9L-2ZpLU2lVVacjob0qw-oQGKZYeKmVGje8KSoI2EpVDjhL-7GO_FN9lwvpXfLqVH0Q","dp":"TK5xQ1Mm-GTqBPHE0s2awhkCjOWvYqrsR8O7l0gj2ArQxNWs_wn2zWxFGnA_n7RJCJ78grtLPk4KNTxc5JmAn-N5u0KzVvEU86ay8FxiehDUJF4HZTypCFIBaVucE91X0MjAkI_EMDAW38zIpOsu3NAaqFc2FBleCgeDvZMUWME","dq":"Y2Ft7GfFHkGyhGP7MkFMNwIdxvpccx6aEhXbqFtQ5EyER_O6JeTn80QjpWalxiIqOFupomoy7MdGavkeBenaHcQ50iD1PXaA_vtMc9Wipv8QY6o8IfYcXuGmsCru4IVaW2wAisdaRnXeQmKWOAgPiCDHyXlZ089_-uQD_InXXak","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"s4GouK-HNh0GqmdlueqUt9mXsz4PGCOgan_1y6HxuZorZ3rODC1v7Kkp8YPJn2TQfidIt2gDJqGOP8YdXhVhf45n7m6yDv8FLeDoeibBQSnnhP_P4wpgXV0O8sZd5oLy_5Vfa6Qt9PjIzrKDs4s0HrlnxVReUvTDomF44M3K9zrJpGVEG33rOTCBacsLctE3jrMic0R_q38kpc_rq9F0o8IVNom070vEI3w8Uh1phLEYq7m35nPlWmdmdi2E7VQPAid1v640Vws5lO5TXBts2IiFU-vTCNHprLTiU-UAS-G7Qbiqawl28SgGAzv8RsYkbpiNjB87wDanwFnwkrppuQ","p":"48SSHt4lojQB-IaEmezZwRx1Bdm29D0QXh7a_9uOwrkAXgJvQQ4tMlg1iuwRQ550LQSzWZHkFFe4wGavQcqYhVae5QphM9hpIM7hovxR8V9mKctqChJbw8tkAdJlKy2eJSKLhmiSSQHAseMjSqwiQDhWDNS6JO-wNqSjbH5xwAU","q":"ycGt_EU549rELQf5c5vxB8YuCPpdddFxnL8AsxXpsoy_kEfU77xa2UkvtDTO2vdDiXm-Om2CeVkk3HQa0-xloRxnA9gncp6vbQqbI045_XG6leZmZSyiIZOHSU2Ql-k_XiYw71ydwp8-ECcFXZv7XsyQiUuRht69S4Kx_OfoVSU","qi":"RNom7l4l8OYkLZqty0l5t86hbs3AY1wAQUc3W8VTHyVh2Y7vvu5TXPqym1JA38cNtQiXK9Cdmk7llOhrbYGK9XOgBljNOoHgJqq6i7tDN003yUTVoGlx1Xlj-jIKqCJkW_B5FR8jp8eKSTcoD7VHgH3Pv8jrFY9SJ5rmbTOb_kE"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"GnVy86wWDK6753bmbHftpHbG0ZXCzlvUkrbkCu1n3YQlLeBqOpzJ/yIfTFezuV366RXlVlV+h/9D//3+XU0dpetpcctjr+E3UvvPX77KAG+2OkTYQ4DyGOSp+Po0AzxociHT7Trw8Oz+rXPAeXW01AitMCbrx4sYE17bVwn5fHM="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"ChRgmekecp/fe4AaDEBkuFehHNBgvJF8xKnxjF9UUGQM6C4lEfBkus/D0BqvFHeXHckIrD4nYuQN7sXMx1IAkXrIYgpFW+bwTS/NqWxvh84u+tXqkc4jWuFCZUyhSWPIf12VExmzgA5nwb2ytc9TjwSK/mzb7m51jEWMgHyFNTs="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"n5W1HHUhtIHNEvPoFngRh0aYpzcq3riHwO5CEpQE3m+har42D+PT/pIV6gENSo4p9US69Im2ezQCi0JEj33PA7adacmBQ6Syg2oF01vYXjZwYmsstos0zIF4KKycw6FXiSXx6nQZj7rA7OGgJTw6amEPg8ybRVYvRHUtldpdtc8="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-384","modulusLength":1024,"publicExponent":3},"jwk":{"alg":"PS384","d":"io9NZjEDTdo3M3-L3-EMzgtkEqjJgVviUlzzWw7KNzKbimIySCDDQugDdpc8E26QB3gTl-Esw47m2Jdax-n1Q67Tv_sBcB1Wjm6x_0ZnJ9OmrebAjDIz_uDiIEI2BAtaez7KkDBHyeXX2GMwVMudyZdXIogSokAEEln8eFrfTKs","dp":"obb--T8z7RFenMwn9KoZGUfBNyCzBoelAQta12Bs7BIybFVNsmZ3XJii2kHT6GKK_ND2xSDh3V5Ul_gv5g47Kw","dq":"kjrXYnL7-2XPt0JFEp1TsafmrrY3scUiT5GO4BA_BKiF7iMwS3C9PIfj29eWgKyHltcrlGuF6eMxjFmilbj4gw","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"z9b0GUmE9MdSzT9Rz9GTNREWG_0uQgnTe4ttCJYvUsvpT5NLbDEk5FwFMeLaHSXYCzQdY9HDJVZaROMIK97v51QoYYINcAi0myQgonSF3u3hgLLjMl_BKUo-jvZ6B_ofzWXklUUufb50jqXuns8DSkB-51JujwroZL11cEH5wIU","p":"8pJ-dd7N45oN6zI77v8lpeuh0rEMict3gZEIQxCjYhtLon_0i5mzCuT0R2K93JPQezlyJ7FSzA1-4_RH2RVYwQ","q":"21hDE6x5-Ri3kuNnm-v9invaBhFTiqezd1pWUBhehvzI5TTIcSkb2svVycNhwQLLYkLBXqFI3tTKUoZz4JV0xQ","qi":"69J6fgjB1rZUmrU99_mQwR9OF5FEELlKglqyWOCpqyHDFIlNxLGNNY9_3tlh8wPvSHbMoz_xO09z4H68vtb-nw"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"kIbcAXrpgJ2K0GSB5whYahSrMMnoehtRfx4QAOnWZFiXEj5huNOesF5y9VhqXBXpQXIWPUqs7zB51I+LcNpOuP0l+L1WpSwTs1n1aymW4jSut1bvhZ9YC1i+h+grkgnmuAWRA1oxgaD+AqqQS1Na6priyAKyTd9GzT/vgf+uAME="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"lVGW+31ZN/Qdmy0iEhONglHg+WrehmAeix3Kxz/8g+0HaZchnR/C2gnL9CcebGykY3bG0WcX8IOJ0tjwlHdPf/Slf9CLxDd36XedbLVMxHkAMUs2TfSdm/sl9xOnXU5oerqj4Koqj2H65EnGEJOvStVyY6iESEK3qaOnf5vWCdE="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"U6ehbhnA5wmrNRR5YXu75OxblM6guC0m9t5Hyhqse10/Xef0xbPEqfnklEphPdmas/eUhgkWrinzAYLNjeRCZM5XOVIjVuTIXiTb2pUHnkwEjQAzUBXydJuIsK36DRatXXom8rS892074bXVe5GDjdA28snJWKnQYH0wvj5kW9E="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-384","modulusLength":1024,"publicExponent":65537},"jwk":{"alg":"PS384","d":"RecvbfLsiCMaJ-jsNhqhps0HIeDR-qYLwXdEv3-5m1EQDut-d2w_mKWKSctMogbp1ZMkCmEQELaHBFZsuH51XQYglGI6ap1zqFQzk3_BQspZfTh-5yWlHpAiUocDeqJTQUNCUpl-HzdGSQ3x_h1HPJArj3JmQSKfAyHt8w-B-GE","dp":"ckXhOrIyo41vuekojQ671S1V5MASNd_7KF390hK4mq7rrhqyK2CLxS92cQdexWCGwCapVn77wvmMgR4cmsd7zw","dq":"O9YFawYVVzW7bhq4flBXD4BqxB44muRWystlqNlLuj1Jl4HFUQHFmNuJNR97BQBJRPgMfcP4vqWgYiKrY9LLMQ","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"slWn0WK2LWDqfrC6EDtkHcNo9EUysD9dHxJ85LrDAy-Ev5HMB6P9dTGlkVcw7uKNDfOFALfx6CEAqAe-YJiRdKnh5tmDEXv4bW4VMuQs6JUuhf45DfALd4d5388P9bnlCFcqcIKE0F59PVLKcHsC8neJLISn0KAVOTiA8KtCzPs","p":"7UZfgDPB6w8B1fop-6m9u_4cWx2ziALMaQcIlv6NvSWxk8XljzvXp6a_Ay-d3adAyUF1M6j5Pk80mowm13BUqw","q":"wGiFW5LtY4HF14GSQedsYmtSd8QreVxnvZs-XfdXILvBaEicfb8YAu2mTLRSzmoED3DtOCovb-ILBntj-hlI8Q","qi":"fTBlgMIeKHnryPcMLCYZkSUKKZsI5rSTouFV3w_aNXm3SMDOmk6z-nNfDfhGCa8qTc3O_Bym49Bcl4JodX913Q"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"C6yOxyhglZpCtX3bSCheXZzhXwFlC3eSfroq51HzGMg/6r3lTaTfQpHyoo4Im+u8HR2bEn47Zq4cIkKOQDOtPhSPVW1SyzMeF93lP/DOL396Sk0DPG2EePHGHT+pYu1R1Kd0yG5gsgirFLV/MLw9SUu83B+G18jqY5PyGH7PfVHD3PQ1IFuDAZXS+0hJtUg02f4NtMRoqqM3Fm6sAK+z0wWsf3EWcqzocrTJd1QqIszsstGxHnKJQu9CjUll8f8D1F6PDsM3yE89fdF4cjECNBdn0C4/kmwlMjRj/X3Lrl4OCkwLm3SZU8UC1tdah7AmggWNOwVUpczeHig6O/2w0w=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"csJjoi6SCZOfaZakeQVTV8svfbDqu+Cbb7HYTfB7fB+u1HC/WytssPmDbukLawx2iZZUN40MxyX+jH8LxdqrQ5ovrXH87/ehlluDmkMZTKmXJPWsNLlL9507Sq1RvfABnZQad4n8WOhxA+Q1AeTQoHtuTzbbW0cFpZocCwoKOCX+lRU+84pVzpdFflgXz435I/rny1qNBwJc3A6bG1Ma6AXTgjGzBEiclw5OuruiCos63YlPmAygsZ6++YXHqd3a4phqjRlnDN8sP9N3PMtonDUrlHbh3sn51iigZgg9DOtqc2fTaJp4kR2TPv/XBK6oxAnRqNjEOEw9wSWKg9Zz3g=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"KXY6M1oKNqnc58aOBCgs9n6ZEAFYW1FOkfq6l0j+jjsXzB/0Op5BeJWmn1Sy9/TzXAobzX1OMaFvUe5iI1xaJgmdhyBscvxMlks5GOvbkYSneJq+QquH5QxqHeQXu84UOHbeEQkg5aSN1irp9e5m6qiiAz/F5r+/33Hny/28CjBtjQG2Nj9WLD4x7jVWieDVcIIas2YbEJwOszwiaGRA/pWjgp8J6jsz2Nwqj2CPGUgX/Us85Yy07esuPonmB+v6oPrNBqsnH4smrauxH9xO1bkgaORW9+S7d7FAFQ5M1ytyDBj9uFkBFJn7XtILxiZBTRH749Qf81bSXxK6Z7ixLQ=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-384","modulusLength":2048,"publicExponent":3},"jwk":{"alg":"PS384","d":"e0Df5wKAU_7-PIzf1wxjoLmEz0A09XsIA41Clt7KlVSFdI3p_SqXbcBKQWek56qs6JPYhKWDhp-1CHUZG8p-Shnv1HnBFV2CoVxnp6kw8SmTpfgqFN14vcRoutdJXa2mPHW-qTT3qK43LG8TFqt-ocJcFUYpBBJjn3vfJzRKAtuPp6gRVrRIlIzq9YiCg-zlpgMBg8m7g_HaiaZRoKgK-y5ifqNr_VFav-sjbyHGinfF3oVH9IuI62W-3fH_Yb84TWslebOAFOUpvKjXJ_kAbU2Ax1tSsiFtDDZwwumBzJS1ISLMp19wy-5BZCyqTkkKgxa9Lbcrue8O0BdnYJnu-w","dp":"l5N4Tj6ivITXrhvAaGsEUmCQSGSjcIx7yLFdpyUhS3EfGR2w--B7gMZrvLcAQjZhPf8R9bB7HWgQbHC6WcZ0e0T9kguW8SnNDCLM4iqngZOSf17YyLP17dtsbtLH2JtTf6cmKJUHIzr8V7zXi0Hj_LXcny9Sil7vpvdL0GJ_nI8","dq":"isbgqrWYufypXGGFS9Or48nNgSbCpuyD-oLt_LsElrJ4IP51fObujc0shT0wS7BLVAk6s9TBMNhgNNoD6r8u6aWXcL2ZWSJbSB-Isi4aSB2F_SCVfOLLNuVr9-k7ntJH8ObbVy6m1tWPx5ZUE2YmAsaZqmufBn_8PX1lKXCIcyM","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"uOFP2oPAff59WtNPwpKVcRZHNuBPcDiMBVPj4k4v3_7ILtTe-7_jJKBvYht3W4ADXN3ExvhFSe-PjK-lqa-9bybnvrahoAxD8gqbe33Jab5dePQ_H0w1HKadGELuDIR5WrCd_c9zfQVSwqacogE98qOKH-k9hhuVbznOus5vBEsLAwGPcGeeoRTwLDVSI-upuJEwlse8e2psnOrwQTTjrihq6C7XJxkd_UUYFPt-qbaD2jrqNqvCwcGQPQhl2xPr1AA8ZFWvkZQ8_n2hQRgvLZj76i5kbVPas5ZDPmN110g4hrZyoJQgSreREwRtcXyO_1OKLP0a5Uhs5yyRzXL-Aw","p":"4100dV30GsdDhSmgnKCGe5DYbJb1KNK5rQoMerex8SmupayJedC5QSmhmxKAY1GR3P6a8Ii4rBwYoqkXhqmuuOd8WxFiab6zkjQzUz_7Ql1bvw5FLQ3w5MkipjwrxOj9P3q5PN-KtNh6g5tDUOLV-xDK7sb7z45nenLxuJO_atc","q":"0CpRABBlFvr-CpJH8b2B1a60Qboj-mLF98Rk-xiG4gu0MX2wO1pl1LPCx9vIcYhw_g3YDb8hyUSQT0cF4B7GXnhjKRxmBbOI7C9NC0UnbCxI-7DgO1Qw0lgh893Zbjtr6VpJAsX6QkBXq2F-HRk5BCnmf6Fuib_6XDwXvijMrLU","qi":"18EhWeLUnPc8Dkv8MVa7wUjPNoQxQZdCJaK_4cRIxcQ65Oyz-CwNFMl0l-8tHdR35_2qeS9JSBKp0ii3ME8cgvIvL66md6Pf8iXtnFX24ROKXgVrFjfmuBRC4540RynzwbVBnQjXv-1lcAsRgYMZHyvGOOlLIQ0SNXl6ek9OdVw"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"czXr2QbylSPbKR26J1SDYnf82ky0gjM9V+wB+lIdy4aR4G9ibiyELBusV1RQZe0xTNhSyySUCsCGx+IAC1gc7Rv+T7onNaakr01Pna8GfmxHFJm9624O5ZfskiNtGrYs52VAVZwPBCRM/zCFgOAhgwrquBIiQGdNzi4AG8VopcmhukYgrvTWOWMhIZqpbpBDbcP7RD1LFvTz5z41yBVUdT3JrfaNepgnfQW4gbZJl0qsvrJLSB9tp7mtI82+5137KH/sytO65WaiUG2AEvta2rFUUPvYgeDvNT5rCg3TeOCE0tFeHB1gOslj5sMsAeT5O3BsNfQ6u5FHx531JuZPAA=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"rASSEGGqZcht0/SGwc8HWFaWvl0azq7hn6reBptEPnb+OFs0gnEf1sle2g52yns8RSv+GGzlv1UzgFdaUekARpwaN+OvuZ2gc5q+8XLAoRFeJ3jKKBJZsim1PC46KcpCOWdfptKG0l8WVHFDE0uOCeyLtqw+wct7ICnrNN8DkMfwtxJ1lDF86v/kRoqzx/sYP9cuK5X1Q1bt/LaAhkTu9z6aieZIJF9KhuRZnwUwKFVyTPXGSbb8EX+i2Q54Qj9HXMqcoB1cc1wpZ9RJdRoaL8g8bCwL1jlpeWk1aGSgsVHPVIo5X4zm+ai5roLImUeyOj3H3VF67WsQS/ExDV7nMw=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"AEVHdMdO+CqVyr1XvAkVT/jgWiBDQk94++UCJgVNyTp0Ii1gO3g7G/S3IZ3ldyCabSwxBfAcvHC4S7gKth4ySfR+xPfUAoqdAemPzc5uUVtzJ7q/ICZV4mjb8VLfxCBMkB+/JNrrpnTt6KxE4denUJQXSa27fXk5O9yAzOsxFCKEYMTSPt4jeld/StmNVAwjtPwZHzYb4fqCsz42A/UXR4tf9jRbbo9AtfSFOph+W5QAXx5nDEM+52n7nwFjO2rWYRLbWXkn66IpndAOG664EAhFMD9CGsmGm6HzT4BsE3Jqr5FZEcHvIGAB2VunHni4z3vLQw3l64VrmtqWvoH/ZQ=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-384","modulusLength":2048,"publicExponent":65537},"jwk":{"alg":"PS384","d":"LTwVqUWlhL5QBBjp4qiampSgi5niycZz-KJGlgPh_IqiVNf9W2u1oZHUrhIBAqMkfbCFfwTVvXDmfsWcex4jaRRx-YOP-tpfOGuhzpAu3xacGPPQpIX5lFmbOd8I4e6qhBrES0c41VxgdkmiM3RcHdv6iO0zfhnS3GbUUNNgYo1Fyu0KOVFLL62mr8HUPNnQkKHH5UW2Bw6x33ZoOkBtmd5-uiHQ_S8Z9fIifAG2QsxMFUTnqFUhmvAvxeKW6ePkqT_Q2pX_oJ5TaxGqkpAYEVZamKmIvVI3YdEXBJgKmi63Gy7cDAhcuCkh0qU0Gyx9ZuCU0clfQRSDJbsuYd9sAQ","dp":"daW6emHPT8Pz6e0dAxQcKEv3DLCPJPvMg6SclX8uwO0g3eQdEz22J3CPEZWPN3M7JbLgEYGY_BpDoM2zQSfoBfP0CGrMuSKtuIvW8zi-WFZ6S4ADRKYwukZYVZcYf9CA7iPW1QPKY9629Jt2BeYiYNr8USFzhy4DbSQczF7mZP8","dq":"DC0Pmp_9jPEsZxdGzf4zvRD3QLylP7v5AZMJ890IgXfJYKFhFshffNXxw3jMMkduq_deUtHI0zrRXppoSm3nL8LWESL8g1BhNCD2CQZDMfQDx8SFkHmrSLSZUKuDn7ZoMo5A8z9UqZWi7UfpIVZGTXghYAwtu0hQRHs9UQM5WGE","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"tR5TKjfJG9ZIm8qqmPAxGQMtTDzIwNUsR2rXlw-j6q0mx5svmYqm3tWOYzOJNN3T-FIhRnrxxYvyu19E1B-B_V7D6NBaEC1zqBVuRFkMABXyOs5Z99huhO35zFwiDGFKHZyIulynnDvmRDlwUG5Z31g3oYdTghXJSzmRQu-At-ZLZdtikGDIC6vK4ahzQMmWAi8GcCGYVR2hvo07hzSFHvFDlLmcvD2NiQnwXQvO1tcXlig1n3JEbSjnDhLF4aEHuA5zetXWeBZ8QU2h3B2fZ5rmoqr2mDo5BhbG0ELl1nGIQuG12uziPGN6fYiKDmNvhzIrU6G2IGZt1XzEuKs4Rw","p":"7kmAQgyoBqvze5DQ3w526qWusDkO4NvlEGTkaaK4_jgLixqdZBTt_nyQ_dhWPvMFhZb-XYOZimjsXRWLSvkODtupSlJOkCGZmaZ7jtwZ3TXwdg-z9SgZgthHrgeoxbzuIepwt6Lj1uY87kn2wQggptJh3nvrNoQhecwpbf6U-ic","q":"wpTt8J5RVYDdPxcnGBiUBgliLJByokDXlWIJy2A31pGgBKqmLqjPknkju35jMjpc-VK6yKMHXezvi-C4E9zk0x5jwGS66mUItWnxhEtr8bfSSs11G1svpxnoO7qaY2FwHF5am7PWW6gjo4pLXGmZPAQsNQhJ4EqhekHoK3sPROE","qi":"ZGYm3i6pv8fTacWxjAIweBq2Rzz622ytc6gDPUXHdyndvphP352V3k3LUcHqIxV1rhsMkFQnGVkN4LZ3-vX0LDlK_9xTB99_QHFoF3Er8rXHquVeBn10AEmhpPP-3PEhPsfZRiWNJtWAqqj0SwczGVJ981k6dGm7QrZl9kAFdy4"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"jp1vp9YnIrc5CB2kmJLQdW5AxXAZ0fWO09yzdPS59EY7UMwrYu/TCLNPwPr1o7Qnt/r7nLwQGCcjld5MhSk0zVUNmr7yK+tX4rSKBvysofUcKmbeydNopuIRbPnrT2uBU9XUlAEq7URNLucCqOxmAOMkDb7R1yyNUuFpaDhy6HM="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"2VgDZFsPOgO8Cdk75KQatb24nAy7XMCAiuXlVcoYMU3bfClyuy7zvE2BY68h+X8kHNiAloBPwPxodfmmoJqJeqAQrwxPVvicA91SlgjVlSXzlsQLWQDJ1ljOj+QE87ZxVgHNLI4vzah17/BElI3K0rauD51Y6EjGzy2fECIajqE="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"IcXCO7gyQel4Y2xeU2YhgykZ3XN/q36tXB/p2IFZb/6mYIhbyrk2t1lHryJAMu+TXeBFxB+6cIqK8qNpWGlCjO5lGEFy0aYUn/oAkRAnJVaENYhklJb3QrO/1KGz3Pax6aZuu7bUWbH3FfhzzBHM3bcYaQoHAWvMbaLBLETlvWI="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-512","modulusLength":1024,"publicExponent":3},"jwk":{"alg":"PS512","d":"oGqAID9nitObF9VGn9U4b6TMExMI92LlJ31eWktQj_Iry4j5VYQWRi158tRbNyscGdIug6MFE2ycbWKBb5xcniOHzj5XdeBwULQxdi9vCIQHdw1dRmTm_QzYzLaD002yNVkjOo5ey5kG9jo0bjRLzD2WJJtbB9BC6rlyRqftmWs","dp":"qA0qYnAO1PMtOpYi2UxiTKWYR1HnwBsQDQugjdmRzTSuG0ABn92XsCVPAUChCbMe2FueJBCaJYfZx_qqcxrUXw","dq":"oumVNMIbEqP7l8ybUETeMyCRAHAxLruW9B1tnrJdHVLej4KUapyty42xCawxqYYFHECuczcBC4ulP3o1KEDoSw","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"8J_AMF8bUD1oo7_p77_Up3cyHJyNcxRXuzwNh3D41-tBsU12AEYhaUQ27D6I0sCqJrtFxXSHnSLqpBPCJ2qK7yW91MBOb6wLNkneToWAbYW0cH-vDv2cdhUCyFSXo1RWowXYuOVFmZ8W8Wex4VtHaEtLqcvz9IIBnqFauWTuAR8","p":"_BO_k6gWP2zD1-E0RfKTcvhkavrboCiYE5Fw1MZas88FKOACb8xjiDf2geDxjoyuRIltNhjnOEvGq_f_rKg-jw","q":"9F5fzyMom_X5Y7Lo-GdNTLDZgKhJxhlibiwkbguLq_xN10Pen-sEsVSJjoJKfkkHqmEFrNKBkVF33zdPvGFccQ","qi":"nKm9Sjrby1zqHP9sQoCRPSzV2H1l23KIuw1WHaeL_R0iBNqzt02hdd56sef37WWLHflrZSsVGyGaqP5CHqdjCA"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"ve6irBPQX6G6GwXNOO4V1SO9YZdWQ8MfL1jN60s7vDCOCwq6W+ohqfCHCRmb7L+MGDNhRS6ve8864wjuXHnJb5DZdcQDyv9LUHkcmlSu28TLNu/pTTBZr1E3H212m7DM/qI5laBNPQd2+3eWVwOKZuRBwpZFSCja8Oa7IFzgRDo="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"ZSdvGsUXeFbQpbn/RkvjVifXM8ymUjsgH5drcT4XJBhR4fTSGSoUzL0wBuEnE9WDeGKjY/ejJVio9sq+5vn4+Rll7hZfwlYe3c4z4NG8/TLR5jNgTVppioQLShPxahhbRsFHAV+S+MU0mV3ev5++juXsj27cIfxmAOmzZZ9Ou/8="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"AySCYZFLxWxZqD6yKEiBxRAdeklc4wIkJ7eC2Xkz79wnxQPU0WAP1F8A10O2gK7tkW5DpOk6MHqaZk82gyhjZQhVEPvDkAggoyzCN/ij/mE4kGFCIkaHeC0y+3vTcFuF7E5d/vjyRZrjycyC7CdHLqDQfn0GyKk0PYx717ic38I="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-512","modulusLength":1024,"publicExponent":65537},"jwk":{"alg":"PS512","d":"oaH2s-RdvHJ-zR7y_bJ_DUirJAEMoKODYjxqDZmm39Xk4iJioBDE1Y_qWfg5ZGid3MF9s-OBiNp5ZoQ0lJm3tBkBgpSQ-lQl_F7bJHbb1jZyQCIPg_qqTuodlNdHBWBqpxNsK2XHw2WQR8ic6m0ZXWgy0AH3DmJNIVgQ4PveVhU","dp":"OvjMXFmNPvSAKIX5XcxsvkAeaOBm997p4ngvGeYoMae3oJHcArA2BgvOgYw-yYwjSs6m0ALIGLdd_RaZk63K1w","dq":"d20hdRb8sHF-QAvjYr1zMs8P5eLlQ_vz7zbzZEZH3nptJN5dw1xXZa__8FrBVBH8oOB6b0i155RG_QYsm0pPnw","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"x8WuMfbiE2Fe2iSk9pQJex_3t_L8rAxSKQHeqw0tezUJv2ieoz-BgCuREE5_rpeATHiTEJlwGdu75IIKToDW0bCZHktVNuP4BFcgkp6v3IhHUclM3Qsruxs3r-1h7qwE7qKpSHG_0rYmpYivjNZqY9G00fBRgku1OExvYxOOpEk","p":"6SUJo4aEucbBFdK4G-MRai88MnMcP-bS8WhHz8Z147zfjvrGFNoBbLttALTf5AAi8mTOe_iG9v0HxmAgxkeKVw","q":"21shzTEqopRn_JJNWP5e86AjDEgVzZIY-e3slGnI3F2OIfYh1Xgd6yy7Qwm_hRQO6kpIIfHJzfNgamUEVjtiXw","qi":"ZYiFhgkOsjS9oyfzBwkSvbouoMIfJwvI8cYzy6x8uFFliVEe4_2V_GYDIRQT2iHJ_UpYcaH0cGXFMUgmdNVKeA"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"owU+y7YZkfgyf6CsUT9oR8EsgjM671D4t5QN12g9TEzCAW50wJHmtKknsXcHI/byCpFEIUzGz+j0NNKYjAITgge0THavIuz6bgnyvTW/q7rEiIgBtxUq59X318k0mC2n7c+6zPkccwiINpBlpFb7abOOESZFOLYLyB39XAHssAJkU8IHkKFKq5tA1LWQtKT/34Zd/OX/zvu9lAg9x8JOISv/W0GGoFa6lT25/cV0vJXnNMGZjw7sko4e7spb2915a6cQiLk8Zu4BVQqVEKrgzVbeAPOKHa40ryPc1dBn2n+Y5mcjIvX5Kid1P5G5cm8am+3vRYQkJYPJkOaqHtN9vw=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"gfVcMHYpNoYMAJD9nO/NlaSgxVMz721q+GwXJiW0hrxG3AOqZM/xbOHuoNKWQ6QlMhYTVbW9x/frYuRvufgWO8A4+XeAq4/61cr0aYSSKL01sR+aV9sXLX6fGqi+uNugJFpBsHKGz0o1RQtmBia/3+JYrnXgQxG9sVA+NDayNLiJQJz1usHWyM/kEKPXHFfesQo8CI+BJHgodLQPyL9cp96JQ3kdIZyDbz0J+jiqDoI6SF2rhs+o2LZ7+VHrpSRJCGn686pIp7rtA8ouHLU+VuR4ySu1LJH5Qj3lURHA4lkUudMYO7W0kIvLda8NhJpI6knl5TEipuki6hykORG3/A=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"oSNCuuPGCN0rbFO8XiA8pTejX957HVh6ASo5RIXKqwtyTg+TOnAz0lSmUNera2o4lyy88F1AT7kfZc0yARi91bcTZCw4/nvzOQPxsHKQjZ//pH2mk9mtLFD1uEVa6HT/45evs6c/jkWFeWo0qxiMru5UP3W8gChrOWk0A9wY6+C71c7Zc78cBfxwnlIXjVEtWOkhLAUD76AvE0ZE+zXH0XEd+ErFJJSoB3H71yGmnCg6VEWZuy87sjdfggwemFHvJ0cLyZAMJfjKhCkHRF4NU0A2jBQLtfKNAK1pyo+Io96WRL/uz2RDMrCX53DMr4Gnj8o15CLjOz+ge09LxPeDjw=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-512","modulusLength":2048,"publicExponent":3},"jwk":{"alg":"PS512","d":"kTtPgcPcy6BCsOVm0UfWEztdyaZAigwdjvnuPl4B-hQ6w2QNDzbXikQf5pCud2NeRZRXqZvFC6wQhR6q_NQH8Hlk3Lwe0Sb7PMAlWrJotR-1Fwg7zbSGSgHig1Q2LrRS2i3JFqRq5Vm7GwdEY8YXQy5vOO4nnia-u70FGVg9qvCceKKuxlMeWdRSa5eexOa30EnEPhxcHnU6s9Ml2DbSHz8MfhUSsJ7G7MzvD4sE0j2l1nflW0q7JK7y64xrYwW56vM3DhPr_x3FgD6SzLIiMbTvU_FrWfzFul50EWeUoXh8_1WZVajjoaY10GOg3hRvKChDBlzYPkc2hIxxDox56w","dp":"oEIQd9g_6VwKOXsQFa7okcMRkz--GnS-KxdKKl_xetrYXdHnvT6PkUTKF7tWhPUAtXVmq4i2EUqP8dMWUz_O9MVawljgc0XwGB5h3gxXAUGN-VgDdwcnEY0jirZ_ckZ1be0di7KNjWEdQaqIlHs1NsTkNRyrQVcSDGdq9Ft0yhM","dq":"mqoR7zrIf0UV-xbRwHX40LF7wMkRPX4y6lJN9UZN0s0XjiZASxJsVP1B0afCgUDm5lD6YeqIMm8jNnSNOoYB7QVjuqR30eXFG7Hj7UfX3E2gnMA5sqnKK9OQ4Vq6HCvR07uRs8eSy3LEGBS1g33iqOlheeasDpzlO8dfm9aNeFs","e":"Aw","ext":true,"key_ops":["sign"],"kty":"RSA","n":"2dj3QqXLMXBkCVgaOevBHNkMrnlgzxIsVnblXY0C9x5YJRYTltJDT2Yv2dkFsxUNaF6DfmmnkYIYx64Aez4L6LYXSxouObp42yA4CAudD6-PooxZtI7JbwLTxP5RRg58R0StofagWAaYqIrmlaki5MWm1WU7bToeGZuHpgRcgGrDFyegxglKeG7KfDYvXqwnZ0KkamGOGhl4LCDoPbEvqsZ0sVuogmgDxkVEq_YQjDfia0VsNc1-TZMozMf1vUHpkIqOESJJwDx1-MaNMVF_oVVIIkXfkGUEqJxQM_G0nZ-d_AdFN63asEtXV3KVQsJ2QaTrDo48S12-DQKB4NYahQ","p":"8GMYs8Rf3goPVjiYIIZc2qSaXN-dJ68dQKLvP4_qOEhEjLrbm93XWecvI5kBx2-BEDAaAU0RGe_X6ryhfN-2bygII4VQrOjoJC2SzRKCgeJU9gQFMoq6mlO1UBG_K2mwJOOsUYvUVBGr4n_M3rjP0idWT6sA4gKbEpsgbokvLx0","q":"5_8a5tgsvueg-KI6oLD1OQo5oS2Z3D1MX3t07-l0vDOjVTlgcJuif3viunujweFaWXl3kt_MS6a00a7T18kC44gVl_azutinqYrV4-vDynRw6yBWi_6vQb1ZUggXKkG6vZlajatcMSwmJB8QRTzT_V4SNtoCFetX2asPacHUNIk","qi":"5pPwOQLMfuxJ0Pj88bZA-CKQ5Md-dlTmVwIosFC_iafaiZJ2W2lW3H2_PZPY2iM1_Fy75NTDuN7WVawSs3rmVq9Q6Q0BPpApJC9XV7dsJlR8wKGSMAOstfTcLiB7URTGEw54SILGNfkdBsgVbyUlioeQYfPIaatzpyL96B2SyBc"}},{"signature":{"0":{"algorithm":{"name":"RSA-PSS","saltLength":0},"signature":"IY7ZbYx07EJqjk1CQCcqQKkN899ugbrSsHH71eRWJ16NGZpZRVtCZ1jGfLiUdHzIx/+XBgh3teQdKz6Bs4Ox7mD4x1ZshyEiSUHMQjRHyWk8JFA496TXWshOJm2kLdsWnIESJv9MbmxEQZgdwjvyVKa8nuaQ3HcISlAKCRoCtYpZTP4w4jjKgJ++FrFNKdGPjSb9bg9zzFUGV/0c2uNMLVsRPPpkw+UTwDoNac+3/HKWSoZFu8KoITVaClORxMZKkzP9jCh0RmO4pTUYIf0EjOEm+rikRV502T+/gZfSc/z1xlw3wP/BFJzZoGVkhBhbCDG1NlPekKqUh43+9pke2w=="},"32":{"algorithm":{"name":"RSA-PSS","saltLength":32},"signature":"J33GUcm/EIMqLtvWIuwMVhCifdkEI6IXrbOzK5m3qk1/oRqyS/MSrlB8cfzQtPJxXCxRAxiVwrsf2tocqEooYb1Ae1oNaOM0szaYxbQa+zR4FmhehpKHNVq6T/z3FFZy6Uv3jfA9NtDzbY4vZ9wtVXEtJfN4W5knvID5bvhKDE+LrQqLIaW2uBp3C4OHRyFwlEJ3wh8hSYiVj/TnBKGOVjz/5LW+5RMGr5gPsFjME8kVcp4ilj1f7wjOg9FQspFcZEB+p1NA1cL9PbwpZt16Q7Sz1KLz3LQUCvpvlHdXcXBIVlyZa3uudFQOtLxdZAjrQN5iSgND51n1OcZDmHzmOA=="},"51":{"algorithm":{"name":"RSA-PSS","saltLength":51},"signature":"DR3WjBw6GOuRQ+VCqwSrljGLRsVqi6qmaAyPfLn/PqwL8CVAOpxytEzxwtVNYTF8MLk1whIZp+S104rrHWD/6EmkYyFYlt6cvKoawTjE/TkqnIJrGQgUPy1/Wnu/xJ3S8zxoRxUWnc5IM2B+p9MpyLDlG/2otKnthsQ8sErkLg4V+IzvfmWGwKIloSZm+uyYGEocbePH+RJ54H0KZE21SNWMDZVyR79ZoC1opCUv99pmk6lxjgcJHdLJD6i2UdsQxUiEiP/n/rOWPTif31z+fN/nN9NpGyQcKWkOUm6PHXWxa3cT5dzoe1J9HJXlMr6xwYV6lJCpzSxcv1Q69PdSRg=="}},"algorithm":{"name":"RSA-PSS","hash":"SHA-512","modulusLength":2048,"publicExponent":65537},"jwk":{"alg":"PS512","d":"JK2KOh2FVSo13NrHIuU35G5Fy5kpj4TSPylwd3UMdkRhYFXEqc5DqkqEIF54_2viV1WPnYwcFUi1wHInQuu2f--WCDqTy0QOcZXhBvvmfZH1mZYU5t49F0FJhvVa2DHWnCVYx-4SMiE2Mi70XqsbFcM_c8npuHQdUEh0Fek7UjlCfnxbUXenRxcDcM9HZXTQgaHUerpdyblIz6uREBWwpfq7QxmzTkPpTNqgcBkKiu2pC9-ZhLFeuHKwupffgDT9K1tifa6i7jeeVz6sbaNS0H4V-MMive6KCtE7ImqZZbgIUtKEdQotDem8WQALunb8K_eGdxxL5wCauZI61TjkAQ","dp":"u5BzbJtMlSCKTzX131PnHT6EkIuuA0JMh_fyHVNvx4Ett71cB6WtwnHSYT3qQcM7V4gTbXk9YE4KW5sER46BPg3IkZJ5OQkUH1DJTJtkbeFdF9673LDzfrhj29zDay_VV7-rj-1Fd4Y9ccuNcPYXfLiewzJTR0ceEOFj9kuqkqU","dq":"gWUfCMGZ9kNnCGRoTaKRVglOFKyS-6igzEqmGaXc-0Zj0EL28n5IDNOX4GvTCIKILdwdhjYDF_75A1TYXjOnW0s8EWdyXnG3W-0Id_MBZBYOUkEapFaN5MufqsL1KGCX2LHbxHU7dQF72pfEsATg3ALdX_ROBiIsPuWwMa1wkcE","e":"AQAB","ext":true,"key_ops":["sign"],"kty":"RSA","n":"vAdY53v743mnEfSLpeT7YyCQssM6KpSzgQj2ufFXDh1PO7zQ5IESHR66DN45oUJbsvEUkWBQIMbeipJByKFZoABwnfg7EhmBjgYj0nENAXNoXIJfaxOfq2G84Yog88Ijhiq2QNutVzeYlCDP5G9f0TAqHQYJqM7GGHdGxpg3BJWDXxOydQFAqLlTXBXiA0ZBkBnS31GILP-ulEXod7606Znu_OmB0xizZtEjgN_uznh6X7kikDF0N2j9ZlkyTqRls_7aMEc-R1uUewJmNm1oaSQsFovgE71j04J7HEc8atpNq_tRoY5fBDls8w4J55_r0791z9JDphAkkB_xBUvkjQ","p":"3HzNPfOwrFioIkZXxkLXR7o_vV0_yiX0ijwwt1T8goqYwa4I1IS6qxTBHEFGf0PnmjlBav9nAbzVYabj3k8CzuUZZ1p8aMJ_XtST5ovFeA_iERvBqJDYljCHf1Iq86-SWETklIp1sVJsaeR9yD5gsIw7i9TPr_dIGxIu2DW_OD0","q":"2lAyEtOZIpiDCx760fb6OxFmTAuLUu6NLH7DeaIki4d3s0douApMQkw3feb6n9eeQLhlqqniaKuR0pc8akPJXw0z_WMQ_U_IaeXuQ9NaEo4bNR2H--U7JtdM4wutgmW0nRM_SKItdmx1Vk5lOmbeqHoQhWbuAsuv-PKg6Jn30pE","qi":"frIHZwlk4whzjtkJtvirUMf9rOdc7AD31udcwd5tqEt1G16c0-qkd8Bg0EbrTu5Nd-Nhho2IUcw4FTk7CXx-RhrgVhDtuVxDFlaaQVDFLy-rpLj-qKgdaW6VOHh6_Z8Egj58wtC3kl-QzyC5-IpOvqtdlaAAagw7Hmbuq4ChgGc"}}]; - -describe("RSA-PSS Vectors", () => { - vectors.forEach(vector => { - context(`${vector.algorithm.name} h:${vector.algorithm.hash} n:${vector.algorithm.modulusLength} e:${vector.algorithm.publicExponent}`, () => { - for (let i in vector.signature) { - let signature = vector.signature[i]; - let saltLength = signature.algorithm.saltLength; - it(`s:${saltLength}`, done => { - let pubJwk = { - alg: vector.jwk.alg, - e: vector.jwk.e, - n: vector.jwk.n, - kty: vector.jwk.kty, - } - subtle.importKey("jwk", pubJwk, {name: vector.algorithm.name, hash: vector.algorithm.hash}, true, ["verify"]) - .then(key => { - return subtle.verify( - signature.algorithm, - key, - Buffer.from(signature.signature, "base64"), - MSG - ) - .then(res => { - assert.equal(res, true); - }) - .then(done, done); - }); - }); - } - }); - }); -}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d02b7ac..8f61db4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "esnext", + "target": "es2015", "noUnusedLocals": true, "strictNullChecks": true, "module": "commonjs", @@ -11,9 +11,5 @@ "sourceMap": false, "importHelpers": true, "noImplicitAny": true - }, - "exclude": [ - "node_modules", - "test" - ] + } } \ No newline at end of file diff --git a/tslint.json b/tslint.json index 4028846..d7113e6 100644 --- a/tslint.json +++ b/tslint.json @@ -12,15 +12,9 @@ "object-literal-sort-keys": false, "no-bitwise": false, "forin": false, - "max-line-length": [ - false - ], - "max-classes-per-file": [ - false - ], - "no-console": [ - false - ], + "max-line-length": false, + "max-classes-per-file": false, + "no-console": false, "no-namespace": false } } \ No newline at end of file From dc24918a3dff21c68587c4f3a0fefb6a9509f8e1 Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 23 Mar 2020 12:26:48 +0300 Subject: [PATCH 2/5] build: fix rollup --- lib/mechs/aes/aes_cbc.ts | 2 +- lib/mechs/aes/aes_ctr.ts | 2 +- lib/mechs/aes/aes_ecb.ts | 2 +- lib/mechs/aes/aes_gcm.ts | 2 +- lib/mechs/aes/aes_kw.ts | 2 +- lib/mechs/aes/crypto.ts | 2 +- lib/mechs/ec/crypto.ts | 2 +- lib/mechs/ec/ec_dh.ts | 2 +- lib/mechs/ec/ec_dsa.ts | 2 +- lib/mechs/hmac/hmac.ts | 2 +- lib/mechs/pbkdf/pbkdf2.ts | 2 +- lib/mechs/rsa/crypto.ts | 2 +- lib/mechs/rsa/rsa_oaep.ts | 2 +- lib/mechs/rsa/rsa_pss.ts | 2 +- lib/mechs/rsa/rsa_ssa.ts | 2 +- lib/mechs/sha/crypto.ts | 2 +- lib/native.d.ts | 274 ++++++++++++++++++++++++++++++++++++++ lib/native.ts | 274 -------------------------------------- package-lock.json | 264 ++++++++++++++++-------------------- package.json | 13 +- rollup.config.js | 28 ++-- tsconfig.json | 1 - 22 files changed, 429 insertions(+), 457 deletions(-) create mode 100644 lib/native.d.ts delete mode 100644 lib/native.ts diff --git a/lib/mechs/aes/aes_cbc.ts b/lib/mechs/aes/aes_cbc.ts index b7d6cc7..af6805c 100644 --- a/lib/mechs/aes/aes_cbc.ts +++ b/lib/mechs/aes/aes_cbc.ts @@ -1,6 +1,6 @@ +import type { AesKey } from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import type { AesKey } from "../../native"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; diff --git a/lib/mechs/aes/aes_ctr.ts b/lib/mechs/aes/aes_ctr.ts index 27c89ce..cc4b253 100644 --- a/lib/mechs/aes/aes_ctr.ts +++ b/lib/mechs/aes/aes_ctr.ts @@ -1,6 +1,6 @@ +import type { AesKey } from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import type { AesKey } from "../../native"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; diff --git a/lib/mechs/aes/aes_ecb.ts b/lib/mechs/aes/aes_ecb.ts index 32691da..fe9e7ab 100644 --- a/lib/mechs/aes/aes_ecb.ts +++ b/lib/mechs/aes/aes_ecb.ts @@ -1,6 +1,6 @@ +import type { AesKey } from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import type { AesKey } from "../../native"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; diff --git a/lib/mechs/aes/aes_gcm.ts b/lib/mechs/aes/aes_gcm.ts index ea26af7..1bf849e 100644 --- a/lib/mechs/aes/aes_gcm.ts +++ b/lib/mechs/aes/aes_gcm.ts @@ -1,6 +1,6 @@ +import type { AesKey } from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import type { AesKey } from "../../native"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; diff --git a/lib/mechs/aes/aes_kw.ts b/lib/mechs/aes/aes_kw.ts index 35f021c..c3857ff 100644 --- a/lib/mechs/aes/aes_kw.ts +++ b/lib/mechs/aes/aes_kw.ts @@ -1,6 +1,6 @@ +import type { AesKey } from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import type { AesKey } from "../../native"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; diff --git a/lib/mechs/aes/crypto.ts b/lib/mechs/aes/crypto.ts index efc1d02..09c2d6b 100644 --- a/lib/mechs/aes/crypto.ts +++ b/lib/mechs/aes/crypto.ts @@ -1,7 +1,7 @@ +import * as native from "native"; import { Convert } from "pvtsutils"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { AesCryptoKey } from "./key"; export class AesCrypto { diff --git a/lib/mechs/ec/crypto.ts b/lib/mechs/ec/crypto.ts index 727b6af..fe8c85a 100644 --- a/lib/mechs/ec/crypto.ts +++ b/lib/mechs/ec/crypto.ts @@ -1,7 +1,7 @@ +import * as native from "native"; import { Convert } from "pvtsutils"; import * as core from "webcrypto-core"; import { CryptoKey, CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { EcPrivateKey } from "./private_key"; import { EcPublicKey } from "./public_key"; diff --git a/lib/mechs/ec/ec_dh.ts b/lib/mechs/ec/ec_dh.ts index 101adff..26bf84b 100644 --- a/lib/mechs/ec/ec_dh.ts +++ b/lib/mechs/ec/ec_dh.ts @@ -1,7 +1,7 @@ +import * as native from "native"; import * as core from "webcrypto-core"; import { CryptoKey } from "../../keys"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { EcCrypto } from "./crypto"; export class EcdhProvider extends core.EcdhProvider { diff --git a/lib/mechs/ec/ec_dsa.ts b/lib/mechs/ec/ec_dsa.ts index a544028..59e468c 100644 --- a/lib/mechs/ec/ec_dsa.ts +++ b/lib/mechs/ec/ec_dsa.ts @@ -1,6 +1,6 @@ +import * as native from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { EcCrypto } from "./crypto"; import type { EcPrivateKey } from "./private_key"; import type { EcPublicKey } from "./public_key"; diff --git a/lib/mechs/hmac/hmac.ts b/lib/mechs/hmac/hmac.ts index 77d937d..6e576f2 100644 --- a/lib/mechs/hmac/hmac.ts +++ b/lib/mechs/hmac/hmac.ts @@ -1,7 +1,7 @@ +import * as native from "native"; import { Convert } from "pvtsutils"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { ShaCrypto } from "../sha/crypto"; import { HmacCryptoKey } from "./key"; diff --git a/lib/mechs/pbkdf/pbkdf2.ts b/lib/mechs/pbkdf/pbkdf2.ts index e37e6f9..b2b1993 100644 --- a/lib/mechs/pbkdf/pbkdf2.ts +++ b/lib/mechs/pbkdf/pbkdf2.ts @@ -1,6 +1,6 @@ +import * as native from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { PbkdfCryptoKey } from "./key"; export class Pbkdf2Provider extends core.Pbkdf2Provider { diff --git a/lib/mechs/rsa/crypto.ts b/lib/mechs/rsa/crypto.ts index c84baea..2f850be 100644 --- a/lib/mechs/rsa/crypto.ts +++ b/lib/mechs/rsa/crypto.ts @@ -1,7 +1,7 @@ +import * as native from "native"; import { Convert } from "pvtsutils"; import * as core from "webcrypto-core"; import { CryptoKey, CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { RsaPrivateKey } from "./private_key"; import { RsaPublicKey } from "./public_key"; diff --git a/lib/mechs/rsa/rsa_oaep.ts b/lib/mechs/rsa/rsa_oaep.ts index e346315..51f9f5d 100644 --- a/lib/mechs/rsa/rsa_oaep.ts +++ b/lib/mechs/rsa/rsa_oaep.ts @@ -1,6 +1,6 @@ +import * as native from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; import { RsaPublicKey } from "./public_key"; diff --git a/lib/mechs/rsa/rsa_pss.ts b/lib/mechs/rsa/rsa_pss.ts index d3774d4..2124009 100644 --- a/lib/mechs/rsa/rsa_pss.ts +++ b/lib/mechs/rsa/rsa_pss.ts @@ -1,6 +1,6 @@ +import * as native from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; diff --git a/lib/mechs/rsa/rsa_ssa.ts b/lib/mechs/rsa/rsa_ssa.ts index 856ce7e..7d69872 100644 --- a/lib/mechs/rsa/rsa_ssa.ts +++ b/lib/mechs/rsa/rsa_ssa.ts @@ -1,6 +1,6 @@ +import * as native from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; -import * as native from "../../native"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; diff --git a/lib/mechs/sha/crypto.ts b/lib/mechs/sha/crypto.ts index 6b6e508..7e515e5 100644 --- a/lib/mechs/sha/crypto.ts +++ b/lib/mechs/sha/crypto.ts @@ -1,5 +1,5 @@ +import * as native from "native"; import * as core from "webcrypto-core"; -import * as native from "../../native"; export class ShaCrypto { diff --git a/lib/native.d.ts b/lib/native.d.ts new file mode 100644 index 0000000..2ddcda8 --- /dev/null +++ b/lib/native.d.ts @@ -0,0 +1,274 @@ +// const native = require("../build/Release/nodessl.node"); + +declare module "native" { + export enum EcNamedCurves { + secp112r1 = 704, + secp112r2 = 705, + secp128r1 = 706, + secp128r2 = 707, + secp160k1 = 708, + secp160r1 = 709, + secp160r2 = 710, + secp192r1 = 409, + secp192k1 = 711, + secp224k1 = 712, + secp224r1 = 713, + secp256k1 = 714, + secp256r1 = 415, + secp384r1 = 715, + secp521r1 = 716, + sect113r1 = 717, + sect113r2 = 718, + sect131r1 = 719, + sect131r2 = 720, + sect163k1 = 721, + sect163r1 = 722, + sect163r2 = 723, + sect193r1 = 724, + sect193r2 = 725, + sect233k1 = 726, + sect233r1 = 727, + sect239k1 = 728, + sect283k1 = 729, + sect283r1 = 730, + sect409k1 = 731, + sect409r1 = 732, + sect571k1 = 733, + sect571r1 = 734, + } + + export enum RsaPublicExponent { + RSA_3, + RSA_F4, + } + + export enum KeyType { + PUBLIC, + PRIVATE, + } + + export class Key { + + /** + * Generate RSA key pair + * @param modulus modulus size of RSA key pair + * @param publicExponent public exponent of RSA key pair + * @param callback callback function (err: Error, key: Key) + */ + public static generateRsa(modulus: number, publicExponent: RsaPublicExponent, callback: (err: Error, key: Key) => void): void; + + /** + * Generate EC key pair + * @param namedCurve NID of curve name + * @param callback callback function (err: Error, raw: Key) + */ + public static generateEc(namedCurve: EcNamedCurves, callback: (err: Error, key: Key) => void): void; + + /** + * create Key from JWK data + * @param jwk key in JWK format + * @param keyType type of imported key (PRIVATE or PUBLIC) + * @param callback callback function (err: Error, key: Key) + */ + public static importJwk(jwk: object, keyType: KeyType, callback: (err: Error, key: Key) => void): void; + /** + * create Key from JWK data + * @param jwk key in JWK format + * @param keyType type of imported key (PRIVATE or PUBLIC) + */ + public static importJwk(jwk: { [key: string]: Buffer }, keyType: KeyType): any; + + /** + * create Key from SPKI + * @param raw DER data raw + * @param callback callback function (err: Error, key: Key) + */ + public static importSpki(raw: Buffer, callback: (err: Error, key: Key) => void): void; + + /** + * create Key from PKCS8 + * @param raw DER data raw + * @param callback callback function (err: Error, key: KeyPair) + */ + public static importPkcs8(raw: Buffer, callback: (err: Error, key: Key) => void): void; + + /** + * type of key + */ + public type: number; + + /** + * RSA modulus length + */ + public modulusLength(): number; + + /** + * RSA public exponent + */ + public publicExponent(): Buffer; + + /** + * Export Key to JWK data + * @param keyType type of exported key (PRIVATE or PUBLIC) + * @param callback callback function (err: Error, jwk: Object) + */ + public exportJwk(keyType: KeyType, callback: (err: Error, jwk: any) => void): void; + /** + * Export Key to JWK data + * @param keyType type of exported key (PRIVATE or PUBLIC) + */ + public exportJwk(keyType: KeyType): any; + + /** + * export Key to SPKI + * @param callback callback function (err: Error, raw: Buffer) + */ + public exportSpki(callback: (err: Error, raw: Buffer) => void): void; + + /** + * export Key to PKCS8 + * @param callback callback function (err: Error, raw: Buffer) + */ + public exportPkcs8(callback: (err: Error, raw: Buffer) => void): void; + + /** + * sign data EC, RSA + * @param digestName name of digest algorithm + * @param message message + * @param callback callback function (err: Error, signature: Buffer) + */ + public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; + + /** + * verify data RSA, EC + * @param digestName name of digest algorithm + * @param message message + * @param signature signature from message + * @param callback callback function (err: Error, valid: boolean) + */ + public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; + + /** + * encrypt/decrypt operation for RSA OAEP key + * @param digestName name of digest algorithm + * @param data incoming data + * @param label label for operation. Can be NULL + * @param decrypt type of operation + * @param callback callback function (err: Error, raw: Buffer) + */ + public RsaOaepEncDec(digestName: string, data: Buffer, label: Buffer | null, decrypt: boolean, callback: (err: Error, raw: Buffer) => void): void; + + public RsaPssSign(digestName: string, saltLength: number, data: Buffer, cb: (err: Error, signature: Buffer) => void): void; + public RsaPssVerify(digestName: string, saltLength: number, data: Buffer, signature: Buffer, cb: (err: Error, verified: boolean) => void): void; + + /** + * derives key with ECDH + * @param pubKey public key for key derivation + * @param derivedLen size of derived key (bytes) + * @param callback callback function (err: Error, raw: Buffer) + */ + public EcdhDeriveKey(pubKey: Key, derivedLen: number, callback: (err: Error, raw: Buffer) => void): void; + + /** + * derives bits with ECDH + * @param pubKey public key for key derivation + * @param lengthBits the number of bits you want to derive + * @param callback callback function (err: Error, raw: Buffer) + */ + public EcdhDeriveBits(pubKey: Key, lengthBits: number, callback: (err: Error, raw: Buffer) => void): void; + + } + + export class AesKey { + /** + * generate key + * @param keySize size of generated key (should be 16, 24, 32) + * @param callback callback function (err: Error, key: KeyPair) + */ + public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; + public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; + + public encrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public encryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; + public encryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public encryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; + public decrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public decryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; + public decryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; + public decryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; + public export(callback: (err: Error, raw: Buffer) => void): void; + public wrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; + public unwrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; + } + + export class HmacKey { + /** + * generate key + * @param keySize size of generated key (should be 16, 24, 32) + * @param callback callback function (err: Error, key: KeyPair) + */ + public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; + public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; + + public export(callback: (err: Error, raw: Buffer) => void): void; + /** + * sign data + * @param digestName name of digest algorithm + * @param message message + * @param callback callback function (err: Error, signature: Buffer) + */ + public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; + + /** + * verify data + * @param digestName name of digest algorithm + * @param message message + * @param signature signature from message + * @param callback callback function (err: Error, valid: boolean) + */ + public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; + } + + /** + * PBKDF2 crypto key + * + * @export + * @class Pbkdf2Key + */ + export class Pbkdf2Key { + + /** + * Creates Pbkdf2Key from raw + * + * @static + * @param {Buffer} raw Raw of data + * @param {(error: Error, data: Pbkdf2Key) => void} cb + * + * @memberOf Pbkdf2Key + */ + public static importKey(raw: Buffer, cb: (error: Error, data: Pbkdf2Key) => void): void; + + /** + * Derives bits + * + * @param {string} digestName SHA digest name. SHA-1, SHA-256, SHA-384, SHA-512 + * @param {number} salt Salt + * @param {number} iterations Iterations + * @param {number} bitsLength Size of derived buffer in bits + * @param {(error: Error, data: Buffer) => void} cb Callback + * + * @memberOf Pbkdf2Key + */ + public deriveBits(digestName: string, salt: Buffer, iterations: number, bitsLength: number, cb: (error: Error, data: Buffer) => void): void; + } + + export class Core { + /** + * Returns a digest generated from the hash function and text given as parameters + * @param {string} digest function name + * @param {Buffer} message for hash generation + * @param {Function} callback function (err: Error, digest: Buffer) + */ + public static digest(digestName: string, message: Buffer, callback: (err: Error, digest: Buffer) => void): void; + } +} diff --git a/lib/native.ts b/lib/native.ts deleted file mode 100644 index 7445223..0000000 --- a/lib/native.ts +++ /dev/null @@ -1,274 +0,0 @@ -const native = require("../build/Release/nodessl.node"); - -export declare enum EcNamedCurves { - secp112r1 = 704, - secp112r2 = 705, - secp128r1 = 706, - secp128r2 = 707, - secp160k1 = 708, - secp160r1 = 709, - secp160r2 = 710, - secp192r1 = 409, - secp192k1 = 711, - secp224k1 = 712, - secp224r1 = 713, - secp256k1 = 714, - secp256r1 = 415, - secp384r1 = 715, - secp521r1 = 716, - sect113r1 = 717, - sect113r2 = 718, - sect131r1 = 719, - sect131r2 = 720, - sect163k1 = 721, - sect163r1 = 722, - sect163r2 = 723, - sect193r1 = 724, - sect193r2 = 725, - sect233k1 = 726, - sect233r1 = 727, - sect239k1 = 728, - sect283k1 = 729, - sect283r1 = 730, - sect409k1 = 731, - sect409r1 = 732, - sect571k1 = 733, - sect571r1 = 734, -} - -export declare enum RsaPublicExponent { - RSA_3, - RSA_F4, -} - -export declare enum KeyType { - PUBLIC, - PRIVATE, -} - -export declare class Key { - - /** - * Generate RSA key pair - * @param modulus modulus size of RSA key pair - * @param publicExponent public exponent of RSA key pair - * @param callback callback function (err: Error, key: Key) - */ - public static generateRsa(modulus: number, publicExponent: RsaPublicExponent, callback: (err: Error, key: Key) => void): void; - - /** - * Generate EC key pair - * @param namedCurve NID of curve name - * @param callback callback function (err: Error, raw: Key) - */ - public static generateEc(namedCurve: EcNamedCurves, callback: (err: Error, key: Key) => void): void; - - /** - * create Key from JWK data - * @param jwk key in JWK format - * @param keyType type of imported key (PRIVATE or PUBLIC) - * @param callback callback function (err: Error, key: Key) - */ - public static importJwk(jwk: object, keyType: KeyType, callback: (err: Error, key: Key) => void): void; - /** - * create Key from JWK data - * @param jwk key in JWK format - * @param keyType type of imported key (PRIVATE or PUBLIC) - */ - public static importJwk(jwk: { [key: string]: Buffer }, keyType: KeyType): any; - - /** - * create Key from SPKI - * @param raw DER data raw - * @param callback callback function (err: Error, key: Key) - */ - public static importSpki(raw: Buffer, callback: (err: Error, key: Key) => void): void; - - /** - * create Key from PKCS8 - * @param raw DER data raw - * @param callback callback function (err: Error, key: KeyPair) - */ - public static importPkcs8(raw: Buffer, callback: (err: Error, key: Key) => void): void; - - /** - * type of key - */ - public type: number; - - /** - * RSA modulus length - */ - public modulusLength(): number; - - /** - * RSA public exponent - */ - public publicExponent(): Buffer; - - /** - * Export Key to JWK data - * @param keyType type of exported key (PRIVATE or PUBLIC) - * @param callback callback function (err: Error, jwk: Object) - */ - public exportJwk(keyType: KeyType, callback: (err: Error, jwk: any) => void): void; - /** - * Export Key to JWK data - * @param keyType type of exported key (PRIVATE or PUBLIC) - */ - public exportJwk(keyType: KeyType): any; - - /** - * export Key to SPKI - * @param callback callback function (err: Error, raw: Buffer) - */ - public exportSpki(callback: (err: Error, raw: Buffer) => void): void; - - /** - * export Key to PKCS8 - * @param callback callback function (err: Error, raw: Buffer) - */ - public exportPkcs8(callback: (err: Error, raw: Buffer) => void): void; - - /** - * sign data EC, RSA - * @param digestName name of digest algorithm - * @param message message - * @param callback callback function (err: Error, signature: Buffer) - */ - public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; - - /** - * verify data RSA, EC - * @param digestName name of digest algorithm - * @param message message - * @param signature signature from message - * @param callback callback function (err: Error, valid: boolean) - */ - public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; - - /** - * encrypt/decrypt operation for RSA OAEP key - * @param digestName name of digest algorithm - * @param data incoming data - * @param label label for operation. Can be NULL - * @param decrypt type of operation - * @param callback callback function (err: Error, raw: Buffer) - */ - public RsaOaepEncDec(digestName: string, data: Buffer, label: Buffer | null, decrypt: boolean, callback: (err: Error, raw: Buffer) => void): void; - - public RsaPssSign(digestName: string, saltLength: number, data: Buffer, cb: (err: Error, signature: Buffer) => void): void; - public RsaPssVerify(digestName: string, saltLength: number, data: Buffer, signature: Buffer, cb: (err: Error, verified: boolean) => void): void; - - /** - * derives key with ECDH - * @param pubKey public key for key derivation - * @param derivedLen size of derived key (bytes) - * @param callback callback function (err: Error, raw: Buffer) - */ - public EcdhDeriveKey(pubKey: Key, derivedLen: number, callback: (err: Error, raw: Buffer) => void): void; - - /** - * derives bits with ECDH - * @param pubKey public key for key derivation - * @param lengthBits the number of bits you want to derive - * @param callback callback function (err: Error, raw: Buffer) - */ - public EcdhDeriveBits(pubKey: Key, lengthBits: number, callback: (err: Error, raw: Buffer) => void): void; - -} - -export declare class AesKey { - /** - * generate key - * @param keySize size of generated key (should be 16, 24, 32) - * @param callback callback function (err: Error, key: KeyPair) - */ - public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; - public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; - - public encrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public encryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; - public encryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public encryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; - public decrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public decryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; - public decryptEcb(input: Buffer, callback: (err: Error, data: Buffer) => void): void; - public decryptCtr(input: Buffer, counter: Buffer, length: number, callback: (err: Error, data: Buffer) => void): void; - public export(callback: (err: Error, raw: Buffer) => void): void; - public wrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; - public unwrapKey(data: Buffer, callback: (err: Error, data: Buffer) => void): void; -} - -export declare class HmacKey { - /** - * generate key - * @param keySize size of generated key (should be 16, 24, 32) - * @param callback callback function (err: Error, key: KeyPair) - */ - public static generate(keySize: number, callback: (err: Error, key: AesKey) => void): void; - public static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; - - public export(callback: (err: Error, raw: Buffer) => void): void; - /** - * sign data - * @param digestName name of digest algorithm - * @param message message - * @param callback callback function (err: Error, signature: Buffer) - */ - public sign(digestName: string, message: Buffer, callback: (err: Error, signature: Buffer) => void): void; - - /** - * verify data - * @param digestName name of digest algorithm - * @param message message - * @param signature signature from message - * @param callback callback function (err: Error, valid: boolean) - */ - public verify(digestName: string, message: Buffer, signature: Buffer, callback: (err: Error, valid: boolean) => void): void; -} - -/** - * PBKDF2 crypto key - * - * @export - * @class Pbkdf2Key - */ -export declare class Pbkdf2Key { - - /** - * Creates Pbkdf2Key from raw - * - * @static - * @param {Buffer} raw Raw of data - * @param {(error: Error, data: Pbkdf2Key) => void} cb - * - * @memberOf Pbkdf2Key - */ - public static importKey(raw: Buffer, cb: (error: Error, data: Pbkdf2Key) => void): void; - - /** - * Derives bits - * - * @param {string} digestName SHA digest name. SHA-1, SHA-256, SHA-384, SHA-512 - * @param {number} salt Salt - * @param {number} iterations Iterations - * @param {number} bitsLength Size of derived buffer in bits - * @param {(error: Error, data: Buffer) => void} cb Callback - * - * @memberOf Pbkdf2Key - */ - public deriveBits(digestName: string, salt: Buffer, iterations: number, bitsLength: number, cb: (error: Error, data: Buffer) => void): void; -} - -export declare class Core { - /** - * Returns a digest generated from the hash function and text given as parameters - * @param {string} digest function name - * @param {Buffer} message for hash generation - * @param {Function} callback function (err: Error, digest: Buffer) - */ - public static digest(digestName: string, message: Buffer, callback: (err: Error, digest: Buffer) => void): void; -} - -module.exports = native; diff --git a/package-lock.json b/package-lock.json index 82df42c..95b4af5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -230,6 +230,42 @@ "tslib": "^1.11.1" } }, + "@rollup/plugin-alias": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-3.0.1.tgz", + "integrity": "sha512-ReSy6iPl3GsWLMNeshXAfgItZFMoMOTYC7MZQQM5va4pqxiGgwl1xZUZfHW6zGyZPK+k8TBadxx+kdmepiUa+g==", + "dev": true, + "requires": { + "slash": "^3.0.0" + } + }, + "@rollup/plugin-typescript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-4.0.0.tgz", + "integrity": "sha512-qA3r4WlR8JnTm+VdBzvQSIkfXt802keGxXuE4SAjUjRMKK3nMXTUCvOGSzFkav2qf0QiGv6yijfbjuf+bhwmZQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.1", + "resolve": "^1.14.1" + } + }, + "@rollup/pluginutils": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.8.tgz", + "integrity": "sha512-rYGeAc4sxcZ+kPG/Tw4/fwJODC3IXHYDH4qusdN/b6aLw5LPUbzpecYbEJh4sVQGPFJxd2dBU4kc1H3oy9/bnw==", + "dev": true, + "requires": { + "estree-walker": "^1.0.1" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -281,9 +317,9 @@ "dev": true }, "@types/rimraf": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.3.tgz", - "integrity": "sha512-dZfyfL/u9l/oi984hEXdmAjX3JHry7TLWw43u1HQ8HhPv6KtfxnrZ3T/bleJ0GEvnk9t5sM7eePkgMqz3yBcGg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.4.tgz", + "integrity": "sha512-8gBudvllD2A/c0CcEX/BivIDorHFt5UI5m46TsNj8DjWCCTTZT74kEe4g+QsY7P/B9WdO98d82zZgXO/RQzu2Q==", "dev": true, "requires": { "@types/glob": "*", @@ -301,12 +337,12 @@ } }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -401,9 +437,9 @@ "dev": true }, "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", "dev": true }, "balanced-match": { @@ -625,24 +661,16 @@ "dev": true }, "coveralls": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz", - "integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.11.tgz", + "integrity": "sha512-LZPWPR2NyGKyaABnc49dR0fpeP6UqhvGq4B5nUrTQ1UBy55z96+ga7r+/ChMdMJUwBgyJDXBi88UBgz2rs9IiQ==", "dev": true, "requires": { "js-yaml": "^3.13.1", "lcov-parse": "^1.0.0", "log-driver": "^1.2.7", - "minimist": "^1.2.0", + "minimist": "^1.2.5", "request": "^2.88.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } } }, "cross-spawn": { @@ -738,9 +766,9 @@ "dev": true }, "es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -785,12 +813,6 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -810,15 +832,15 @@ "dev": true }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "fill-range": { @@ -892,17 +914,6 @@ "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", "dev": true }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -958,9 +969,9 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -1366,15 +1377,6 @@ } } }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1454,18 +1456,18 @@ "dev": true }, "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", "dev": true }, "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", "dev": true, "requires": { - "mime-db": "1.42.0" + "mime-db": "1.43.0" } }, "minimatch": { @@ -1478,9 +1480,9 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { @@ -1489,9 +1491,9 @@ "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==" }, "mocha": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.0.tgz", - "integrity": "sha512-MymHK8UkU0K15Q/zX7uflZgVoRWiTjy0fXE/QjKts6mowUvGxOdPhZ2qj3b0iZdUrNZlW9LAIMFHB4IW+2b3EQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", + "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -1507,7 +1509,7 @@ "js-yaml": "3.13.1", "log-symbols": "3.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", + "mkdirp": "0.5.3", "ms": "2.1.1", "node-environment-flags": "1.0.6", "object.assign": "4.1.0", @@ -1515,18 +1517,18 @@ "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", - "yargs": "13.3.0", - "yargs-parser": "13.1.1", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", "yargs-unparser": "1.6.0" }, "dependencies": { "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", + "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } } } @@ -1892,9 +1894,9 @@ "dev": true }, "picomatch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, "pkg-dir": { @@ -1952,9 +1954,9 @@ } }, "psl": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", - "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", "dev": true }, "punycode": { @@ -1996,9 +1998,9 @@ } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -2008,7 +2010,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -2018,7 +2020,7 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } @@ -2068,36 +2070,6 @@ "fsevents": "~2.1.2" } }, - "rollup-plugin-typescript2": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.26.0.tgz", - "integrity": "sha512-lUK7XZVG77tu8dmv1L/0LZFlavED/5Yo6e4iMMl6fdox/yKdj4IFRRPPJEXNdmEaT1nDQQeCi7b5IwKHffMNeg==", - "dev": true, - "requires": { - "find-cache-dir": "^3.2.0", - "fs-extra": "8.1.0", - "resolve": "1.15.1", - "rollup-pluginutils": "2.8.2", - "tslib": "1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - } - } - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - } - }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", @@ -2143,6 +2115,12 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -2318,27 +2296,19 @@ } }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "ts-node": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.7.0.tgz", - "integrity": "sha512-s659CsHrsxaRVDEleuOkGvbsA0rWHtszUNEt1r0CgAFN5ZZTQtDzpsluS7W5pOGJIa1xZE8R/zK4dEs+ldFezg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.8.1.tgz", + "integrity": "sha512-10DE9ONho06QORKAaCBpPiFCdW+tZJuY/84tyypGtl6r+/C7Asq0dhqbRZURuUlLQtZxxDvT8eoj8cGW0ha6Bg==", "dev": true, "requires": { "arg": "^4.1.0", @@ -2397,12 +2367,6 @@ "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", "dev": true }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -2526,9 +2490,9 @@ "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { "cliui": "^5.0.0", @@ -2540,7 +2504,7 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -2572,9 +2536,9 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/package.json b/package.json index a4e883a..cf548c5 100644 --- a/package.json +++ b/package.json @@ -39,23 +39,24 @@ "dependencies": { "mkdirp": "^1.0.3", "nan": "^2.14.0", + "pvtsutils": "^1.0.10", "tslib": "^1.11.1", "webcrypto-core": "^1.0.18" }, "devDependencies": { "@peculiar/webcrypto-test": "^1.0.1", + "@rollup/plugin-alias": "^3.0.1", + "@rollup/plugin-typescript": "^4.0.0", "@types/mkdirp": "^1.0.0", "@types/mocha": "^7.0.2", "@types/node": "^12.12.30", - "@types/rimraf": "^2.0.3", - "coveralls": "^3.0.9", - "mocha": "^7.1.0", + "@types/rimraf": "^2.0.4", + "coveralls": "^3.0.11", + "mocha": "^7.1.1", "nyc": "^15.0.0", - "pvtsutils": "^1.0.10", "rimraf": "^3.0.2", "rollup": "^2.1.0", - "rollup-plugin-typescript2": "^0.26.0", - "ts-node": "^8.7.0", + "ts-node": "^8.8.1", "typescript": "^3.8.3" }, "nyc": { diff --git a/rollup.config.js b/rollup.config.js index f2a39c5..62d4879 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,4 +1,6 @@ -import typescript from "rollup-plugin-typescript2"; +import path from "path"; +import alias from "@rollup/plugin-alias"; +import typescript from "@rollup/plugin-typescript"; // @ts-ignore import pkg from "./package.json"; @@ -9,7 +11,13 @@ const banner = [ "", ].join("\n"); const input = "lib/index.ts"; -const external = Object.keys(pkg.dependencies); +const external = [ + "crypto", + "os", + "path", + "fs", + ...Object.keys(pkg.dependencies) +]; export default [ @@ -18,16 +26,16 @@ export default [ input, plugins: [ typescript({ - check: true, - clean: true, - tsconfigOverride: { - compilerOptions: { - module: "ES2015", - } - } + module: "ES2015", + removeComments: true, + }), + alias({ + entries: [ + { find: "native", replacement: "../../../build/Release/nodessl.node" }, + ] }), ], - external, + external: (name) => external.includes(name) || path.basename(name) === "nodessl.node", output: [ { banner, diff --git a/tsconfig.json b/tsconfig.json index 8f61db4..551668f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,6 @@ "strictNullChecks": true, "module": "commonjs", "moduleResolution": "node", - "outDir": "buildjs", "removeComments": true, "declaration": false, "sourceMap": false, From a599e4f5e4535f8862fb6d31a728dd8d12cdf717 Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 23 Mar 2020 13:29:23 +0300 Subject: [PATCH 3/5] build: apply aliases --- .travis.yml | 1 - lib/mechs/aes/aes_cbc.ts | 3 +++ package-lock.json | 35 +++++++++++++++++++++++++++++++++++ package.json | 6 +++++- tsconfig.json | 6 +++++- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3b0e78..042d72e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,6 @@ before_install: - gcc --version script: - - npm run build:source - npm run coverage after_success: diff --git a/lib/mechs/aes/aes_cbc.ts b/lib/mechs/aes/aes_cbc.ts index af6805c..7726c3b 100644 --- a/lib/mechs/aes/aes_cbc.ts +++ b/lib/mechs/aes/aes_cbc.ts @@ -1,3 +1,6 @@ +// tslint:disable-next-line: no-reference +/// + import type { AesKey } from "native"; import * as core from "webcrypto-core"; import { CryptoKeyStorage } from "../../keys"; diff --git a/package-lock.json b/package-lock.json index 95b4af5..f722f73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -289,6 +289,12 @@ "@types/node": "*" } }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -2326,6 +2332,35 @@ } } }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "tslib": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", diff --git a/package.json b/package.json index cf548c5..7ae7aaa 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "rimraf": "^3.0.2", "rollup": "^2.1.0", "ts-node": "^8.8.1", + "tsconfig-paths": "^3.9.0", "typescript": "^3.8.3" }, "nyc": { @@ -76,7 +77,10 @@ ] }, "mocha": { - "require": "ts-node/register", + "require": [ + "ts-node/register", + "tsconfig-paths/register" + ], "extension": [ "ts" ], diff --git a/tsconfig.json b/tsconfig.json index 551668f..d61349d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,10 @@ "declaration": false, "sourceMap": false, "importHelpers": true, - "noImplicitAny": true + "noImplicitAny": true, + "baseUrl": ".", + "paths": { + "native": ["build/Release/nodessl.node"] + } } } \ No newline at end of file From af9d23cd67c4e07124daae261416de8da1016bdc Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 23 Mar 2020 13:39:58 +0300 Subject: [PATCH 4/5] ci: disable tests for node v8 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 042d72e..c2ba8e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - "8" - "10" - "11" - "12" From cf529c4662159aa82bd35ac80fd68a546b258058 Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 23 Mar 2020 13:53:22 +0300 Subject: [PATCH 5/5] npm: update build script --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 7ae7aaa..cfa7d60 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,9 @@ "clear": "rimraf buildjs", "build": "rollup -c", "rebuild": "npm run clear && npm run build", + "lint": "tslint -p .", + "lint:fix": "tslint -p . --fix", + "prepub": "npm run lint && npm run rebuild", "pub": "npm version patch && npm publish && git push", "sync": "git ac && git pull --rebase && git push", "coverage": "nyc npm test",