From fd98284182d83fbe96b6dc8a9bad7527fcb57b7e Mon Sep 17 00:00:00 2001 From: microshine Date: Fri, 13 Mar 2020 18:20:02 +0300 Subject: [PATCH] Use WeakMap to protect private data --- src/index.ts | 2 +- src/mechs/aes/aes_cbc.ts | 16 ++++++----- src/mechs/aes/aes_cmac.ts | 12 +++++---- src/mechs/aes/aes_ctr.ts | 14 +++++----- src/mechs/aes/aes_ecb.ts | 14 +++++----- src/mechs/aes/aes_gcm.ts | 14 +++++----- src/mechs/aes/aes_kw.ts | 15 ++++++----- src/mechs/des/des_cbc.ts | 17 ++++++------ src/mechs/des/des_ede3_cbc.ts | 17 ++++++------ src/mechs/ec/ec_dh.ts | 19 ++++++++----- src/mechs/ec/ec_dsa.ts | 20 ++++++++------ src/mechs/hkdf/hkdf.ts | 7 ++--- src/mechs/hmac/hmac.ts | 15 ++++++----- src/mechs/pbkdf/pbkdf2.ts | 7 ++--- src/mechs/rsa/rsa_es.ts | 18 ++++++++----- src/mechs/rsa/rsa_oaep.ts | 50 ++++++++++++++++++++--------------- src/mechs/rsa/rsa_pss.ts | 20 ++++++++------ src/mechs/rsa/rsa_ssa.ts | 20 ++++++++------ src/mechs/storage.ts | 21 +++++++++++++++ 19 files changed, 192 insertions(+), 126 deletions(-) create mode 100644 src/mechs/storage.ts diff --git a/src/index.ts b/src/index.ts index c3f9d3d..2be3353 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,2 @@ -export { CryptoKey } from "./keys"; +export { CryptoKey } from "webcrypto-core"; export { Crypto } from "./crypto"; diff --git a/src/mechs/aes/aes_cbc.ts b/src/mechs/aes/aes_cbc.ts index bb7abca..12777cd 100644 --- a/src/mechs/aes/aes_cbc.ts +++ b/src/mechs/aes/aes_cbc.ts @@ -1,4 +1,5 @@ import * as core from "webcrypto-core"; +import { getCryptoKey, setCryptoKey } from "../storage"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; @@ -13,28 +14,29 @@ export class AesCbcProvider extends core.AesCbcProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { - return AesCrypto.exportKey(format, key); + return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(key); } - + public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof AesCryptoKey)) { + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError("key: Is not a AesCryptoKey"); } } diff --git a/src/mechs/aes/aes_cmac.ts b/src/mechs/aes/aes_cmac.ts index 046b3ca..e1afef7 100644 --- a/src/mechs/aes/aes_cmac.ts +++ b/src/mechs/aes/aes_cmac.ts @@ -1,5 +1,6 @@ import * as crypto from "crypto"; import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; @@ -121,11 +122,11 @@ export class AesCmacProvider extends core.AesCmacProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onSign(algorithm: AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise { - const result = aesCmac(key.data, Buffer.from(data)); + const result = aesCmac(getCryptoKey(key).data, Buffer.from(data)); return new Uint8Array(result).buffer; } @@ -135,16 +136,17 @@ export class AesCmacProvider extends core.AesCmacProvider { } public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { - return AesCrypto.exportKey(format, key); + return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof AesCryptoKey)) { + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError("key: Is not a AesCryptoKey"); } } diff --git a/src/mechs/aes/aes_ctr.ts b/src/mechs/aes/aes_ctr.ts index d2cd221..50af5fa 100644 --- a/src/mechs/aes/aes_ctr.ts +++ b/src/mechs/aes/aes_ctr.ts @@ -1,4 +1,5 @@ import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; @@ -13,28 +14,29 @@ export class AesCtrProvider extends core.AesCtrProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { - return AesCrypto.exportKey(format, key); + return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof AesCryptoKey)) { + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError("key: Is not a AesCryptoKey"); } } diff --git a/src/mechs/aes/aes_ecb.ts b/src/mechs/aes/aes_ecb.ts index 68e023d..a5a49de 100644 --- a/src/mechs/aes/aes_ecb.ts +++ b/src/mechs/aes/aes_ecb.ts @@ -1,4 +1,5 @@ import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; @@ -13,28 +14,29 @@ export class AesEcbProvider extends core.AesEcbProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { - return AesCrypto.exportKey(format, key); + return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof AesCryptoKey)) { + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError("key: Is not a AesCryptoKey"); } } diff --git a/src/mechs/aes/aes_gcm.ts b/src/mechs/aes/aes_gcm.ts index defb8f4..b2d61ba 100644 --- a/src/mechs/aes/aes_gcm.ts +++ b/src/mechs/aes/aes_gcm.ts @@ -1,4 +1,5 @@ import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; @@ -13,28 +14,29 @@ export class AesGcmProvider extends core.AesGcmProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { - return AesCrypto.exportKey(format, key); + return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof AesCryptoKey)) { + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError("key: Is not a AesCryptoKey"); } } diff --git a/src/mechs/aes/aes_kw.ts b/src/mechs/aes/aes_kw.ts index 527ebd9..b70a027 100644 --- a/src/mechs/aes/aes_kw.ts +++ b/src/mechs/aes/aes_kw.ts @@ -1,11 +1,12 @@ import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { AesCrypto } from "./crypto"; import { AesCryptoKey } from "./key"; export class AesKwProvider extends core.AesKwProvider { public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return await AesCrypto.generateKey( + const res = await AesCrypto.generateKey( { name: this.name, length: algorithm.length, @@ -13,27 +14,29 @@ export class AesKwProvider extends core.AesKwProvider { extractable, keyUsages, ); + return setCryptoKey(res); } public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise { - return AesCrypto.exportKey(format, key); + return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { - return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages); + return setCryptoKey(res); } public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise { - return AesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data)); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof AesCryptoKey)) { + if (!(getCryptoKey(key) instanceof AesCryptoKey)) { throw new TypeError("key: Is not a AesCryptoKey"); } } diff --git a/src/mechs/des/des_cbc.ts b/src/mechs/des/des_cbc.ts index af9d7fa..92f075b 100644 --- a/src/mechs/des/des_cbc.ts +++ b/src/mechs/des/des_cbc.ts @@ -1,5 +1,6 @@ import * as core from "webcrypto-core"; import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { DesCrypto } from "./crypto"; import { DesCryptoKey } from "./key"; @@ -11,7 +12,7 @@ export class DesCbcProvider extends core.DesProvider { public ivSize = 8; public name = "DES-CBC"; - public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await DesCrypto.generateKey( { name: this.name, @@ -20,32 +21,32 @@ export class DesCbcProvider extends core.DesProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { - return DesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { - return DesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return DesCrypto.exportKey(format, key); + return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey); } - public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { 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 key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof DesCryptoKey)) { + if (!(getCryptoKey(key) instanceof DesCryptoKey)) { throw new TypeError("key: Is not a DesCryptoKey"); } } diff --git a/src/mechs/des/des_ede3_cbc.ts b/src/mechs/des/des_ede3_cbc.ts index b35522f..7f94c61 100644 --- a/src/mechs/des/des_ede3_cbc.ts +++ b/src/mechs/des/des_ede3_cbc.ts @@ -1,5 +1,6 @@ import * as core from "webcrypto-core"; import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { DesCrypto } from "./crypto"; import { DesCryptoKey } from "./key"; @@ -11,7 +12,7 @@ export class DesEde3CbcProvider extends core.DesProvider { public ivSize = 8; public name = "DES-EDE3-CBC"; - public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await DesCrypto.generateKey( { name: this.name, @@ -20,32 +21,32 @@ export class DesEde3CbcProvider extends core.DesProvider { extractable, keyUsages); - return key; + return setCryptoKey(key); } public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { - return DesCrypto.encrypt(algorithm, key, new Uint8Array(data)); + return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); } public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise { - return DesCrypto.decrypt(algorithm, key, new Uint8Array(data)); + return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return DesCrypto.exportKey(format, key); + return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey); } - public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise { 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 key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof DesCryptoKey)) { + if (!(getCryptoKey(key) instanceof DesCryptoKey)) { throw new TypeError("key: Is not a DesCryptoKey"); } } diff --git a/src/mechs/ec/ec_dh.ts b/src/mechs/ec/ec_dh.ts index 501e1d8..496b121 100644 --- a/src/mechs/ec/ec_dh.ts +++ b/src/mechs/ec/ec_dh.ts @@ -1,5 +1,6 @@ import * as core from "webcrypto-core"; import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { EcCrypto } from "./crypto"; import { EcPrivateKey } from "./private_key"; import { EcPublicKey } from "./public_key"; @@ -7,7 +8,7 @@ import { EcPublicKey } from "./public_key"; export class EcdhProvider extends core.EcdhProvider { public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - const key = await EcCrypto.generateKey( + const keys = await EcCrypto.generateKey( { ...algorithm, name: this.name, @@ -15,27 +16,31 @@ export class EcdhProvider extends core.EcdhProvider { extractable, keyUsages); - return key; + return { + privateKey: setCryptoKey(keys.privateKey as CryptoKey), + publicKey: setCryptoKey(keys.publicKey as CryptoKey), + }; } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return EcCrypto.exportKey(format, key); + return EcCrypto.exportKey(format, getCryptoKey(key)); } - public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { + public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await EcCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages); - return key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof EcPrivateKey || key instanceof EcPublicKey)) { + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) { throw new TypeError("key: Is not EC CryptoKey"); } } public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise { - const bits = await EcCrypto.deriveBits(algorithm, baseKey, length); + const bits = await EcCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length); return bits; } diff --git a/src/mechs/ec/ec_dsa.ts b/src/mechs/ec/ec_dsa.ts index 89a1a4e..883ea91 100644 --- a/src/mechs/ec/ec_dsa.ts +++ b/src/mechs/ec/ec_dsa.ts @@ -1,5 +1,5 @@ import * as core from "webcrypto-core"; -import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { EcCrypto } from "./crypto"; import { EcPrivateKey } from "./private_key"; import { EcPublicKey } from "./public_key"; @@ -9,7 +9,7 @@ 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 { - const key = await EcCrypto.generateKey( + const keys = await EcCrypto.generateKey( { ...algorithm, name: this.name, @@ -17,29 +17,33 @@ export class EcdsaProvider extends core.EcdsaProvider { extractable, keyUsages); - return key; + return { + privateKey: setCryptoKey(keys.privateKey as EcPrivateKey), + publicKey: setCryptoKey(keys.publicKey as EcPublicKey), + }; } public async onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise { - return EcCrypto.sign(algorithm, key, new Uint8Array(data)); + return EcCrypto.sign(algorithm, getCryptoKey(key) as EcPrivateKey, new Uint8Array(data)); } public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { - return EcCrypto.verify(algorithm, key, new Uint8Array(signature), new Uint8Array(data)); + return EcCrypto.verify(algorithm, getCryptoKey(key) as EcPublicKey, new Uint8Array(signature), new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return EcCrypto.exportKey(format, key); + return EcCrypto.exportKey(format, getCryptoKey(key)); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); - return key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof EcPrivateKey || key instanceof EcPublicKey)) { + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) { throw new TypeError("key: Is not EC CryptoKey"); } } diff --git a/src/mechs/hkdf/hkdf.ts b/src/mechs/hkdf/hkdf.ts index f5cc28d..ca114e8 100644 --- a/src/mechs/hkdf/hkdf.ts +++ b/src/mechs/hkdf/hkdf.ts @@ -1,6 +1,7 @@ import crypto from "crypto"; import * as core from "webcrypto-core"; import { BufferSourceConverter, CryptoKey } from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { HkdfCryptoKey } from "./key"; export class HkdfProvider extends core.HkdfProvider { @@ -15,7 +16,7 @@ export class HkdfProvider extends core.HkdfProvider { key.algorithm = { name: this.name }; key.extractable = extractable; key.usages = keyUsages; - return key; + return setCryptoKey(key); } public async onDeriveBits(params: HkdfParams, baseKey: HkdfCryptoKey, length: number): Promise { @@ -26,7 +27,7 @@ export class HkdfProvider extends core.HkdfProvider { const info = BufferSourceConverter.toUint8Array(params.info); const PRK = crypto.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt)) - .update(BufferSourceConverter.toUint8Array(baseKey.data)) + .update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data)) .digest(); const blocks = [Buffer.alloc(0)]; @@ -44,7 +45,7 @@ export class HkdfProvider extends core.HkdfProvider { public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof HkdfCryptoKey)) { + if (!(getCryptoKey(key) instanceof HkdfCryptoKey)) { throw new TypeError("key: Is not HKDF CryptoKey"); } } diff --git a/src/mechs/hmac/hmac.ts b/src/mechs/hmac/hmac.ts index 0b970d9..4f14730 100644 --- a/src/mechs/hmac/hmac.ts +++ b/src/mechs/hmac/hmac.ts @@ -1,6 +1,7 @@ import crypto from "crypto"; import { JsonParser, JsonSerializer } from "@peculiar/json-schema"; import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { HmacCryptoKey } from "./key"; export class HmacProvider extends core.HmacProvider { @@ -16,12 +17,12 @@ export class HmacProvider extends core.HmacProvider { key.usages = keyUsages; key.data = crypto.randomBytes(length >> 3); - return key; + return setCryptoKey(key); } public async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise { const hash = key.algorithm.hash.name.replace("-", ""); - const hmac = crypto.createHmac(hash, key.data) + const hmac = crypto.createHmac(hash, getCryptoKey(key).data) .update(Buffer.from(data)).digest(); return new Uint8Array(hmac).buffer; @@ -29,7 +30,7 @@ export class HmacProvider extends core.HmacProvider { public async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { const hash = key.algorithm.hash.name.replace("-", ""); - const hmac = crypto.createHmac(hash, key.data) + const hmac = crypto.createHmac(hash, getCryptoKey(key).data) .update(Buffer.from(data)).digest(); return hmac.compare(Buffer.from(signature)) === 0; @@ -58,15 +59,15 @@ export class HmacProvider extends core.HmacProvider { key.extractable = extractable; key.usages = keyUsages; - return key; + return setCryptoKey(key); } public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise { switch (format.toLowerCase()) { case "jwk": - return JsonSerializer.toJSON(key); + return JsonSerializer.toJSON(getCryptoKey(key)); case "raw": - return new Uint8Array(key.data).buffer; + return new Uint8Array(getCryptoKey(key).data).buffer; default: throw new core.OperationError("format: Must be 'jwk' or 'raw'"); } @@ -74,7 +75,7 @@ export class HmacProvider extends core.HmacProvider { public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof HmacCryptoKey)) { + if (!(getCryptoKey(key) instanceof HmacCryptoKey)) { throw new TypeError("key: Is not HMAC CryptoKey"); } } diff --git a/src/mechs/pbkdf/pbkdf2.ts b/src/mechs/pbkdf/pbkdf2.ts index ab3cdcb..968e68f 100644 --- a/src/mechs/pbkdf/pbkdf2.ts +++ b/src/mechs/pbkdf/pbkdf2.ts @@ -1,5 +1,6 @@ import crypto from "crypto"; import * as core from "webcrypto-core"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { PbkdfCryptoKey } from "./key"; export class Pbkdf2Provider extends core.Pbkdf2Provider { @@ -8,7 +9,7 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider { return new Promise((resolve, reject) => { const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt); const hash = (algorithm.hash as Algorithm).name.replace("-", ""); - crypto.pbkdf2(baseKey.data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => { + crypto.pbkdf2(getCryptoKey(baseKey).data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => { if (err) { reject(err); } else { @@ -25,14 +26,14 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider { key.algorithm = { name: this.name }; key.extractable = false; key.usages = keyUsages; - return key; + return setCryptoKey(key); } throw new core.OperationError("format: Must be 'raw'"); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof PbkdfCryptoKey)) { + if (!(getCryptoKey(key) instanceof PbkdfCryptoKey)) { throw new TypeError("key: Is not PBKDF CryptoKey"); } } diff --git a/src/mechs/rsa/rsa_es.ts b/src/mechs/rsa/rsa_es.ts index a12922c..1f64cdc 100644 --- a/src/mechs/rsa/rsa_es.ts +++ b/src/mechs/rsa/rsa_es.ts @@ -1,7 +1,7 @@ import * as crypto from "crypto"; import { Convert } from "pvtsutils"; import * as core from "webcrypto-core"; -import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; import { RsaPublicKey } from "./public_key"; @@ -15,7 +15,7 @@ export class RsaEsProvider extends core.ProviderCrypto { }; public async onGenerateKey(algorithm: RsaKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - const key = await RsaCrypto.generateKey( + const keys = await RsaCrypto.generateKey( { ...algorithm, name: this.name, @@ -23,7 +23,10 @@ export class RsaEsProvider extends core.ProviderCrypto { extractable, keyUsages); - return key; + return { + privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), + publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), + }; } public checkGenerateKeyParams(algorithm: RsaKeyGenParams) { @@ -62,17 +65,18 @@ export class RsaEsProvider extends core.ProviderCrypto { } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return RsaCrypto.exportKey(format, key); + return RsaCrypto.exportKey(format, getCryptoKey(key)); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); - return key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) { + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { throw new TypeError("key: Is not RSA CryptoKey"); } } @@ -82,7 +86,7 @@ export class RsaEsProvider extends core.ProviderCrypto { private toCryptoOptions(key: RsaPrivateKey | RsaPublicKey) { const type = key.type.toUpperCase(); return { - key: `-----BEGIN ${type} KEY-----\n${key.data.toString("base64")}\n-----END ${type} KEY-----`, + key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`, // @ts-ignore padding: crypto.constants.RSA_PKCS1_PADDING, }; diff --git a/src/mechs/rsa/rsa_oaep.ts b/src/mechs/rsa/rsa_oaep.ts index aa584df..bf06e8e 100644 --- a/src/mechs/rsa/rsa_oaep.ts +++ b/src/mechs/rsa/rsa_oaep.ts @@ -1,7 +1,7 @@ import crypto from "crypto"; import * as core from "webcrypto-core"; -import { CryptoKey } from "../../keys"; import { ShaCrypto } from "../sha/crypto"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; import { RsaPublicKey } from "./public_key"; @@ -16,7 +16,7 @@ import { RsaPublicKey } from "./public_key"; export class RsaOaepProvider extends core.RsaOaepProvider { public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - const key = await RsaCrypto.generateKey( + const keys = await RsaCrypto.generateKey( { ...algorithm, name: this.name, @@ -24,13 +24,17 @@ export class RsaOaepProvider extends core.RsaOaepProvider { extractable, keyUsages); - return key; + return { + privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), + publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), + }; } public async onEncrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: ArrayBuffer): Promise { + const internalKey = getCryptoKey(key) as RsaPublicKey; const dataView = new Uint8Array(data); - const keySize = Math.ceil(key.algorithm.modulusLength >> 3); - const hashSize = ShaCrypto.size(key.algorithm.hash) >> 3; + const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); + const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; const dataLength = dataView.byteLength; const psLength = keySize - dataLength - 2 * hashSize - 2; @@ -44,7 +48,7 @@ export class RsaOaepProvider extends core.RsaOaepProvider { dataBlock.set(dataView, hashSize + psLength + 1); - const labelHash = crypto.createHash(key.algorithm.hash.name.replace("-", "")) + const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", "")) .update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0))) .digest(); dataBlock.set(labelHash, 0); @@ -52,22 +56,22 @@ export class RsaOaepProvider extends core.RsaOaepProvider { crypto.randomFillSync(seed); - const dataBlockMask = this.mgf1(key.algorithm.hash, seed, dataBlock.length); + const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length); for (let i = 0; i < dataBlock.length; i++) { dataBlock[i] ^= dataBlockMask[i]; } - const seedMask = this.mgf1(key.algorithm.hash, dataBlock, seed.length); + const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length); for (let i = 0; i < seed.length; i++) { seed[i] ^= seedMask[i]; } - if (!key.pem) { - key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`; + if (!internalKey.pem) { + internalKey.pem = `-----BEGIN PUBLIC KEY-----\n${internalKey.data.toString("base64")}\n-----END PUBLIC KEY-----`; } const pkcs0 = crypto.publicEncrypt({ - key: key.pem, + key: internalKey.pem, padding: crypto.constants.RSA_NO_PADDING, }, Buffer.from(message)); @@ -75,20 +79,21 @@ export class RsaOaepProvider extends core.RsaOaepProvider { } public async onDecrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: ArrayBuffer): Promise { - const keySize = Math.ceil(key.algorithm.modulusLength >> 3); - const hashSize = ShaCrypto.size(key.algorithm.hash) >> 3; + const internalKey = getCryptoKey(key) as RsaPrivateKey; + const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3); + const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3; const dataLength = data.byteLength; if (dataLength !== keySize) { throw new Error("Bad data"); } - if (!key.pem) { - key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`; + if (!internalKey.pem) { + internalKey.pem = `-----BEGIN PRIVATE KEY-----\n${internalKey.data.toString("base64")}\n-----END PRIVATE KEY-----`; } let pkcs0 = crypto.privateDecrypt({ - key: key.pem, + key: internalKey.pem, padding: crypto.constants.RSA_NO_PADDING, }, Buffer.from(data)); const z = pkcs0[0]; @@ -99,17 +104,17 @@ export class RsaOaepProvider extends core.RsaOaepProvider { throw new Error("Decryption failed"); } - const seedMask = this.mgf1(key.algorithm.hash, dataBlock, seed.length); + const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length); for (let i = 0; i < seed.length; i++) { seed[i] ^= seedMask[i]; } - const dataBlockMask = this.mgf1(key.algorithm.hash, seed, dataBlock.length); + const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length); for (let i = 0; i < dataBlock.length; i++) { dataBlock[i] ^= dataBlockMask[i]; } - const labelHash = crypto.createHash(key.algorithm.hash.name.replace("-", "")) + const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", "")) .update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0))) .digest(); for (let i = 0; i < hashSize; i++) { @@ -138,17 +143,18 @@ export class RsaOaepProvider extends core.RsaOaepProvider { } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return RsaCrypto.exportKey(format, key); + return RsaCrypto.exportKey(format, getCryptoKey(key)); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages); - return key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) { + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { throw new TypeError("key: Is not RSA CryptoKey"); } } diff --git a/src/mechs/rsa/rsa_pss.ts b/src/mechs/rsa/rsa_pss.ts index 489393b..059fceb 100644 --- a/src/mechs/rsa/rsa_pss.ts +++ b/src/mechs/rsa/rsa_pss.ts @@ -1,5 +1,5 @@ import * as core from "webcrypto-core"; -import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; import { RsaPublicKey } from "./public_key"; @@ -7,7 +7,7 @@ import { RsaPublicKey } from "./public_key"; export class RsaPssProvider extends core.RsaPssProvider { public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - const key = await RsaCrypto.generateKey( + const keys = await RsaCrypto.generateKey( { ...algorithm, name: this.name, @@ -15,29 +15,33 @@ export class RsaPssProvider extends core.RsaPssProvider { extractable, keyUsages); - return key; + return { + privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), + publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), + }; } public async onSign(algorithm: RsaPssParams, key: RsaPrivateKey, data: ArrayBuffer): Promise { - return RsaCrypto.sign(algorithm, key, new Uint8Array(data)); + return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data)); } public async onVerify(algorithm: RsaPssParams, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { - return RsaCrypto.verify(algorithm, key, new Uint8Array(signature), new Uint8Array(data)); + return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return RsaCrypto.exportKey(format, key); + return RsaCrypto.exportKey(format, getCryptoKey(key)); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages); - return key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) { + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { throw new TypeError("key: Is not RSA CryptoKey"); } } diff --git a/src/mechs/rsa/rsa_ssa.ts b/src/mechs/rsa/rsa_ssa.ts index 046ecb4..7eca5f3 100644 --- a/src/mechs/rsa/rsa_ssa.ts +++ b/src/mechs/rsa/rsa_ssa.ts @@ -1,5 +1,5 @@ import * as core from "webcrypto-core"; -import { CryptoKey } from "../../keys"; +import { setCryptoKey, getCryptoKey } from "../storage"; import { RsaCrypto } from "./crypto"; import { RsaPrivateKey } from "./private_key"; import { RsaPublicKey } from "./public_key"; @@ -7,7 +7,7 @@ import { RsaPublicKey } from "./public_key"; export class RsaSsaProvider extends core.RsaSsaProvider { public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { - const key = await RsaCrypto.generateKey( + const keys = await RsaCrypto.generateKey( { ...algorithm, name: this.name, @@ -15,29 +15,33 @@ export class RsaSsaProvider extends core.RsaSsaProvider { extractable, keyUsages); - return key; + return { + privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey), + publicKey: setCryptoKey(keys.publicKey as RsaPublicKey), + }; } public async onSign(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise { - return RsaCrypto.sign(algorithm, key, new Uint8Array(data)); + return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data)); } public async onVerify(algorithm: Algorithm, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise { - return RsaCrypto.verify(algorithm, key, new Uint8Array(signature), new Uint8Array(data)); + return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data)); } public async onExportKey(format: KeyFormat, key: CryptoKey): Promise { - return RsaCrypto.exportKey(format, key); + return RsaCrypto.exportKey(format, getCryptoKey(key)); } public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise { const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages); - return key; + return setCryptoKey(key); } public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) { super.checkCryptoKey(key, keyUsage); - if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) { + const internalKey = getCryptoKey(key); + if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) { throw new TypeError("key: Is not RSA CryptoKey"); } } diff --git a/src/mechs/storage.ts b/src/mechs/storage.ts new file mode 100644 index 0000000..3d3e2e9 --- /dev/null +++ b/src/mechs/storage.ts @@ -0,0 +1,21 @@ +import * as core from "webcrypto-core"; +import { CryptoKey as InternalCryptoKey } from "../keys"; + +const keyStorage = new WeakMap(); + +export function getCryptoKey(key: core.CryptoKey) { + const res = keyStorage.get(key); + if (!res) { + throw new core.OperationError("Cannot get CryptoKey from secure storage"); + } + return res; +} + +export function setCryptoKey(value: InternalCryptoKey) { + const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages); + Object.freeze(key); + + keyStorage.set(key, value); + + return key; +}