From b6c2ad330784631324876e8572cc99fea212cb85 Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 12:11:34 +0200 Subject: [PATCH 1/7] removed!: keySpec from BaseKeyHandle Removed `KeySpec` from BaseKeyHandle as there is currently no use in sync context. --- src/CryptoErrorCode.ts | 1 + .../encryption/BaseDerivedKeyHandle.ts | 0 src/crypto-layer/encryption/BaseKeyHandle.ts | 52 ++++++++++++------- .../encryption/CryptoEncryptionHandle.ts | 10 ++-- .../encryption/DeviceBoundDerivedKeyHandle.ts | 1 - .../encryption/DeviceBoundKeyHandle.ts | 1 - .../encryption/PortableDerivedKeyHandle.ts | 1 - .../encryption/PortableKeyHandle.ts | 1 - test/cal/KeyValidation.ts | 30 +++++------ .../encryption/CryptoEncryptionHandle.test.ts | 41 +++++++-------- .../encryption/CryptoSecretKeyHandle.test.ts | 1 - 11 files changed, 72 insertions(+), 67 deletions(-) create mode 100644 src/crypto-layer/encryption/BaseDerivedKeyHandle.ts diff --git a/src/CryptoErrorCode.ts b/src/CryptoErrorCode.ts index d6f29b9..206bd8b 100644 --- a/src/CryptoErrorCode.ts +++ b/src/CryptoErrorCode.ts @@ -58,6 +58,7 @@ export enum CryptoErrorCode { CalProvidersAlreadyInitialized = "error.crypto.cal.providersAlreadyInitialized", CalImportOfKey = "error.crypto.cal.calImportOfKey", CalKeyDerivation = "error.crypto.cal.keyDerivation", + CalLoadKey = "error.crypto.cal.loadKey", DeserializeValidation = "error.deserialize.validation" } diff --git a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/crypto-layer/encryption/BaseKeyHandle.ts b/src/crypto-layer/encryption/BaseKeyHandle.ts index 9235329..e9098aa 100644 --- a/src/crypto-layer/encryption/BaseKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseKeyHandle.ts @@ -1,22 +1,22 @@ import { ISerializable, ISerialized, SerializableAsync, serialize, type, validate } from "@js-soft/ts-serval"; import { KeyHandle, KeySpec, Provider } from "@nmshd/rs-crypto-types"; -import { isKeySpec } from "@nmshd/rs-crypto-types/checks"; +import { CryptoHashAlgorithm } from "src/hash/CryptoHash"; import { CoreBuffer, ICoreBuffer } from "../../CoreBuffer"; import { CryptoError } from "../../CryptoError"; import { CryptoErrorCode } from "../../CryptoErrorCode"; import { CryptoSerializableAsync } from "../../CryptoSerializable"; +import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; +import { CryptoLayerUtils } from "../CryptoLayerUtils"; export interface IBaseKeyHandleSerialized extends ISerialized { kid: string; pnm: string; - spc: KeySpec; } export interface IBaseKeyHandle extends ISerializable { id: string; providerName: string; - spec: KeySpec; } export interface BaseKeyHandleConstructor { @@ -46,18 +46,27 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I @serialize() public providerName: string; - @validate({ - customValidator: (value) => { - if (isKeySpec(value)) return undefined; - return "Is not of type KeySpec."; - } - }) - @serialize() - public spec: KeySpec; - public provider: Provider; public keyHandle: KeyHandle; + public async encryptionAndHashAlgorithm(): Promise<[CryptoEncryptionAlgorithm, CryptoHashAlgorithm]> { + const spec = await this.keyHandle.spec(); + return [ + CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher), + CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash) + ]; + } + + public async encryptionAlgorithm(): Promise { + const spec = await this.keyHandle.spec(); + return CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher); + } + + public async hashAlgorithm(): Promise { + const spec = await this.keyHandle.spec(); + return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash); + } + /** * Deserializes an object representation of a {@link BaseKeyHandle}. * @@ -96,11 +105,7 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I ): Promise { const result = new this(); - [result.providerName, result.id, result.spec] = await Promise.all([ - provider.providerName(), - keyHandle.id(), - keyHandle.spec() - ]); + [result.providerName, result.id] = await Promise.all([provider.providerName(), keyHandle.id()]); result.provider = provider; result.keyHandle = keyHandle; @@ -125,7 +130,18 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I } const provider = getProvider({ providerName: value.providerName }); - const keyHandle = await provider.loadKey(value.id); + let keyHandle: KeyHandle; + try { + keyHandle = await provider.loadKey(value.id); + } catch (e) { + throw new CryptoError( + CryptoErrorCode.CalLoadKey, + "Failed to load key during deserialization.", + undefined, + e as Error, + BaseKeyHandle.postFrom + ); + } value.keyHandle = keyHandle; value.provider = provider; diff --git a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts index ea9c812..3a67edb 100644 --- a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts +++ b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts @@ -64,7 +64,7 @@ export class CryptoEncryptionHandle { secretKeyHandle: T, nonce?: CoreBuffer ): Promise { - const encryptionAlgorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(secretKeyHandle.spec.cipher); + const encryptionAlgorithm = await secretKeyHandle.encryptionAlgorithm(); if (nonce === undefined || nonce.buffer.length === 0) { nonce = await this.createNonce(encryptionAlgorithm, secretKeyHandle.provider); @@ -98,7 +98,7 @@ export class CryptoEncryptionHandle { nonce: CoreBuffer, counter: number ): Promise { - const encryptionAlgorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(secretKeyHandle.spec.cipher); + const encryptionAlgorithm = await secretKeyHandle.encryptionAlgorithm(); CryptoValidation.checkCounter(counter); CryptoValidation.checkNonceForAlgorithm(nonce, encryptionAlgorithm); @@ -130,7 +130,7 @@ export class CryptoEncryptionHandle { secretKeyHandle: T, nonce?: CoreBuffer ): Promise { - const encryptionAlgorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(secretKeyHandle.spec.cipher); + const encryptionAlgorithm = await secretKeyHandle.encryptionAlgorithm(); let publicNonce; if (nonce !== undefined) { @@ -165,7 +165,7 @@ export class CryptoEncryptionHandle { nonce: CoreBuffer, counter: number ): Promise { - const encryptionAlgorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(secretKeyHandle.spec.cipher); + const encryptionAlgorithm = await secretKeyHandle.encryptionAlgorithm(); CryptoValidation.checkCounter(counter); CryptoValidation.checkNonceForAlgorithm(nonce, encryptionAlgorithm); @@ -218,7 +218,7 @@ export class CryptoEncryptionHandle { portableKeyHandle: PortableKeyHandle | PortableDerivedKeyHandle ): Promise { const rawKeyPromise = CryptoEncryptionHandle.extractRawKey(portableKeyHandle); - const algorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(portableKeyHandle.spec.cipher); + const algorithm = await portableKeyHandle.encryptionAlgorithm(); const cryptoSecretKeyObj: ICryptoSecretKey = { algorithm: algorithm, secretKey: await rawKeyPromise diff --git a/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts b/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts index c5feba1..85c2990 100644 --- a/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts @@ -12,7 +12,6 @@ export class DeviceBoundDerivedKeyHandle extends BaseKeyHandle { return { kid: this.id, pnm: this.providerName, - spc: this.spec, "@type": verbose ? "DeviceBoundDerivedKeyHandle" : undefined }; } diff --git a/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts b/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts index 9ff3c5d..d0ae865 100644 --- a/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts +++ b/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts @@ -12,7 +12,6 @@ export class DeviceBoundKeyHandle extends BaseKeyHandle { return { kid: this.id, pnm: this.providerName, - spc: this.spec, "@type": verbose ? "DeviceBoundKeyHandle" : undefined }; } diff --git a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts index dc2117f..297794e 100644 --- a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts @@ -11,7 +11,6 @@ export class PortableDerivedKeyHandle extends BaseKeyHandle { return { kid: this.id, pnm: this.providerName, - spc: this.spec, "@type": verbose ? "PortableDerivedKeyHandle" : undefined }; } diff --git a/src/crypto-layer/encryption/PortableKeyHandle.ts b/src/crypto-layer/encryption/PortableKeyHandle.ts index 8ae971d..7fcfe67 100644 --- a/src/crypto-layer/encryption/PortableKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableKeyHandle.ts @@ -12,7 +12,6 @@ export class PortableKeyHandle extends ImportableBaseKeyHandle { return { kid: this.id, pnm: this.providerName, - spc: this.spec, "@type": verbose ? "PortableKeyHandle" : undefined }; } diff --git a/test/cal/KeyValidation.ts b/test/cal/KeyValidation.ts index ae67819..8275d03 100644 --- a/test/cal/KeyValidation.ts +++ b/test/cal/KeyValidation.ts @@ -3,13 +3,12 @@ import { CoreBuffer, CryptoCipher, CryptoEncryptionHandle, - CryptoLayerUtils, DeviceBoundDerivedKeyHandle, DeviceBoundKeyHandle, PortableDerivedKeyHandle, PortableKeyHandle } from "@nmshd/crypto"; -import { assertKeyHandle, assertKeySpec, assertProvider } from "@nmshd/rs-crypto-types/checks"; +import { assertKeyHandle, assertProvider } from "@nmshd/rs-crypto-types/checks"; import { expect } from "chai"; /** @@ -20,28 +19,26 @@ export async function assertSecretKeyHandleValid(handle expect(handle.id).to.exist.and.to.be.a("string"); expect(handle.keyHandle).to.exist; expect(handle.provider).to.exist; - expect(handle.spec).to.exist; expect(handle.providerName).to.exist.and.to.be.a("string"); assertKeyHandle(handle.keyHandle); assertProvider(handle.provider); - assertKeySpec(handle.spec); expect(await handle.keyHandle.id()).to.exist.and.to.be.a("string").and.to.be.not.empty; - expect(await handle.keyHandle.spec()).to.exist.and.to.deep.equal(handle.spec); + const spec = await handle.keyHandle.spec(); if (handle instanceof DeviceBoundKeyHandle) { - expect(handle.spec.ephemeral).to.be.false; - expect(handle.spec.non_exportable).to.be.true; + expect(spec.ephemeral).to.be.false; + expect(spec.non_exportable).to.be.true; } else if (handle instanceof DeviceBoundDerivedKeyHandle) { - expect(handle.spec.ephemeral).to.be.true; - expect(handle.spec.non_exportable).to.be.true; + expect(spec.ephemeral).to.be.true; + expect(spec.non_exportable).to.be.true; } else if (handle instanceof PortableKeyHandle) { - expect(handle.spec.ephemeral).to.be.false; - expect(handle.spec.non_exportable).to.be.false; + expect(spec.ephemeral).to.be.false; + expect(spec.non_exportable).to.be.false; } else if (handle instanceof PortableDerivedKeyHandle) { - expect(handle.spec.ephemeral).to.be.true; - expect(handle.spec.non_exportable).to.be.false; + expect(spec.ephemeral).to.be.true; + expect(spec.non_exportable).to.be.false; } else { throw new Error("Test: unknown key handle instance."); } @@ -54,9 +51,7 @@ async function testDecryptEncryptIsIdentityFunction(bef expect(encryptedPayload).to.exist; expect(encryptedPayload).to.be.instanceOf(CryptoCipher); - expect(encryptedPayload.algorithm).to.be.equal( - CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(before.spec.cipher) - ); + expect(encryptedPayload.algorithm).to.be.equal(await before.encryptionAlgorithm()); expect(encryptedPayload.counter).to.not.exist; expect(encryptedPayload.nonce).to.exist; expect(encryptedPayload.nonce?.buffer.byteLength).to.be.greaterThanOrEqual(12); @@ -70,7 +65,8 @@ async function testDecryptEncryptIsIdentityFunction(bef * Test that the content of two SecretKeys match. */ export async function assertSecretKeyHandleEqual(before: T, after: T): Promise { - expect(before.spec).to.deep.equal(after.spec); + const [beforeSpec, afterSpec] = await Promise.all([before.keyHandle.spec(), after.keyHandle.spec()]); + expect(beforeSpec).to.deep.equal(afterSpec); if ( (before instanceof PortableKeyHandle && after instanceof PortableKeyHandle) || (before instanceof PortableDerivedKeyHandle && after instanceof PortableDerivedKeyHandle) diff --git a/test/cal/encryption/CryptoEncryptionHandle.test.ts b/test/cal/encryption/CryptoEncryptionHandle.test.ts index d55b077..4ccb92b 100644 --- a/test/cal/encryption/CryptoEncryptionHandle.test.ts +++ b/test/cal/encryption/CryptoEncryptionHandle.test.ts @@ -50,9 +50,7 @@ export class CryptoEncryptionHandleTest { const data = new CoreBuffer("0123456789ABCDEF"); const encrypted = await CryptoEncryptionHandle.encrypt(data, cryptoSecretKeyHandle); expect(encrypted).to.be.ok.and.to.be.instanceOf(CryptoCipher); - expect(encrypted.algorithm).to.equal( - CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(cryptoSecretKeyHandle.spec.cipher) - ); + expect(encrypted.algorithm).to.equal(await cryptoSecretKeyHandle.encryptionAlgorithm()); const decrypted = await CryptoEncryptionHandle.decrypt(encrypted, cryptoSecretKeyHandle); @@ -67,9 +65,7 @@ export class CryptoEncryptionHandleTest { crypto, hash ); - const cryptoEncryptionAlgorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher( - cryptoSecretKeyHandle.spec.cipher - ); + const cryptoEncryptionAlgorithm = await cryptoSecretKeyHandle.encryptionAlgorithm(); const nonce = await CryptoEncryptionHandle.createNonce( cryptoEncryptionAlgorithm, @@ -106,9 +102,7 @@ export class CryptoEncryptionHandleTest { hash ); - const cryptoEncryptionAlgorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher( - cryptoSecretKeyHandle.spec.cipher - ); + const cryptoEncryptionAlgorithm = await cryptoSecretKeyHandle.encryptionAlgorithm(); const nonce = await CryptoEncryptionHandle.createNonce( cryptoEncryptionAlgorithm, @@ -158,7 +152,7 @@ export class CryptoEncryptionHandleTest { ); const keyBufferPromise = CryptoEncryptionHandle.extractRawKey(key); - const algorithm = CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(key.spec.cipher); + const algorithm = await key.encryptionAlgorithm(); const keyObject: ICryptoSecretKeySerialized = { alg: algorithm, key: (await keyBufferPromise).toBase64URL() @@ -220,12 +214,11 @@ export class CryptoEncryptionHandleTest { it("should return a SecretKey", function () { expect(key).to.exist; expect(key).to.be.instanceOf(PortableKeyHandle); - expect(key.spec).to.exist; expect(key.keyHandle).to.exist; }); - it("should return a correct algorithm in the key", function () { - expect(key.spec).to.deep.equal(spec); + it("should return a correct algorithm in the key", async function () { + expect(await key.keyHandle.spec()).to.deep.equal(spec); }); it("should serialize and deserialize the key correctly", async function () { @@ -248,20 +241,24 @@ export class CryptoEncryptionHandleTest { expect(deserialized.id).to.equal(key.id); }); - it("should not deserialize a wrong KeySpec", async function () { + it("should not deserialize a non existing key", async function () { await expectThrows(() => { return PortableKeyHandle.fromJSON({ - kid: "3KpnHNPtcG", + kid: "this_key_does_not_exist", pnm: "SoftwareProvider", - spc: { - cipher: "XChaCha20Poly1305", - signing_hash: "Sha2_256a", - ephemeral: false, - non_exportable: false - }, "@type": "PortableKeyHandle" } as any); - }, "PortableKeyHandle.spec:Object :: Is not of type KeySpec."); + }, /.*error\.crypto\.cal\.loadKey.*Failed to load key during deserialization.*/); + }); + + it("should not deserialize with a non initialized provider", async function () { + await expectThrows(() => { + return PortableKeyHandle.fromJSON({ + kid: "3KpnHNPtcG", + pnm: "ProviderThatDoesNotExist", + "@type": "PortableKeyHandle" + } as any); + }, /.*error\.crypto\.cal\.thisProviderNotInitialized.*/); }); it("should serialize and deserialize the key using base64 correctly", async function () { diff --git a/test/cal/encryption/CryptoSecretKeyHandle.test.ts b/test/cal/encryption/CryptoSecretKeyHandle.test.ts index 7d988e3..fc50191 100644 --- a/test/cal/encryption/CryptoSecretKeyHandle.test.ts +++ b/test/cal/encryption/CryptoSecretKeyHandle.test.ts @@ -54,7 +54,6 @@ export class CryptoSecretKeyHandleTest { const loadedKeyHandle = await DeviceBoundKeyHandle.from({ id: keyHandle.id, - spec: keyHandle.spec, providerName: keyHandle.providerName }); From f10dff10a3ca2ca99dbf574eddce4e372d47d378 Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 12:41:56 +0200 Subject: [PATCH 2/7] refactor!: derived key handles are not serializable Refactored *Derived variant of key handles to not use BaseKeyHandle anymore, but rather a DerivedBaseKeyHandle that does not support serialization. The need stems from derived key handles being ephemeral. If they are being dropped, they do not exist anymore. Hence deserializing ephemeral key handles does not make sense and will result in an error. --- src/crypto-layer/CryptoDerivationHandle.ts | 11 +-- .../encryption/BaseDerivedKeyHandle.ts | 0 src/crypto-layer/encryption/BaseKeyHandle.ts | 10 +-- .../encryption/CryptoEncryptionHandle.ts | 17 ++-- .../encryption/DerivedBaseKeyHandle.ts | 88 +++++++++++++++++++ .../encryption/DeviceBoundDerivedKeyHandle.ts | 17 +--- .../encryption/PortableDerivedKeyHandle.ts | 17 +--- src/crypto-layer/index.ts | 1 + test/cal/KeyValidation.ts | 15 +++- 9 files changed, 122 insertions(+), 54 deletions(-) delete mode 100644 src/crypto-layer/encryption/BaseDerivedKeyHandle.ts create mode 100644 src/crypto-layer/encryption/DerivedBaseKeyHandle.ts diff --git a/src/crypto-layer/CryptoDerivationHandle.ts b/src/crypto-layer/CryptoDerivationHandle.ts index 4234c3f..ebb42d7 100644 --- a/src/crypto-layer/CryptoDerivationHandle.ts +++ b/src/crypto-layer/CryptoDerivationHandle.ts @@ -9,7 +9,8 @@ import { CryptoEncryptionAlgorithm } from "../encryption/CryptoEncryption"; import { CryptoHashAlgorithm } from "../hash/CryptoHash"; import { getProvider, ProviderIdentifier } from "./CryptoLayerProviders"; import { CryptoLayerUtils } from "./CryptoLayerUtils"; -import { BaseKeyHandle, BaseKeyHandleConstructor } from "./encryption/BaseKeyHandle"; +import { BaseKeyHandle } from "./encryption/BaseKeyHandle"; +import { DerivedBaseKeyHandle, DerivedBaseKeyHandleConstructor } from "./encryption/DerivedBaseKeyHandle"; import { DeviceBoundDerivedKeyHandle } from "./encryption/DeviceBoundDerivedKeyHandle"; import { DeviceBoundKeyHandle } from "./encryption/DeviceBoundKeyHandle"; import { PortableDerivedKeyHandle } from "./encryption/PortableDerivedKeyHandle"; @@ -28,8 +29,8 @@ export interface DeriveKeyHandleFromPasswordParameters { } export class CryptoDerivationHandle { - private static async deriveKeyHandleFromPassword( - constructor: BaseKeyHandleConstructor, + private static async deriveKeyHandleFromPassword( + constructor: DerivedBaseKeyHandleConstructor, derivationParameters: DeriveKeyHandleFromPasswordParameters, keySpecOfResultingKey: KeySpec ): Promise { @@ -105,8 +106,8 @@ export class CryptoDerivationHandle { ); } - private static async deriveKeyFromBaseKeyHandle( - constructor: BaseKeyHandleConstructor, + private static async deriveKeyFromBaseKeyHandle( + constructor: DerivedBaseKeyHandleConstructor, baseKey: T, keyId: number, context: string diff --git a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/crypto-layer/encryption/BaseKeyHandle.ts b/src/crypto-layer/encryption/BaseKeyHandle.ts index e9098aa..416fabc 100644 --- a/src/crypto-layer/encryption/BaseKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseKeyHandle.ts @@ -1,11 +1,11 @@ import { ISerializable, ISerialized, SerializableAsync, serialize, type, validate } from "@js-soft/ts-serval"; import { KeyHandle, KeySpec, Provider } from "@nmshd/rs-crypto-types"; -import { CryptoHashAlgorithm } from "src/hash/CryptoHash"; import { CoreBuffer, ICoreBuffer } from "../../CoreBuffer"; import { CryptoError } from "../../CryptoError"; import { CryptoErrorCode } from "../../CryptoErrorCode"; import { CryptoSerializableAsync } from "../../CryptoSerializable"; import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; +import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; import { CryptoLayerUtils } from "../CryptoLayerUtils"; @@ -19,15 +19,11 @@ export interface IBaseKeyHandle extends ISerializable { providerName: string; } -export interface BaseKeyHandleConstructor { +export interface BaseKeyHandleConstructor { new (): T; deserialize(value: string): Promise; - fromProviderAndKeyHandle( - provider: Provider, - keyHandle: KeyHandle, - other?: { providerName?: string; keyId?: string; keySpec?: KeySpec } - ): Promise; + fromProviderAndKeyHandle(provider: Provider, keyHandle: KeyHandle): Promise; fromAny(value: any): Promise; } diff --git a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts index 3a67edb..25ccb7d 100644 --- a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts +++ b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts @@ -11,6 +11,7 @@ import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; import { CryptoLayerUtils } from "../CryptoLayerUtils"; import { BaseKeyHandle, BaseKeyHandleConstructor } from "./BaseKeyHandle"; +import { DerivedBaseKeyHandle, DerivedBaseKeyHandleConstructor } from "./DerivedBaseKeyHandle"; import { DeviceBoundKeyHandle } from "./DeviceBoundKeyHandle"; import { PortableDerivedKeyHandle } from "./PortableDerivedKeyHandle"; import { PortableKeyHandle } from "./PortableKeyHandle"; @@ -23,9 +24,7 @@ export class CryptoEncryptionHandle { ): Promise { const provider = getProvider(providerIdent); const keyHandle = await provider.createKey(spec); - const secretKeyHandle = await constructor.fromProviderAndKeyHandle(provider, keyHandle, { - keySpec: spec - }); + const secretKeyHandle = await constructor.fromProviderAndKeyHandle(provider, keyHandle); return secretKeyHandle; } @@ -59,7 +58,7 @@ export class CryptoEncryptionHandle { return await this.generateKeyHandle(PortableKeyHandle, providerIdent, portableSpec); } - public static async encrypt( + public static async encrypt( plaintext: CoreBuffer, secretKeyHandle: T, nonce?: CoreBuffer @@ -92,7 +91,7 @@ export class CryptoEncryptionHandle { }); } - public static async encryptWithCounter( + public static async encryptWithCounter( plaintext: CoreBuffer, secretKeyHandle: T, nonce: CoreBuffer, @@ -125,7 +124,7 @@ export class CryptoEncryptionHandle { }); } - public static async decrypt( + public static async decrypt( cipher: CryptoCipher, secretKeyHandle: T, nonce?: CoreBuffer @@ -159,7 +158,7 @@ export class CryptoEncryptionHandle { } } - public static async decryptWithCounter( + public static async decryptWithCounter( cipher: CryptoCipher, secretKeyHandle: T, nonce: CoreBuffer, @@ -226,8 +225,8 @@ export class CryptoEncryptionHandle { return CryptoSecretKey.from(cryptoSecretKeyObj); } - private static async keyHandleFromCryptoSecretKey( - constructor: BaseKeyHandleConstructor, + private static async keyHandleFromCryptoSecretKey( + constructor: DerivedBaseKeyHandleConstructor, providerIdent: ProviderIdentifier, cryptoSecretKey: CryptoSecretKey, signingHash: CryptoHashAlgorithm, diff --git a/src/crypto-layer/encryption/DerivedBaseKeyHandle.ts b/src/crypto-layer/encryption/DerivedBaseKeyHandle.ts new file mode 100644 index 0000000..a843cda --- /dev/null +++ b/src/crypto-layer/encryption/DerivedBaseKeyHandle.ts @@ -0,0 +1,88 @@ +// filepath: m:\DEV\WorkProjects\nmshd2\ts-crypto\src\crypto-layer\encryption\DerivedBaseKeyHandle.ts +import { KeyHandle, KeySpec, Provider } from "@nmshd/rs-crypto-types"; +import { ICoreBuffer } from "../../CoreBuffer"; +import { CryptoError } from "../../CryptoError"; +import { CryptoErrorCode } from "../../CryptoErrorCode"; +import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; // Path relative to src/crypto-layer/encryption/ +import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; // Assuming 'src/' is a root path or alias +import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; +import { CryptoLayerUtils } from "../CryptoLayerUtils"; // Path relative to src/crypto-layer/encryption/ + +export interface DerivedBaseKeyHandleConstructor { + new (): T; + + fromProviderAndKeyHandle(provider: Provider, keyHandle: KeyHandle): Promise; +} + +/** + * Variant of {@link BaseKeyHandle} without serialization and deserialization. + */ +export abstract class DerivedBaseKeyHandle { + public id: string; + public providerName: string; + + public provider: Provider; + public keyHandle: KeyHandle; + + public async encryptionAndHashAlgorithm(): Promise<[CryptoEncryptionAlgorithm, CryptoHashAlgorithm]> { + const spec = await this.keyHandle.spec(); + return [ + CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher), + CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash) + ]; + } + + public async encryptionAlgorithm(): Promise { + const spec = await this.keyHandle.spec(); + return CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher); + } + + public async hashAlgorithm(): Promise { + const spec = await this.keyHandle.spec(); + return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash); + } + + /** + * Creates a new {@link DerivedBaseKeyHandle} or its child from an existing {@link KeyHandle}. + */ + public static async fromProviderAndKeyHandle( + this: new () => T, + provider: Provider, + keyHandle: KeyHandle + ): Promise { + const result = new this(); + + [result.providerName, result.id] = await Promise.all([provider.providerName(), keyHandle.id()]); + + result.provider = provider; + result.keyHandle = keyHandle; + return result; + } +} + +export abstract class ImportableDerivedBaseKeyHandle extends DerivedBaseKeyHandle { + /** + * Creates a new {@link BaseKeyHandle} or its child by importing a raw key into a provider. + */ + public static async fromRawKey( + this: DerivedBaseKeyHandleConstructor, + providerIdent: ProviderIdentifier, + rawKey: ICoreBuffer, + spec: KeySpec + ): Promise { + const provider = getProvider(providerIdent); + let keyHandle; + try { + keyHandle = await provider.importKey(spec, rawKey.buffer); + } catch (e) { + throw new CryptoError( + CryptoErrorCode.CalImportOfKey, + "Failed to import raw symmetric key.", + undefined, + e as Error, + ImportableDerivedBaseKeyHandle.fromRawKey + ); + } + return await this.fromProviderAndKeyHandle(provider, keyHandle); + } +} diff --git a/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts b/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts index 85c2990..7592c9f 100644 --- a/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts @@ -1,22 +1,9 @@ import { type } from "@js-soft/ts-serval"; -import { CoreBuffer } from "../../CoreBuffer"; -import { BaseKeyHandle, IBaseKeyHandleSerialized } from "./BaseKeyHandle"; +import { DerivedBaseKeyHandle } from "./DerivedBaseKeyHandle"; /** Non exportable, ephemeral key handle that is derived from a device bound key handle. */ @type("DeviceBoundDerivedKeyHandle") -export class DeviceBoundDerivedKeyHandle extends BaseKeyHandle { +export class DeviceBoundDerivedKeyHandle extends DerivedBaseKeyHandle { // Phantom marker to make this type incompatible to other types that extend `BaseKeyHandle`. public readonly _isDeviceBoundDerivedKeyHandle = true; - - public override toJSON(verbose = true): IBaseKeyHandleSerialized { - return { - kid: this.id, - pnm: this.providerName, - "@type": verbose ? "DeviceBoundDerivedKeyHandle" : undefined - }; - } - - public override toBase64(verbose = true): string { - return CoreBuffer.utf8_base64(this.serialize(verbose)); - } } diff --git a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts index 297794e..3b8c097 100644 --- a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts @@ -1,21 +1,8 @@ import { type } from "@js-soft/ts-serval"; -import { CoreBuffer } from "../../CoreBuffer"; -import { BaseKeyHandle, IBaseKeyHandleSerialized } from "./BaseKeyHandle"; +import { ImportableDerivedBaseKeyHandle } from "./DerivedBaseKeyHandle"; @type("PortableDerivedKeyHandle") -export class PortableDerivedKeyHandle extends BaseKeyHandle { +export class PortableDerivedKeyHandle extends ImportableDerivedBaseKeyHandle { // Phantom marker to make this type incompatible to other types that extend `BaseKeyHandle`. public readonly _isPortableDeriveKeyHandle = true; - - public override toJSON(verbose = true): IBaseKeyHandleSerialized { - return { - kid: this.id, - pnm: this.providerName, - "@type": verbose ? "PortableDerivedKeyHandle" : undefined - }; - } - - public override toBase64(verbose = true): string { - return CoreBuffer.utf8_base64(this.serialize(verbose)); - } } diff --git a/src/crypto-layer/index.ts b/src/crypto-layer/index.ts index 6d42790..cd7fefd 100644 --- a/src/crypto-layer/index.ts +++ b/src/crypto-layer/index.ts @@ -4,6 +4,7 @@ export * from "./CryptoLayerProviders"; export * from "./CryptoLayerUtils"; export * from "./encryption/BaseKeyHandle"; export * from "./encryption/CryptoEncryptionHandle"; +export * from "./encryption/DerivedBaseKeyHandle"; export * from "./encryption/DeviceBoundDerivedKeyHandle"; export * from "./encryption/DeviceBoundKeyHandle"; export * from "./encryption/PortableDerivedKeyHandle"; diff --git a/test/cal/KeyValidation.ts b/test/cal/KeyValidation.ts index 8275d03..13325ea 100644 --- a/test/cal/KeyValidation.ts +++ b/test/cal/KeyValidation.ts @@ -3,6 +3,7 @@ import { CoreBuffer, CryptoCipher, CryptoEncryptionHandle, + DerivedBaseKeyHandle, DeviceBoundDerivedKeyHandle, DeviceBoundKeyHandle, PortableDerivedKeyHandle, @@ -14,7 +15,9 @@ import { expect } from "chai"; /** * Tests SecretKeyHandle for validity and executes the id function. */ -export async function assertSecretKeyHandleValid(handle: T): Promise { +export async function assertSecretKeyHandleValid( + handle: T +): Promise { expect(handle).to.exist; expect(handle.id).to.exist.and.to.be.a("string"); expect(handle.keyHandle).to.exist; @@ -44,7 +47,10 @@ export async function assertSecretKeyHandleValid(handle } } -async function testDecryptEncryptIsIdentityFunction(before: T, after: T): Promise { +async function testDecryptEncryptIsIdentityFunction( + before: T, + after: T +): Promise { const payload = CoreBuffer.fromUtf8("Hello World!"); const encryptedPayload = await CryptoEncryptionHandle.encrypt(payload, before); @@ -64,7 +70,10 @@ async function testDecryptEncryptIsIdentityFunction(bef /** * Test that the content of two SecretKeys match. */ -export async function assertSecretKeyHandleEqual(before: T, after: T): Promise { +export async function assertSecretKeyHandleEqual( + before: T, + after: T +): Promise { const [beforeSpec, afterSpec] = await Promise.all([before.keyHandle.spec(), after.keyHandle.spec()]); expect(beforeSpec).to.deep.equal(afterSpec); if ( From d7b46e05e7b8b5bd4cf148f31428faa787c59bf6 Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 15:41:02 +0200 Subject: [PATCH 3/7] refactor!: move construction method of key handles to CryptoEncryptionHandle --- src/crypto-layer/CryptoDerivationHandle.ts | 19 ++-- .../encryption/BaseDerivedKeyHandle.ts | 39 ++++++++ src/crypto-layer/encryption/BaseKeyHandle.ts | 50 ++--------- .../encryption/CryptoEncryptionHandle.ts | 41 ++++++--- .../encryption/DerivedBaseKeyHandle.ts | 88 ------------------- .../encryption/DeviceBoundDerivedKeyHandle.ts | 4 +- .../encryption/PortableDerivedKeyHandle.ts | 4 +- src/crypto-layer/index.ts | 2 +- test/cal/KeyValidation.ts | 8 +- .../encryption/CryptoEncryptionHandle.test.ts | 31 ++++--- 10 files changed, 116 insertions(+), 170 deletions(-) create mode 100644 src/crypto-layer/encryption/BaseDerivedKeyHandle.ts delete mode 100644 src/crypto-layer/encryption/DerivedBaseKeyHandle.ts diff --git a/src/crypto-layer/CryptoDerivationHandle.ts b/src/crypto-layer/CryptoDerivationHandle.ts index ebb42d7..798d156 100644 --- a/src/crypto-layer/CryptoDerivationHandle.ts +++ b/src/crypto-layer/CryptoDerivationHandle.ts @@ -9,8 +9,9 @@ import { CryptoEncryptionAlgorithm } from "../encryption/CryptoEncryption"; import { CryptoHashAlgorithm } from "../hash/CryptoHash"; import { getProvider, ProviderIdentifier } from "./CryptoLayerProviders"; import { CryptoLayerUtils } from "./CryptoLayerUtils"; +import { BaseDerivedKeyHandle } from "./encryption/BaseDerivedKeyHandle"; import { BaseKeyHandle } from "./encryption/BaseKeyHandle"; -import { DerivedBaseKeyHandle, DerivedBaseKeyHandleConstructor } from "./encryption/DerivedBaseKeyHandle"; +import { CryptoEncryptionHandle } from "./encryption/CryptoEncryptionHandle"; import { DeviceBoundDerivedKeyHandle } from "./encryption/DeviceBoundDerivedKeyHandle"; import { DeviceBoundKeyHandle } from "./encryption/DeviceBoundKeyHandle"; import { PortableDerivedKeyHandle } from "./encryption/PortableDerivedKeyHandle"; @@ -29,8 +30,8 @@ export interface DeriveKeyHandleFromPasswordParameters { } export class CryptoDerivationHandle { - private static async deriveKeyHandleFromPassword( - constructor: DerivedBaseKeyHandleConstructor, + private static async deriveKeyHandleFromPassword( + constructor: new () => T, derivationParameters: DeriveKeyHandleFromPasswordParameters, keySpecOfResultingKey: KeySpec ): Promise { @@ -63,7 +64,7 @@ export class CryptoDerivationHandle { ); } - return await constructor.fromProviderAndKeyHandle(provider, keyHandle); + return await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle); } /** @@ -106,8 +107,8 @@ export class CryptoDerivationHandle { ); } - private static async deriveKeyFromBaseKeyHandle( - constructor: DerivedBaseKeyHandleConstructor, + private static async deriveKeyFromBaseKeyHandle( + constructor: new () => R, baseKey: T, keyId: number, context: string @@ -127,7 +128,11 @@ export class CryptoDerivationHandle { ); } - return await constructor.fromProviderAndKeyHandle(baseKey.provider, keyHandle); + return await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle( + constructor, + baseKey.provider, + keyHandle + ); } /** diff --git a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts new file mode 100644 index 0000000..8932166 --- /dev/null +++ b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts @@ -0,0 +1,39 @@ +// filepath: m:\DEV\WorkProjects\nmshd2\ts-crypto\src\crypto-layer\encryption\DerivedBaseKeyHandle.ts +import { KeyHandle, Provider } from "@nmshd/rs-crypto-types"; +import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; // Path relative to src/crypto-layer/encryption/ +import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; // Assuming 'src/' is a root path or alias +import { CryptoLayerUtils } from "../CryptoLayerUtils"; // Path relative to src/crypto-layer/encryption/ + +/** + * Variant of {@link BaseKeyHandle} without serialization and deserialization. + */ +export abstract class BaseDerivedKeyHandle { + public id: string; + public providerName: string; + + public provider: Provider; + public keyHandle: KeyHandle; + + public async encryptionAndHashAlgorithm(): Promise<[CryptoEncryptionAlgorithm, CryptoHashAlgorithm]> { + const spec = await this.keyHandle.spec(); + return [ + CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher), + CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash) + ]; + } + + public async encryptionAlgorithm(): Promise { + const spec = await this.keyHandle.spec(); + return CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher); + } + + public async hashAlgorithm(): Promise { + const spec = await this.keyHandle.spec(); + return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash); + } +} + +export abstract class ImportableBaseDerivedKeyHandle extends BaseDerivedKeyHandle { + // Phantom marker to make this type incompatible with `BaseDerivedKeyHandle`. + public readonly _importable = true; +} diff --git a/src/crypto-layer/encryption/BaseKeyHandle.ts b/src/crypto-layer/encryption/BaseKeyHandle.ts index 416fabc..e309799 100644 --- a/src/crypto-layer/encryption/BaseKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseKeyHandle.ts @@ -1,12 +1,12 @@ import { ISerializable, ISerialized, SerializableAsync, serialize, type, validate } from "@js-soft/ts-serval"; -import { KeyHandle, KeySpec, Provider } from "@nmshd/rs-crypto-types"; -import { CoreBuffer, ICoreBuffer } from "../../CoreBuffer"; +import { KeyHandle, Provider } from "@nmshd/rs-crypto-types"; +import { CoreBuffer } from "../../CoreBuffer"; import { CryptoError } from "../../CryptoError"; import { CryptoErrorCode } from "../../CryptoErrorCode"; import { CryptoSerializableAsync } from "../../CryptoSerializable"; import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; -import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; +import { getProvider } from "../CryptoLayerProviders"; import { CryptoLayerUtils } from "../CryptoLayerUtils"; export interface IBaseKeyHandleSerialized extends ISerialized { @@ -23,7 +23,6 @@ export interface BaseKeyHandleConstructor { new (): T; deserialize(value: string): Promise; - fromProviderAndKeyHandle(provider: Provider, keyHandle: KeyHandle): Promise; fromAny(value: any): Promise; } @@ -91,23 +90,6 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I return await this.deserialize(CoreBuffer.base64_utf8(value)); } - /** - * Creates a new {@link BaseKeyHandle} or its child from an existing {@link KeyHandle}. - */ - public static async fromProviderAndKeyHandle( - this: new () => T, - provider: Provider, - keyHandle: KeyHandle - ): Promise { - const result = new this(); - - [result.providerName, result.id] = await Promise.all([provider.providerName(), keyHandle.id()]); - - result.provider = provider; - result.keyHandle = keyHandle; - return result; - } - protected static override preFrom(value: any): any { if (value.kid) { value = { @@ -146,28 +128,6 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I } export abstract class ImportableBaseKeyHandle extends BaseKeyHandle { - /** - * Creates a new {@link BaseKeyHandle} or its child by importing a raw key into a provider. - */ - public static async fromRawKey( - this: BaseKeyHandleConstructor, - providerIdent: ProviderIdentifier, - rawKey: ICoreBuffer, - spec: KeySpec - ): Promise { - const provider = getProvider(providerIdent); - let keyHandle; - try { - keyHandle = await provider.importKey(spec, rawKey.buffer); - } catch (e) { - throw new CryptoError( - CryptoErrorCode.CalImportOfKey, - "Failed to import raw symmetric key.", - undefined, - e as Error, - ImportableBaseKeyHandle.fromRawKey - ); - } - return await this.fromProviderAndKeyHandle(provider, keyHandle); - } + // Phantom marker to make this type incompatible with `BaseKeyHandle`. + public readonly _importable = true; } diff --git a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts index 25ccb7d..18ba230 100644 --- a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts +++ b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { KeySpec, Provider } from "@nmshd/rs-crypto-types"; +import { KeyHandle, KeySpec, Provider } from "@nmshd/rs-crypto-types"; import { CoreBuffer } from "../../CoreBuffer"; import { CryptoError } from "../../CryptoError"; import { CryptoErrorCode } from "../../CryptoErrorCode"; @@ -10,13 +10,30 @@ import { CryptoSecretKey, ICryptoSecretKey } from "../../encryption/CryptoSecret import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; import { CryptoLayerUtils } from "../CryptoLayerUtils"; +import { BaseDerivedKeyHandle } from "./BaseDerivedKeyHandle"; import { BaseKeyHandle, BaseKeyHandleConstructor } from "./BaseKeyHandle"; -import { DerivedBaseKeyHandle, DerivedBaseKeyHandleConstructor } from "./DerivedBaseKeyHandle"; import { DeviceBoundKeyHandle } from "./DeviceBoundKeyHandle"; import { PortableDerivedKeyHandle } from "./PortableDerivedKeyHandle"; import { PortableKeyHandle } from "./PortableKeyHandle"; export class CryptoEncryptionHandle { + /** + * Creates a new {@link BaseKeyHandle} / {@link DerivedBaseKeyHandle} or its child from an existing {@link KeyHandle}. + */ + public static async _KeyHandleFromProviderAndCalKeyHandle( + constructor: new () => T, + provider: Provider, + keyHandle: KeyHandle + ): Promise { + const result = new constructor(); + + [result.providerName, result.id] = await Promise.all([provider.providerName(), keyHandle.id()]); + + result.provider = provider; + result.keyHandle = keyHandle; + return result; + } + private static async generateKeyHandle( constructor: BaseKeyHandleConstructor, providerIdent: ProviderIdentifier, @@ -24,7 +41,11 @@ export class CryptoEncryptionHandle { ): Promise { const provider = getProvider(providerIdent); const keyHandle = await provider.createKey(spec); - const secretKeyHandle = await constructor.fromProviderAndKeyHandle(provider, keyHandle); + const secretKeyHandle = await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle( + constructor, + provider, + keyHandle + ); return secretKeyHandle; } @@ -58,7 +79,7 @@ export class CryptoEncryptionHandle { return await this.generateKeyHandle(PortableKeyHandle, providerIdent, portableSpec); } - public static async encrypt( + public static async encrypt( plaintext: CoreBuffer, secretKeyHandle: T, nonce?: CoreBuffer @@ -91,7 +112,7 @@ export class CryptoEncryptionHandle { }); } - public static async encryptWithCounter( + public static async encryptWithCounter( plaintext: CoreBuffer, secretKeyHandle: T, nonce: CoreBuffer, @@ -124,7 +145,7 @@ export class CryptoEncryptionHandle { }); } - public static async decrypt( + public static async decrypt( cipher: CryptoCipher, secretKeyHandle: T, nonce?: CoreBuffer @@ -158,7 +179,7 @@ export class CryptoEncryptionHandle { } } - public static async decryptWithCounter( + public static async decryptWithCounter( cipher: CryptoCipher, secretKeyHandle: T, nonce: CoreBuffer, @@ -225,8 +246,8 @@ export class CryptoEncryptionHandle { return CryptoSecretKey.from(cryptoSecretKeyObj); } - private static async keyHandleFromCryptoSecretKey( - constructor: DerivedBaseKeyHandleConstructor, + private static async keyHandleFromCryptoSecretKey( + constructor: new () => T, providerIdent: ProviderIdentifier, cryptoSecretKey: CryptoSecretKey, signingHash: CryptoHashAlgorithm, @@ -243,7 +264,7 @@ export class CryptoEncryptionHandle { const provider = getProvider(providerIdent); const keyHandle = await provider.importKey(keySpec, cryptoSecretKey.secretKey.buffer); - return await constructor.fromProviderAndKeyHandle(provider, keyHandle); + return await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle); } public static async portableKeyHandleFromCryptoSecretKey( diff --git a/src/crypto-layer/encryption/DerivedBaseKeyHandle.ts b/src/crypto-layer/encryption/DerivedBaseKeyHandle.ts deleted file mode 100644 index a843cda..0000000 --- a/src/crypto-layer/encryption/DerivedBaseKeyHandle.ts +++ /dev/null @@ -1,88 +0,0 @@ -// filepath: m:\DEV\WorkProjects\nmshd2\ts-crypto\src\crypto-layer\encryption\DerivedBaseKeyHandle.ts -import { KeyHandle, KeySpec, Provider } from "@nmshd/rs-crypto-types"; -import { ICoreBuffer } from "../../CoreBuffer"; -import { CryptoError } from "../../CryptoError"; -import { CryptoErrorCode } from "../../CryptoErrorCode"; -import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; // Path relative to src/crypto-layer/encryption/ -import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; // Assuming 'src/' is a root path or alias -import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; -import { CryptoLayerUtils } from "../CryptoLayerUtils"; // Path relative to src/crypto-layer/encryption/ - -export interface DerivedBaseKeyHandleConstructor { - new (): T; - - fromProviderAndKeyHandle(provider: Provider, keyHandle: KeyHandle): Promise; -} - -/** - * Variant of {@link BaseKeyHandle} without serialization and deserialization. - */ -export abstract class DerivedBaseKeyHandle { - public id: string; - public providerName: string; - - public provider: Provider; - public keyHandle: KeyHandle; - - public async encryptionAndHashAlgorithm(): Promise<[CryptoEncryptionAlgorithm, CryptoHashAlgorithm]> { - const spec = await this.keyHandle.spec(); - return [ - CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher), - CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash) - ]; - } - - public async encryptionAlgorithm(): Promise { - const spec = await this.keyHandle.spec(); - return CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher); - } - - public async hashAlgorithm(): Promise { - const spec = await this.keyHandle.spec(); - return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash); - } - - /** - * Creates a new {@link DerivedBaseKeyHandle} or its child from an existing {@link KeyHandle}. - */ - public static async fromProviderAndKeyHandle( - this: new () => T, - provider: Provider, - keyHandle: KeyHandle - ): Promise { - const result = new this(); - - [result.providerName, result.id] = await Promise.all([provider.providerName(), keyHandle.id()]); - - result.provider = provider; - result.keyHandle = keyHandle; - return result; - } -} - -export abstract class ImportableDerivedBaseKeyHandle extends DerivedBaseKeyHandle { - /** - * Creates a new {@link BaseKeyHandle} or its child by importing a raw key into a provider. - */ - public static async fromRawKey( - this: DerivedBaseKeyHandleConstructor, - providerIdent: ProviderIdentifier, - rawKey: ICoreBuffer, - spec: KeySpec - ): Promise { - const provider = getProvider(providerIdent); - let keyHandle; - try { - keyHandle = await provider.importKey(spec, rawKey.buffer); - } catch (e) { - throw new CryptoError( - CryptoErrorCode.CalImportOfKey, - "Failed to import raw symmetric key.", - undefined, - e as Error, - ImportableDerivedBaseKeyHandle.fromRawKey - ); - } - return await this.fromProviderAndKeyHandle(provider, keyHandle); - } -} diff --git a/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts b/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts index 7592c9f..56764bd 100644 --- a/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/DeviceBoundDerivedKeyHandle.ts @@ -1,9 +1,9 @@ import { type } from "@js-soft/ts-serval"; -import { DerivedBaseKeyHandle } from "./DerivedBaseKeyHandle"; +import { BaseDerivedKeyHandle } from "./BaseDerivedKeyHandle"; /** Non exportable, ephemeral key handle that is derived from a device bound key handle. */ @type("DeviceBoundDerivedKeyHandle") -export class DeviceBoundDerivedKeyHandle extends DerivedBaseKeyHandle { +export class DeviceBoundDerivedKeyHandle extends BaseDerivedKeyHandle { // Phantom marker to make this type incompatible to other types that extend `BaseKeyHandle`. public readonly _isDeviceBoundDerivedKeyHandle = true; } diff --git a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts index 3b8c097..299b28e 100644 --- a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts @@ -1,8 +1,8 @@ import { type } from "@js-soft/ts-serval"; -import { ImportableDerivedBaseKeyHandle } from "./DerivedBaseKeyHandle"; +import { ImportableBaseDerivedKeyHandle } from "./BaseDerivedKeyHandle"; @type("PortableDerivedKeyHandle") -export class PortableDerivedKeyHandle extends ImportableDerivedBaseKeyHandle { +export class PortableDerivedKeyHandle extends ImportableBaseDerivedKeyHandle { // Phantom marker to make this type incompatible to other types that extend `BaseKeyHandle`. public readonly _isPortableDeriveKeyHandle = true; } diff --git a/src/crypto-layer/index.ts b/src/crypto-layer/index.ts index cd7fefd..7234409 100644 --- a/src/crypto-layer/index.ts +++ b/src/crypto-layer/index.ts @@ -2,9 +2,9 @@ export * from "./CryptoDerivationHandle"; export * from "./CryptoLayerConfig"; export * from "./CryptoLayerProviders"; export * from "./CryptoLayerUtils"; +export * from "./encryption/BaseDerivedKeyHandle"; export * from "./encryption/BaseKeyHandle"; export * from "./encryption/CryptoEncryptionHandle"; -export * from "./encryption/DerivedBaseKeyHandle"; export * from "./encryption/DeviceBoundDerivedKeyHandle"; export * from "./encryption/DeviceBoundKeyHandle"; export * from "./encryption/PortableDerivedKeyHandle"; diff --git a/test/cal/KeyValidation.ts b/test/cal/KeyValidation.ts index 13325ea..54217a8 100644 --- a/test/cal/KeyValidation.ts +++ b/test/cal/KeyValidation.ts @@ -1,9 +1,9 @@ import { + BaseDerivedKeyHandle, BaseKeyHandle, CoreBuffer, CryptoCipher, CryptoEncryptionHandle, - DerivedBaseKeyHandle, DeviceBoundDerivedKeyHandle, DeviceBoundKeyHandle, PortableDerivedKeyHandle, @@ -15,7 +15,7 @@ import { expect } from "chai"; /** * Tests SecretKeyHandle for validity and executes the id function. */ -export async function assertSecretKeyHandleValid( +export async function assertSecretKeyHandleValid( handle: T ): Promise { expect(handle).to.exist; @@ -47,7 +47,7 @@ export async function assertSecretKeyHandleValid( +async function testDecryptEncryptIsIdentityFunction( before: T, after: T ): Promise { @@ -70,7 +70,7 @@ async function testDecryptEncryptIsIdentityFunction( +export async function assertSecretKeyHandleEqual( before: T, after: T ): Promise { diff --git a/test/cal/encryption/CryptoEncryptionHandle.test.ts b/test/cal/encryption/CryptoEncryptionHandle.test.ts index 4ccb92b..f803ba3 100644 --- a/test/cal/encryption/CryptoEncryptionHandle.test.ts +++ b/test/cal/encryption/CryptoEncryptionHandle.test.ts @@ -8,7 +8,6 @@ import { CryptoEncryptionHandle, CryptoError, CryptoHashAlgorithm, - CryptoLayerUtils, CryptoSecretKey, ICryptoSecretKeySerialized, PortableKeyHandle @@ -170,23 +169,33 @@ export class CryptoEncryptionHandleTest { expect(decrypted.buffer).to.deep.equal(payload.buffer); }); - it("libsodium key should be importable", async function () { + it("libsodium key should be importable as portable key handle", async function () { const libsodiumKey = await CryptoEncryption.generateKey( CryptoEncryptionAlgorithm.XCHACHA20_POLY1305 ); - const spec: KeySpec = { - cipher: CryptoLayerUtils.cipherFromCryptoEncryptionAlgorithm(libsodiumKey.algorithm), - signing_hash: "Sha2_256", - ephemeral: false, - non_exportable: false - }; + const keyHandle = await CryptoEncryptionHandle.portableKeyHandleFromCryptoSecretKey( + TEST_PROVIDER_IDENT, + libsodiumKey, + CryptoHashAlgorithm.SHA256 + ); - const keyHandle = await PortableKeyHandle.fromRawKey( + await assertSecretKeyHandleValid(keyHandle); + + expect(await keyHandle.keyHandle.extractKey()).to.deep.equal(libsodiumKey.secretKey.buffer); + }); + + it("libsodium key should be importable as portable derived key handle", async function () { + const libsodiumKey = await CryptoEncryption.generateKey( + CryptoEncryptionAlgorithm.XCHACHA20_POLY1305 + ); + + const keyHandle = await CryptoEncryptionHandle.portableDerivedKeyHandleFromCryptoSecretKey( TEST_PROVIDER_IDENT, - libsodiumKey.secretKey, - spec + libsodiumKey, + CryptoHashAlgorithm.SHA256 ); + await assertSecretKeyHandleValid(keyHandle); expect(await keyHandle.keyHandle.extractKey()).to.deep.equal(libsodiumKey.secretKey.buffer); From 5e69ca352a20c1ac81432c6a83a2c1988cb7fed8 Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 15:45:38 +0200 Subject: [PATCH 4/7] fix: from methods of key handles wrongly inferring BaseKeyHandle --- src/crypto-layer/encryption/BaseKeyHandle.ts | 29 ------------------- .../encryption/DeviceBoundKeyHandle.ts | 21 +++++++++++++- .../encryption/PortableKeyHandle.ts | 19 ++++++++++++ 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/crypto-layer/encryption/BaseKeyHandle.ts b/src/crypto-layer/encryption/BaseKeyHandle.ts index e309799..1acb7dc 100644 --- a/src/crypto-layer/encryption/BaseKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseKeyHandle.ts @@ -1,6 +1,5 @@ import { ISerializable, ISerialized, SerializableAsync, serialize, type, validate } from "@js-soft/ts-serval"; import { KeyHandle, Provider } from "@nmshd/rs-crypto-types"; -import { CoreBuffer } from "../../CoreBuffer"; import { CryptoError } from "../../CryptoError"; import { CryptoErrorCode } from "../../CryptoErrorCode"; import { CryptoSerializableAsync } from "../../CryptoSerializable"; @@ -62,34 +61,6 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash); } - /** - * Deserializes an object representation of a {@link BaseKeyHandle}. - * - * This method is not able to import raw keys or {@link KeyHandle}. - */ - public static async from( - this: BaseKeyHandleConstructor, - value: BaseKeyHandleConstructor | IBaseKeyHandle | CoreBuffer - ): Promise { - return await this.fromAny(value); - } - - /** @see from */ - public static async fromJSON( - this: BaseKeyHandleConstructor, - value: IBaseKeyHandleSerialized - ): Promise { - return await this.fromAny(value); - } - - /** @see from */ - public static async fromBase64( - this: BaseKeyHandleConstructor, - value: string - ): Promise { - return await this.deserialize(CoreBuffer.base64_utf8(value)); - } - protected static override preFrom(value: any): any { if (value.kid) { value = { diff --git a/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts b/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts index d0ae865..8c5f04f 100644 --- a/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts +++ b/src/crypto-layer/encryption/DeviceBoundKeyHandle.ts @@ -1,6 +1,6 @@ import { type } from "@js-soft/ts-serval"; import { CoreBuffer } from "../../CoreBuffer"; -import { BaseKeyHandle, IBaseKeyHandleSerialized } from "./BaseKeyHandle"; +import { BaseKeyHandle, IBaseKeyHandle, IBaseKeyHandleSerialized } from "./BaseKeyHandle"; /** Key handle that is non exportable (the key cannot be extracted). */ @type("DeviceBoundKeyHandle") @@ -19,4 +19,23 @@ export class DeviceBoundKeyHandle extends BaseKeyHandle { public override toBase64(verbose = true): string { return CoreBuffer.utf8_base64(this.serialize(verbose)); } + + /** + * Deserializes an object representation of a {@link DeviceBoundKeyHandle}. + * + * This method is not able to import raw keys or {@link KeyHandle}. + */ + public static async from(value: IBaseKeyHandle | CoreBuffer): Promise { + return await this.fromAny(value); + } + + /** @see from */ + public static async fromJSON(value: IBaseKeyHandleSerialized): Promise { + return await this.fromAny(value); + } + + /** @see from */ + public static async fromBase64(value: string): Promise { + return await this.deserialize(CoreBuffer.base64_utf8(value)); + } } diff --git a/src/crypto-layer/encryption/PortableKeyHandle.ts b/src/crypto-layer/encryption/PortableKeyHandle.ts index 7fcfe67..a6b0c5e 100644 --- a/src/crypto-layer/encryption/PortableKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableKeyHandle.ts @@ -19,4 +19,23 @@ export class PortableKeyHandle extends ImportableBaseKeyHandle { public override toBase64(verbose = true): string { return CoreBuffer.utf8_base64(this.serialize(verbose)); } + + /** + * Deserializes an object representation of a {@link PortableKeyHandle}. + * + * This method is not able to import raw keys or {@link KeyHandle}. + */ + public static async from(value: IBaseKeyHandleSerialized | CoreBuffer): Promise { + return await this.fromAny(value); + } + + /** @see from */ + public static async fromJSON(value: IBaseKeyHandleSerialized): Promise { + return await this.fromAny(value); + } + + /** @see from */ + public static async fromBase64(value: string): Promise { + return await this.deserialize(CoreBuffer.base64_utf8(value)); + } } From 8c1a53f60fc22c5304fc68e4731bf05323b6bc75 Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 15:48:31 +0200 Subject: [PATCH 5/7] refactor: remove unused type and useless comments --- src/crypto-layer/encryption/BaseDerivedKeyHandle.ts | 7 +++---- src/crypto-layer/encryption/BaseKeyHandle.ts | 7 ------- src/crypto-layer/encryption/CryptoEncryptionHandle.ts | 4 ++-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts index 8932166..0bd3e77 100644 --- a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts @@ -1,8 +1,7 @@ -// filepath: m:\DEV\WorkProjects\nmshd2\ts-crypto\src\crypto-layer\encryption\DerivedBaseKeyHandle.ts import { KeyHandle, Provider } from "@nmshd/rs-crypto-types"; -import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; // Path relative to src/crypto-layer/encryption/ -import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; // Assuming 'src/' is a root path or alias -import { CryptoLayerUtils } from "../CryptoLayerUtils"; // Path relative to src/crypto-layer/encryption/ +import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption"; +import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; +import { CryptoLayerUtils } from "../CryptoLayerUtils"; /** * Variant of {@link BaseKeyHandle} without serialization and deserialization. diff --git a/src/crypto-layer/encryption/BaseKeyHandle.ts b/src/crypto-layer/encryption/BaseKeyHandle.ts index 1acb7dc..f96f12f 100644 --- a/src/crypto-layer/encryption/BaseKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseKeyHandle.ts @@ -18,13 +18,6 @@ export interface IBaseKeyHandle extends ISerializable { providerName: string; } -export interface BaseKeyHandleConstructor { - new (): T; - - deserialize(value: string): Promise; - fromAny(value: any): Promise; -} - /** * Represents a handle to a secret key used for symmetric encryption/decryption within the crypto layer. * This handle encapsulates a reference to the key material, managed by the underlying crypto provider, diff --git a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts index 18ba230..eff6bc0 100644 --- a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts +++ b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts @@ -11,7 +11,7 @@ import { CryptoHashAlgorithm } from "../../hash/CryptoHash"; import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders"; import { CryptoLayerUtils } from "../CryptoLayerUtils"; import { BaseDerivedKeyHandle } from "./BaseDerivedKeyHandle"; -import { BaseKeyHandle, BaseKeyHandleConstructor } from "./BaseKeyHandle"; +import { BaseKeyHandle } from "./BaseKeyHandle"; import { DeviceBoundKeyHandle } from "./DeviceBoundKeyHandle"; import { PortableDerivedKeyHandle } from "./PortableDerivedKeyHandle"; import { PortableKeyHandle } from "./PortableKeyHandle"; @@ -35,7 +35,7 @@ export class CryptoEncryptionHandle { } private static async generateKeyHandle( - constructor: BaseKeyHandleConstructor, + constructor: new () => T, providerIdent: ProviderIdentifier, spec: KeySpec ): Promise { From dfd12c59d25a1b1206cae37d6f3db69cb65d37a5 Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 16:03:01 +0200 Subject: [PATCH 6/7] refactor: create nonce takes a provider identifier --- src/crypto-layer/CryptoDerivationHandle.ts | 4 +-- .../encryption/CryptoEncryptionHandle.ts | 28 +++++++++++++++---- .../encryption/CryptoEncryptionHandle.test.ts | 8 +++--- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/crypto-layer/CryptoDerivationHandle.ts b/src/crypto-layer/CryptoDerivationHandle.ts index 798d156..f4510ab 100644 --- a/src/crypto-layer/CryptoDerivationHandle.ts +++ b/src/crypto-layer/CryptoDerivationHandle.ts @@ -64,7 +64,7 @@ export class CryptoDerivationHandle { ); } - return await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle); + return await CryptoEncryptionHandle._keyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle); } /** @@ -128,7 +128,7 @@ export class CryptoDerivationHandle { ); } - return await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle( + return await CryptoEncryptionHandle._keyHandleFromProviderAndCalKeyHandle( constructor, baseKey.provider, keyHandle diff --git a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts index eff6bc0..5827f21 100644 --- a/src/crypto-layer/encryption/CryptoEncryptionHandle.ts +++ b/src/crypto-layer/encryption/CryptoEncryptionHandle.ts @@ -20,7 +20,7 @@ export class CryptoEncryptionHandle { /** * Creates a new {@link BaseKeyHandle} / {@link DerivedBaseKeyHandle} or its child from an existing {@link KeyHandle}. */ - public static async _KeyHandleFromProviderAndCalKeyHandle( + public static async _keyHandleFromProviderAndCalKeyHandle( constructor: new () => T, provider: Provider, keyHandle: KeyHandle @@ -41,7 +41,7 @@ export class CryptoEncryptionHandle { ): Promise { const provider = getProvider(providerIdent); const keyHandle = await provider.createKey(spec); - const secretKeyHandle = await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle( + const secretKeyHandle = await CryptoEncryptionHandle._keyHandleFromProviderAndCalKeyHandle( constructor, provider, keyHandle @@ -87,7 +87,7 @@ export class CryptoEncryptionHandle { const encryptionAlgorithm = await secretKeyHandle.encryptionAlgorithm(); if (nonce === undefined || nonce.buffer.length === 0) { - nonce = await this.createNonce(encryptionAlgorithm, secretKeyHandle.provider); + nonce = await this.createNonce({ providerName: secretKeyHandle.providerName }, encryptionAlgorithm); } else { CryptoValidation.checkNonceForAlgorithm(nonce, encryptionAlgorithm); } @@ -206,7 +206,12 @@ export class CryptoEncryptionHandle { } } - public static async createNonce(algorithm: CryptoEncryptionAlgorithm, provider: Provider): Promise { + public static async createNonce( + providerIdent: ProviderIdentifier, + algorithm: CryptoEncryptionAlgorithm + ): Promise { + const provider = getProvider(providerIdent); + let nonceLength; switch (algorithm) { case CryptoEncryptionAlgorithm.AES128_GCM: @@ -262,9 +267,20 @@ export class CryptoEncryptionHandle { }; const provider = getProvider(providerIdent); - const keyHandle = await provider.importKey(keySpec, cryptoSecretKey.secretKey.buffer); + let keyHandle: KeyHandle; + try { + keyHandle = await provider.importKey(keySpec, cryptoSecretKey.secretKey.buffer); + } catch (e) { + throw new CryptoError( + CryptoErrorCode.CalImportOfKey, + "Failed to import crypto secret key.", + undefined, + e as Error, + CryptoEncryptionHandle.keyHandleFromCryptoSecretKey + ); + } - return await CryptoEncryptionHandle._KeyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle); + return await CryptoEncryptionHandle._keyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle); } public static async portableKeyHandleFromCryptoSecretKey( diff --git a/test/cal/encryption/CryptoEncryptionHandle.test.ts b/test/cal/encryption/CryptoEncryptionHandle.test.ts index f803ba3..7e0f214 100644 --- a/test/cal/encryption/CryptoEncryptionHandle.test.ts +++ b/test/cal/encryption/CryptoEncryptionHandle.test.ts @@ -67,8 +67,8 @@ export class CryptoEncryptionHandleTest { const cryptoEncryptionAlgorithm = await cryptoSecretKeyHandle.encryptionAlgorithm(); const nonce = await CryptoEncryptionHandle.createNonce( - cryptoEncryptionAlgorithm, - cryptoSecretKeyHandle.provider + TEST_PROVIDER_IDENT, + cryptoEncryptionAlgorithm ); const data = new CoreBuffer("0123456789ABCDEF"); @@ -104,8 +104,8 @@ export class CryptoEncryptionHandleTest { const cryptoEncryptionAlgorithm = await cryptoSecretKeyHandle.encryptionAlgorithm(); const nonce = await CryptoEncryptionHandle.createNonce( - cryptoEncryptionAlgorithm, - cryptoSecretKeyHandle.provider + TEST_PROVIDER_IDENT, + cryptoEncryptionAlgorithm ); const data = new CoreBuffer("0123456789ABCDEF"); From 9a7430b3b39aa20be57430473a9ccf32b3dcaeaa Mon Sep 17 00:00:00 2001 From: Adam McKellar Date: Thu, 5 Jun 2025 16:11:12 +0200 Subject: [PATCH 7/7] removed: importable base key handle abstraction --- src/crypto-layer/encryption/BaseDerivedKeyHandle.ts | 5 ----- src/crypto-layer/encryption/BaseKeyHandle.ts | 5 ----- src/crypto-layer/encryption/PortableDerivedKeyHandle.ts | 4 ++-- src/crypto-layer/encryption/PortableKeyHandle.ts | 4 ++-- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts index 0bd3e77..b5787b2 100644 --- a/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseDerivedKeyHandle.ts @@ -31,8 +31,3 @@ export abstract class BaseDerivedKeyHandle { return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash); } } - -export abstract class ImportableBaseDerivedKeyHandle extends BaseDerivedKeyHandle { - // Phantom marker to make this type incompatible with `BaseDerivedKeyHandle`. - public readonly _importable = true; -} diff --git a/src/crypto-layer/encryption/BaseKeyHandle.ts b/src/crypto-layer/encryption/BaseKeyHandle.ts index f96f12f..8dc9656 100644 --- a/src/crypto-layer/encryption/BaseKeyHandle.ts +++ b/src/crypto-layer/encryption/BaseKeyHandle.ts @@ -90,8 +90,3 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I return value; } } - -export abstract class ImportableBaseKeyHandle extends BaseKeyHandle { - // Phantom marker to make this type incompatible with `BaseKeyHandle`. - public readonly _importable = true; -} diff --git a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts index 299b28e..3d8dfa1 100644 --- a/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableDerivedKeyHandle.ts @@ -1,8 +1,8 @@ import { type } from "@js-soft/ts-serval"; -import { ImportableBaseDerivedKeyHandle } from "./BaseDerivedKeyHandle"; +import { BaseDerivedKeyHandle } from "./BaseDerivedKeyHandle"; @type("PortableDerivedKeyHandle") -export class PortableDerivedKeyHandle extends ImportableBaseDerivedKeyHandle { +export class PortableDerivedKeyHandle extends BaseDerivedKeyHandle { // Phantom marker to make this type incompatible to other types that extend `BaseKeyHandle`. public readonly _isPortableDeriveKeyHandle = true; } diff --git a/src/crypto-layer/encryption/PortableKeyHandle.ts b/src/crypto-layer/encryption/PortableKeyHandle.ts index a6b0c5e..0bf64f0 100644 --- a/src/crypto-layer/encryption/PortableKeyHandle.ts +++ b/src/crypto-layer/encryption/PortableKeyHandle.ts @@ -1,10 +1,10 @@ import { type } from "@js-soft/ts-serval"; import { CoreBuffer } from "../../CoreBuffer"; -import { IBaseKeyHandleSerialized, ImportableBaseKeyHandle } from "./BaseKeyHandle"; +import { BaseKeyHandle, IBaseKeyHandleSerialized } from "./BaseKeyHandle"; /** Key handle that is exportable and can also be created by importing a key. */ @type("PortableKeyHandle") -export class PortableKeyHandle extends ImportableBaseKeyHandle { +export class PortableKeyHandle extends BaseKeyHandle { // Phantom marker to make this type incompatible to other types that extend `BaseKeyHandle`. public readonly _isPortableKeyHandle = true;