Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CryptoErrorCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
20 changes: 13 additions & 7 deletions src/crypto-layer/CryptoDerivationHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ 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 { BaseDerivedKeyHandle } from "./encryption/BaseDerivedKeyHandle";
import { BaseKeyHandle } from "./encryption/BaseKeyHandle";
import { CryptoEncryptionHandle } from "./encryption/CryptoEncryptionHandle";
import { DeviceBoundDerivedKeyHandle } from "./encryption/DeviceBoundDerivedKeyHandle";
import { DeviceBoundKeyHandle } from "./encryption/DeviceBoundKeyHandle";
import { PortableDerivedKeyHandle } from "./encryption/PortableDerivedKeyHandle";
Expand All @@ -28,8 +30,8 @@ export interface DeriveKeyHandleFromPasswordParameters {
}

export class CryptoDerivationHandle {
private static async deriveKeyHandleFromPassword<T extends BaseKeyHandle>(
constructor: BaseKeyHandleConstructor<T>,
private static async deriveKeyHandleFromPassword<T extends BaseDerivedKeyHandle>(
constructor: new () => T,
derivationParameters: DeriveKeyHandleFromPasswordParameters,
keySpecOfResultingKey: KeySpec
): Promise<T> {
Expand Down Expand Up @@ -62,7 +64,7 @@ export class CryptoDerivationHandle {
);
}

return await constructor.fromProviderAndKeyHandle(provider, keyHandle);
return await CryptoEncryptionHandle._keyHandleFromProviderAndCalKeyHandle(constructor, provider, keyHandle);
}

/**
Expand Down Expand Up @@ -105,8 +107,8 @@ export class CryptoDerivationHandle {
);
}

private static async deriveKeyFromBaseKeyHandle<T extends BaseKeyHandle, R extends BaseKeyHandle>(
constructor: BaseKeyHandleConstructor<R>,
private static async deriveKeyFromBaseKeyHandle<T extends BaseKeyHandle, R extends BaseDerivedKeyHandle>(
constructor: new () => R,
baseKey: T,
keyId: number,
context: string
Expand All @@ -126,7 +128,11 @@ export class CryptoDerivationHandle {
);
}

return await constructor.fromProviderAndKeyHandle(baseKey.provider, keyHandle);
return await CryptoEncryptionHandle._keyHandleFromProviderAndCalKeyHandle(
constructor,
baseKey.provider,
keyHandle
);
}

/**
Expand Down
33 changes: 33 additions & 0 deletions src/crypto-layer/encryption/BaseDerivedKeyHandle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { KeyHandle, Provider } from "@nmshd/rs-crypto-types";
import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption";
import { CryptoHashAlgorithm } from "../../hash/CryptoHash";
import { CryptoLayerUtils } from "../CryptoLayerUtils";

/**
* 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<CryptoEncryptionAlgorithm> {
const spec = await this.keyHandle.spec();
return CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher);
}

public async hashAlgorithm(): Promise<CryptoHashAlgorithm> {
const spec = await this.keyHandle.spec();
return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash);
}
}
121 changes: 26 additions & 95 deletions src/crypto-layer/encryption/BaseKeyHandle.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,21 @@
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 { CoreBuffer, ICoreBuffer } from "../../CoreBuffer";
import { KeyHandle, Provider } from "@nmshd/rs-crypto-types";
import { CryptoError } from "../../CryptoError";
import { CryptoErrorCode } from "../../CryptoErrorCode";
import { CryptoSerializableAsync } from "../../CryptoSerializable";
import { getProvider, ProviderIdentifier } from "../CryptoLayerProviders";
import { CryptoEncryptionAlgorithm } from "../../encryption/CryptoEncryption";
import { CryptoHashAlgorithm } from "../../hash/CryptoHash";
import { getProvider } 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<T extends BaseKeyHandle> {
new (): T;

deserialize(value: string): Promise<T>;
fromProviderAndKeyHandle(
provider: Provider,
keyHandle: KeyHandle,
other?: { providerName?: string; keyId?: string; keySpec?: KeySpec }
): Promise<T>;
fromAny(value: any): Promise<T>;
}

/**
Expand All @@ -46,65 +33,25 @@ 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;

/**
* Deserializes an object representation of a {@link BaseKeyHandle}.
*
* This method is not able to import raw keys or {@link KeyHandle}.
*/
public static async from<T extends BaseKeyHandle>(
this: BaseKeyHandleConstructor<T>,
value: BaseKeyHandleConstructor<T> | IBaseKeyHandle | CoreBuffer
): Promise<T> {
return await this.fromAny(value);
public async encryptionAndHashAlgorithm(): Promise<[CryptoEncryptionAlgorithm, CryptoHashAlgorithm]> {
const spec = await this.keyHandle.spec();
return [
CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher),
CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash)
];
}

/** @see from */
public static async fromJSON<T extends BaseKeyHandle>(
this: BaseKeyHandleConstructor<T>,
value: IBaseKeyHandleSerialized
): Promise<T> {
return await this.fromAny(value);
public async encryptionAlgorithm(): Promise<CryptoEncryptionAlgorithm> {
const spec = await this.keyHandle.spec();
return CryptoLayerUtils.cryptoEncryptionAlgorithmFromCipher(spec.cipher);
}

/** @see from */
public static async fromBase64<T extends BaseKeyHandle>(
this: BaseKeyHandleConstructor<T>,
value: string
): Promise<T> {
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<T extends BaseKeyHandle>(
this: new () => T,
provider: Provider,
keyHandle: KeyHandle
): Promise<T> {
const result = new this();

[result.providerName, result.id, result.spec] = await Promise.all([
provider.providerName(),
keyHandle.id(),
keyHandle.spec()
]);

result.provider = provider;
result.keyHandle = keyHandle;
return result;
public async hashAlgorithm(): Promise<CryptoHashAlgorithm> {
const spec = await this.keyHandle.spec();
return CryptoLayerUtils.cryptoHashAlgorithmFromCryptoHash(spec.signing_hash);
}

protected static override preFrom(value: any): any {
Expand All @@ -125,37 +72,21 @@ export abstract class BaseKeyHandle extends CryptoSerializableAsync implements I
}

const provider = getProvider({ providerName: value.providerName });
const keyHandle = await provider.loadKey(value.id);

value.keyHandle = keyHandle;
value.provider = provider;
return value;
}
}

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<T extends ImportableBaseKeyHandle>(
this: BaseKeyHandleConstructor<T>,
providerIdent: ProviderIdentifier,
rawKey: ICoreBuffer,
spec: KeySpec
): Promise<T> {
const provider = getProvider(providerIdent);
let keyHandle;
let keyHandle: KeyHandle;
try {
keyHandle = await provider.importKey(spec, rawKey.buffer);
keyHandle = await provider.loadKey(value.id);
} catch (e) {
throw new CryptoError(
CryptoErrorCode.CalImportOfKey,
"Failed to import raw symmetric key.",
CryptoErrorCode.CalLoadKey,
"Failed to load key during deserialization.",
undefined,
e as Error,
ImportableBaseKeyHandle.fromRawKey
BaseKeyHandle.postFrom
);
}
return await this.fromProviderAndKeyHandle(provider, keyHandle);

value.keyHandle = keyHandle;
value.provider = provider;
return value;
}
}
Loading