UNPKG

@fungible-systems/webcrypto-expo

Version:

A WebCrypto Polyfill for Expo (React Native)

804 lines (777 loc) 29.8 kB
/** * Copyright (c) 2020 Peculiar Ventures, LLC */ import { Buffer as Buffer$1 } from 'buffer'; import * as core from 'webcrypto-core'; export { CryptoKey } from 'webcrypto-core'; import getRandomValues from 'expo-standard-web-crypto/build/getRandomValues'; import { __decorate } from 'tslib'; import { JsonProp, JsonPropTypes, JsonSerializer, JsonParser } from '@peculiar/json-schema'; import { Convert } from 'pvtsutils'; import crypto, { createHash } from 'crypto'; import '@peculiar/asn1-schema'; import { hashSha512, hashSha256 } from 'micro-stacks/crypto-sha'; import { hmacSha256Shim, hmacSha512Shim } from 'micro-stacks/crypto-hmac-sha'; const JsonBase64UrlConverter = { fromJSON: (value) => Buffer.from(Convert.FromBase64Url(value)), toJSON: (value) => Convert.ToBase64Url(value), }; class CryptoKey extends core.CryptoKey { constructor() { super(...arguments); this.data = Buffer.alloc(0); this.algorithm = { name: '' }; this.extractable = false; this.type = 'secret'; this.usages = []; this.kty = 'oct'; this.alg = ''; } } __decorate([ JsonProp({ name: 'ext', type: JsonPropTypes.Boolean, optional: true }) ], CryptoKey.prototype, "extractable", void 0); __decorate([ JsonProp({ name: 'key_ops', type: JsonPropTypes.String, repeated: true, optional: true }) ], CryptoKey.prototype, "usages", void 0); __decorate([ JsonProp({ type: JsonPropTypes.String }) ], CryptoKey.prototype, "kty", void 0); __decorate([ JsonProp({ type: JsonPropTypes.String }) ], CryptoKey.prototype, "alg", void 0); class SymmetricKey extends CryptoKey { constructor() { super(...arguments); this.kty = 'oct'; this.type = 'secret'; } } class AesCryptoKey extends SymmetricKey { get alg() { switch (this.algorithm.name.toUpperCase()) { case 'AES-CBC': return `A${this.algorithm.length}CBC`; case 'AES-CTR': return `A${this.algorithm.length}CTR`; case 'AES-GCM': return `A${this.algorithm.length}GCM`; case 'AES-KW': return `A${this.algorithm.length}KW`; case 'AES-CMAC': return `A${this.algorithm.length}CMAC`; case 'AES-ECB': return `A${this.algorithm.length}ECB`; default: throw new core.AlgorithmError('Unsupported algorithm name'); } } set alg(value) { } } __decorate([ JsonProp({ name: 'k', converter: JsonBase64UrlConverter }) ], AesCryptoKey.prototype, "data", void 0); const keyStorage = new WeakMap(); function getCryptoKey(key) { const res = keyStorage.get(key); if (!res) { throw new core.OperationError('Cannot get CryptoKey from secure storage'); } return res; } function setCryptoKey(value) { const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages); Object.freeze(key); keyStorage.set(key, value); return key; } class AesCrypto { static async generateKey(algorithm, extractable, keyUsages) { const key = new AesCryptoKey(); key.algorithm = algorithm; key.extractable = extractable; key.usages = keyUsages; key.data = crypto.randomBytes(algorithm.length >> 3); return key; } static async exportKey(format, key) { if (!(key instanceof AesCryptoKey)) { throw new Error('key: Is not AesCryptoKey'); } switch (format.toLowerCase()) { case 'jwk': return JsonSerializer.toJSON(key); case 'raw': return new Uint8Array(key.data).buffer; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } } static async importKey(format, keyData, algorithm, extractable, keyUsages) { let key; switch (format.toLowerCase()) { case 'jwk': key = JsonParser.fromJSON(keyData, { targetSchema: AesCryptoKey }); break; case 'raw': key = new AesCryptoKey(); key.data = Buffer.from(keyData); break; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } key.algorithm = algorithm; key.algorithm.length = key.data.length << 3; key.extractable = extractable; key.usages = keyUsages; switch (key.algorithm.length) { case 128: case 192: case 256: break; default: throw new core.OperationError('keyData: Is wrong key length'); } return key; } static async encrypt(algorithm, key, data) { switch (algorithm.name.toUpperCase()) { case 'AES-CBC': return this.encryptAesCBC(algorithm, key, Buffer.from(data)); case 'AES-CTR': return this.encryptAesCTR(algorithm, key, Buffer.from(data)); case 'AES-GCM': return this.encryptAesGCM(algorithm, key, Buffer.from(data)); case 'AES-KW': return this.encryptAesKW(algorithm, key, Buffer.from(data)); case 'AES-ECB': return this.encryptAesECB(algorithm, key, Buffer.from(data)); default: throw new core.OperationError('algorithm: Is not recognized'); } } static async decrypt(algorithm, key, data) { if (!(key instanceof AesCryptoKey)) { throw new Error('key: Is not AesCryptoKey'); } switch (algorithm.name.toUpperCase()) { case 'AES-CBC': return this.decryptAesCBC(algorithm, key, Buffer.from(data)); case 'AES-CTR': return this.decryptAesCTR(algorithm, key, Buffer.from(data)); case 'AES-GCM': return this.decryptAesGCM(algorithm, key, Buffer.from(data)); case 'AES-KW': return this.decryptAesKW(algorithm, key, Buffer.from(data)); case 'AES-ECB': return this.decryptAesECB(algorithm, key, Buffer.from(data)); default: throw new core.OperationError('algorithm: Is not recognized'); } } static async encryptAesCBC(algorithm, key, data) { const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv)); let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final()]); const res = new Uint8Array(enc).buffer; return res; } static async decryptAesCBC(algorithm, key, data) { const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv)); let dec = decipher.update(data); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } static async encryptAesCTR(algorithm, key, data) { const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ctr`, key.data, Buffer.from(algorithm.counter)); let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final()]); const res = new Uint8Array(enc).buffer; return res; } static async decryptAesCTR(algorithm, key, data) { const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ctr`, key.data, new Uint8Array(algorithm.counter)); let dec = decipher.update(data); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } static async encryptAesGCM(algorithm, key, data) { const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-gcm`, key.data, Buffer.from(algorithm.iv), { authTagLength: (algorithm.tagLength || 128) >> 3, }); if (algorithm.additionalData) { cipher.setAAD(Buffer.from(algorithm.additionalData)); } let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final(), cipher.getAuthTag()]); const res = new Uint8Array(enc).buffer; return res; } static async decryptAesGCM(algorithm, key, data) { const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-gcm`, key.data, new Uint8Array(algorithm.iv)); const tagLength = (algorithm.tagLength || 128) >> 3; const enc = data.slice(0, data.length - tagLength); const tag = data.slice(data.length - tagLength); if (algorithm.additionalData) { decipher.setAAD(Buffer.from(algorithm.additionalData)); } decipher.setAuthTag(tag); let dec = decipher.update(enc); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } static async encryptAesKW(algorithm, key, data) { const cipher = crypto.createCipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV); let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final()]); return new Uint8Array(enc).buffer; } static async decryptAesKW(algorithm, key, data) { const decipher = crypto.createDecipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV); let dec = decipher.update(data); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } static async encryptAesECB(algorithm, key, data) { const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0)); let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final()]); const res = new Uint8Array(enc).buffer; return res; } static async decryptAesECB(algorithm, key, data) { const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0)); let dec = decipher.update(data); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } } AesCrypto.AES_KW_IV = Buffer.from('A6A6A6A6A6A6A6A6', 'hex'); class AesCbcProvider extends core.AesCbcProvider { async onGenerateKey(algorithm, extractable, keyUsages) { const key = await AesCrypto.generateKey({ name: this.name, length: algorithm.length, }, extractable, keyUsages); return setCryptoKey(key); } async onEncrypt(algorithm, key, data) { return AesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); } async onDecrypt(algorithm, key, data) { return AesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); } async onExportKey(format, key) { return AesCrypto.exportKey(format, getCryptoKey(key)); } async onImportKey(format, keyData, algorithm, extractable, keyUsages) { const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); return setCryptoKey(key); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError('key: Is not a AesCryptoKey'); } } } Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135]); class DesCryptoKey extends SymmetricKey { get alg() { switch (this.algorithm.name.toUpperCase()) { case 'DES-CBC': return `DES-CBC`; case 'DES-EDE3-CBC': return `3DES-CBC`; default: throw new core.AlgorithmError('Unsupported algorithm name'); } } set alg(value) { } } __decorate([ JsonProp({ name: 'k', converter: JsonBase64UrlConverter }) ], DesCryptoKey.prototype, "data", void 0); class DesCrypto { static async generateKey(algorithm, extractable, keyUsages) { const key = new DesCryptoKey(); key.algorithm = algorithm; key.extractable = extractable; key.usages = keyUsages; key.data = crypto.randomBytes(algorithm.length >> 3); return key; } static async exportKey(format, key) { switch (format.toLowerCase()) { case 'jwk': return JsonSerializer.toJSON(key); case 'raw': return new Uint8Array(key.data).buffer; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } } static async importKey(format, keyData, algorithm, extractable, keyUsages) { let key; switch (format.toLowerCase()) { case 'jwk': key = JsonParser.fromJSON(keyData, { targetSchema: DesCryptoKey }); break; case 'raw': key = new DesCryptoKey(); key.data = Buffer.from(keyData); break; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } key.algorithm = algorithm; key.extractable = extractable; key.usages = keyUsages; return key; } static async encrypt(algorithm, key, data) { switch (algorithm.name.toUpperCase()) { case 'DES-CBC': return this.encryptDesCBC(algorithm, key, Buffer.from(data)); case 'DES-EDE3-CBC': return this.encryptDesEDE3CBC(algorithm, key, Buffer.from(data)); default: throw new core.OperationError('algorithm: Is not recognized'); } } static async decrypt(algorithm, key, data) { if (!(key instanceof DesCryptoKey)) { throw new Error('key: Is not DesCryptoKey'); } switch (algorithm.name.toUpperCase()) { case 'DES-CBC': return this.decryptDesCBC(algorithm, key, Buffer.from(data)); case 'DES-EDE3-CBC': return this.decryptDesEDE3CBC(algorithm, key, Buffer.from(data)); default: throw new core.OperationError('algorithm: Is not recognized'); } } static async encryptDesCBC(algorithm, key, data) { const cipher = crypto.createCipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv)); let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final()]); const res = new Uint8Array(enc).buffer; return res; } static async decryptDesCBC(algorithm, key, data) { const decipher = crypto.createDecipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv)); let dec = decipher.update(data); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } static async encryptDesEDE3CBC(algorithm, key, data) { const cipher = crypto.createCipheriv(`des-ede3-cbc`, key.data, Buffer.from(algorithm.iv)); let enc = cipher.update(data); enc = Buffer.concat([enc, cipher.final()]); const res = new Uint8Array(enc).buffer; return res; } static async decryptDesEDE3CBC(algorithm, key, data) { const decipher = crypto.createDecipheriv(`des-ede3-cbc`, key.data, new Uint8Array(algorithm.iv)); let dec = decipher.update(data); dec = Buffer.concat([dec, decipher.final()]); return new Uint8Array(dec).buffer; } } class DesCbcProvider extends core.DesProvider { constructor() { super(...arguments); this.keySizeBits = 64; this.ivSize = 8; this.name = 'DES-CBC'; } async onGenerateKey(algorithm, extractable, keyUsages) { const key = await DesCrypto.generateKey({ name: this.name, length: this.keySizeBits, }, extractable, keyUsages); return setCryptoKey(key); } async onEncrypt(algorithm, key, data) { return DesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); } async onDecrypt(algorithm, key, data) { return DesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); } async onExportKey(format, key) { return DesCrypto.exportKey(format, getCryptoKey(key)); } async onImportKey(format, keyData, algorithm, extractable, keyUsages) { const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages); if (key.data.length !== this.keySizeBits >> 3) { throw new core.OperationError('keyData: Wrong key size'); } return setCryptoKey(key); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); if (!(getCryptoKey(key) instanceof DesCryptoKey)) { throw new TypeError('key: Is not a DesCryptoKey'); } } } class DesEde3CbcProvider extends core.DesProvider { constructor() { super(...arguments); this.keySizeBits = 192; this.ivSize = 8; this.name = 'DES-EDE3-CBC'; } async onGenerateKey(algorithm, extractable, keyUsages) { const key = await DesCrypto.generateKey({ name: this.name, length: this.keySizeBits, }, extractable, keyUsages); return setCryptoKey(key); } async onEncrypt(algorithm, key, data) { return DesCrypto.encrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); } async onDecrypt(algorithm, key, data) { return DesCrypto.decrypt(algorithm, getCryptoKey(key), new Uint8Array(data)); } async onExportKey(format, key) { return DesCrypto.exportKey(format, getCryptoKey(key)); } async onImportKey(format, keyData, algorithm, extractable, keyUsages) { const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages); if (key.data.length !== this.keySizeBits >> 3) { throw new core.OperationError('keyData: Wrong key size'); } return setCryptoKey(key); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); if (!(getCryptoKey(key) instanceof DesCryptoKey)) { throw new TypeError('key: Is not a DesCryptoKey'); } } } class ShaCrypto { static size(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'); } } static digest(algorithm, data) { const hash = crypto .createHash(algorithm.name.replace('-', '')) .update(Buffer.from(data)) .digest(); return new Uint8Array(hash).buffer; } } ({ [core.asn1.idEd448]: 'Ed448', ed448: core.asn1.idEd448, [core.asn1.idX448]: 'X448', x448: core.asn1.idX448, [core.asn1.idEd25519]: 'Ed25519', ed25519: core.asn1.idEd25519, [core.asn1.idX25519]: 'X25519', x25519: core.asn1.idX25519, }); class Sha256Provider extends core.ProviderCrypto { constructor() { super(...arguments); this.name = 'SHA-256'; this.usages = []; } async onDigest(algorithm, data) { return ShaCrypto.digest(algorithm, data); } } class Sha512Provider extends core.ProviderCrypto { constructor() { super(...arguments); this.name = 'SHA-512'; this.usages = []; } async onDigest(algorithm, data) { return ShaCrypto.digest(algorithm, data); } } class PbkdfCryptoKey extends CryptoKey { } const MAX_ALLOC = Math.pow(2, 30) - 1; function createHasher(alg) { let normalizedAlg; if (alg === 'rmd160') { normalizedAlg = 'ripemd160'; } else { normalizedAlg = alg; } return (value) => { switch (normalizedAlg) { case 'sha256': return Buffer.from(hashSha256(value)); case 'sha512': return Buffer.from(hashSha512(value)); default: { return Buffer.from(createHash(normalizedAlg).update(value).digest()); } } }; } function getZeroes(zeros) { return Buffer.alloc(zeros); } const sizes = { md5: 16, sha1: 20, sha224: 28, sha256: 32, sha384: 48, sha512: 64, rmd160: 20, ripemd160: 20, }; function toBuffer(bufferable) { if (bufferable instanceof Uint8Array || typeof bufferable === 'string') { return Buffer.from(bufferable); } else { return Buffer.from(bufferable.buffer); } } class Hmac { constructor(alg, key, saltLen) { this.hash = createHasher(alg); const blocksize = alg === 'sha512' || alg === 'sha384' ? 128 : 64; if (key.length > blocksize) { key = this.hash(key); } else if (key.length < blocksize) { key = Buffer.concat([key, getZeroes(blocksize - key.length)], blocksize); } const ipad = Buffer.allocUnsafe(blocksize + sizes[alg]); const opad = Buffer.allocUnsafe(blocksize + sizes[alg]); for (let i = 0; i < blocksize; i++) { ipad[i] = key[i] ^ 0x36; opad[i] = key[i] ^ 0x5c; } const ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4); ipad.copy(ipad1, 0, 0, blocksize); this.ipad1 = ipad1; this.ipad2 = ipad; this.opad = opad; this.alg = alg; this.blocksize = blocksize; this.size = sizes[alg]; } run(data, ipad) { data.copy(ipad, this.blocksize); const h = this.hash(ipad); h.copy(this.opad, this.blocksize); return this.hash(this.opad); } } function pbkdf2Sync(password, salt, iterations, keylen, digest = 'sha1') { if (typeof iterations !== 'number' || iterations < 0) { throw new TypeError('Bad iterations'); } if (typeof keylen !== 'number' || keylen < 0 || keylen > MAX_ALLOC) { throw new TypeError('Bad key length'); } const bufferedPassword = toBuffer(password); const bufferedSalt = toBuffer(salt); const hmac = new Hmac(digest, bufferedPassword, bufferedSalt.length); const DK = Buffer.allocUnsafe(keylen); const block1 = Buffer.allocUnsafe(bufferedSalt.length + 4); bufferedSalt.copy(block1, 0, 0, bufferedSalt.length); let destPos = 0; const hLen = sizes[digest]; const l = Math.ceil(keylen / hLen); for (let i = 1; i <= l; i++) { block1.writeUInt32BE(i, bufferedSalt.length); const T = hmac.run(block1, hmac.ipad1); let U = T; for (let j = 1; j < iterations; j++) { U = hmac.run(U, hmac.ipad2); for (let k = 0; k < hLen; k++) T[k] ^= U[k]; } T.copy(DK, destPos); destPos += hLen; } return DK; } function pbkdf2(password, salt, iterations, keylen, digest = 'sha1', callback) { console.log('pbkdf2'); setTimeout(() => { let err = null, res; try { res = pbkdf2Sync(password, salt, iterations, keylen, digest); } catch (e) { err = e; } if (err) { callback(err); } else { callback(null, res); } }, 0); } class Pbkdf2Provider extends core.Pbkdf2Provider { async onDeriveBits(algorithm, baseKey, length) { return new Promise((resolve, reject) => { const salt = Buffer.from(core.BufferSourceConverter.toArrayBuffer(algorithm.salt)); const digest = algorithm.hash.name.replace('-', '').toLowerCase(); const password = getCryptoKey(baseKey).data; const iterations = algorithm.iterations; const keyLength = length >> 3; pbkdf2(password, salt, iterations, keyLength, digest, (err, derivedBits) => { if (err) reject(err); derivedBits && resolve(new Uint8Array(derivedBits).buffer); }); }); } async onImportKey(format, keyData, algorithm, extractable, keyUsages) { if (format === 'raw') { const key = new PbkdfCryptoKey(); key.data = Buffer.from(keyData); key.algorithm = { name: this.name }; key.extractable = false; key.usages = keyUsages; return setCryptoKey(key); } throw new core.OperationError("format: Must be 'raw'"); } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); if (!(getCryptoKey(key) instanceof PbkdfCryptoKey)) { throw new TypeError('key: Is not PBKDF CryptoKey'); } } } class HmacCryptoKey extends CryptoKey { get alg() { const hash = this.algorithm.hash.name.toUpperCase(); return `HS${hash.replace('SHA-', '')}`; } set alg(value) { } } __decorate([ JsonProp({ name: 'k', converter: JsonBase64UrlConverter }) ], HmacCryptoKey.prototype, "data", void 0); class HmacProvider extends core.HmacProvider { async onGenerateKey(algorithm, extractable, keyUsages) { const length = ((algorithm.length || this.getDefaultLength(algorithm.hash.name)) >> 3) << 3; const key = new HmacCryptoKey(); key.algorithm = { ...algorithm, length, name: this.name, }; key.extractable = extractable; key.usages = keyUsages; key.data = crypto.randomBytes(length >> 3); return setCryptoKey(key); } async onSign(algorithm, key, data) { const hash = key.algorithm.hash.name.replace('-', ''); let hmac; if (hash === 'SHA256') hmac = hmacSha256Shim(getCryptoKey(key).data, new Uint8Array(data)); if (hash === 'SHA512') hmac = hmacSha512Shim(getCryptoKey(key).data, new Uint8Array(data)); if (!hmac) hmac = crypto.createHmac(hash, getCryptoKey(key).data).update(new Uint8Array(data)).digest(); return new Uint8Array(hmac).buffer; } async onVerify(algorithm, key, signature, data) { const hash = key.algorithm.hash.name.replace('-', ''); let hmac; if (hash === 'SHA256') hmac = hmacSha256Shim(getCryptoKey(key).data, new Uint8Array(data)); if (hash === 'SHA512') hmac = hmacSha512Shim(getCryptoKey(key).data, new Uint8Array(data)); if (!hmac) hmac = crypto.createHmac(hash, getCryptoKey(key).data).update(new Uint8Array(data)).digest(); return Buffer.from(hmac).compare(Buffer.from(signature)) === 0; } async onImportKey(format, keyData, algorithm, extractable, keyUsages) { let key; switch (format.toLowerCase()) { case 'jwk': key = JsonParser.fromJSON(keyData, { targetSchema: HmacCryptoKey }); break; case 'raw': key = new HmacCryptoKey(); key.data = Buffer.from(keyData); break; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } key.algorithm = { hash: { name: algorithm.hash.name }, name: this.name, length: key.data.length << 3, }; key.extractable = extractable; key.usages = keyUsages; return setCryptoKey(key); } async onExportKey(format, key) { switch (format.toLowerCase()) { case 'jwk': return JsonSerializer.toJSON(getCryptoKey(key)); case 'raw': return new Uint8Array(getCryptoKey(key).data).buffer; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } } checkCryptoKey(key, keyUsage) { super.checkCryptoKey(key, keyUsage); if (!(getCryptoKey(key) instanceof HmacCryptoKey)) { throw new TypeError('key: Is not HMAC CryptoKey'); } } } class SubtleCrypto extends core.SubtleCrypto { constructor() { super(); this.providers.set(new AesCbcProvider()); this.providers.set(new DesCbcProvider()); this.providers.set(new DesEde3CbcProvider()); this.providers.set(new Sha256Provider()); this.providers.set(new Sha512Provider()); this.providers.set(new Pbkdf2Provider()); this.providers.set(new HmacProvider()); } } class Crypto extends core.Crypto { constructor() { super(...arguments); this.subtle = new SubtleCrypto(); } getRandomValues(array) { return getRandomValues(array); } } global.Buffer = Buffer$1; export { Crypto };