fix: requested changes

This commit is contained in:
Daniel Hougaard
2025-04-04 04:21:00 +04:00
parent c7416c825c
commit 53b5497271
23 changed files with 222 additions and 202 deletions
+16 -16
View File
@@ -1,36 +1,36 @@
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify } from "@app/lib/crypto/sign";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm } from "@app/lib/crypto/sign";
import { BadRequestError } from "@app/lib/errors";
import { KmsKeyIntent } from "./kms-types";
import { KmsKeyUsage } from "./kms-types";
export const KMS_ROOT_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
export const getByteLengthForSymmetricEncryptionAlgorithm = (encryptionAlgorithm: SymmetricKeyEncryptDecrypt) => {
export const getByteLengthForSymmetricEncryptionAlgorithm = (encryptionAlgorithm: SymmetricKeyAlgorithm) => {
switch (encryptionAlgorithm) {
case SymmetricKeyEncryptDecrypt.AES_GCM_128:
case SymmetricKeyAlgorithm.AES_GCM_128:
return 16;
case SymmetricKeyEncryptDecrypt.AES_GCM_256:
case SymmetricKeyAlgorithm.AES_GCM_256:
default:
return 32;
}
};
export const verifyKeyTypeAndAlgorithm = (
type: KmsKeyIntent,
algorithm: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify,
keyUsage: KmsKeyUsage,
algorithm: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm,
extra?: {
forceType?: KmsKeyIntent;
forceType?: KmsKeyUsage;
}
) => {
if (extra?.forceType && type !== extra.forceType) {
if (extra?.forceType && keyUsage !== extra.forceType) {
throw new BadRequestError({
message: `Unsupported key type, expected ${extra.forceType} but got ${type}`
message: `Unsupported key type, expected ${extra.forceType} but got ${keyUsage}`
});
}
if (type === KmsKeyIntent.ENCRYPT_DECRYPT) {
if (!Object.values(SymmetricKeyEncryptDecrypt).includes(algorithm as SymmetricKeyEncryptDecrypt)) {
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
if (!Object.values(SymmetricKeyAlgorithm).includes(algorithm as SymmetricKeyAlgorithm)) {
throw new BadRequestError({
message: `Unsupported encryption algorithm for encrypt/decrypt key: ${algorithm as string}`
});
@@ -39,8 +39,8 @@ export const verifyKeyTypeAndAlgorithm = (
return true;
}
if (type === KmsKeyIntent.SIGN_VERIFY) {
if (!Object.values(AsymmetricKeySignVerify).includes(algorithm as AsymmetricKeySignVerify)) {
if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
if (!Object.values(AsymmetricKeyAlgorithm).includes(algorithm as AsymmetricKeyAlgorithm)) {
throw new BadRequestError({
message: `Unsupported sign/verify algorithm for sign/verify key: ${algorithm as string}`
});
@@ -50,6 +50,6 @@ export const verifyKeyTypeAndAlgorithm = (
}
throw new BadRequestError({
message: `Unsupported key type: ${type as string}`
message: `Unsupported key type: ${keyUsage as string}`
});
};
+46 -46
View File
@@ -17,9 +17,9 @@ import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
import { TEnvConfig } from "@app/lib/config/env";
import { randomSecureBytes } from "@app/lib/crypto";
import { symmetricCipherService, SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { symmetricCipherService, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { generateHash } from "@app/lib/crypto/encryption";
import { AsymmetricKeySignVerify, signingService } from "@app/lib/crypto/sign";
import { AsymmetricKeyAlgorithm, signingService } from "@app/lib/crypto/sign";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { alphaNumericNanoId } from "@app/lib/nanoid";
@@ -36,7 +36,7 @@ import { TKmsKeyDALFactory } from "./kms-key-dal";
import { TKmsRootConfigDALFactory } from "./kms-root-config-dal";
import {
KmsDataKey,
KmsKeyIntent,
KmsKeyUsage,
KmsType,
RootKeyEncryptionStrategy,
TDecryptWithKeyDTO,
@@ -94,21 +94,21 @@ export const kmsServiceFactory = ({
tx,
name,
projectId,
encryptionAlgorithm = SymmetricKeyEncryptDecrypt.AES_GCM_256,
type = KmsKeyIntent.ENCRYPT_DECRYPT,
encryptionAlgorithm = SymmetricKeyAlgorithm.AES_GCM_256,
keyUsage = KmsKeyUsage.ENCRYPT_DECRYPT,
description
}: TGenerateKMSDTO) => {
// daniel: ensure that the key type (sign/encrypt) and the encryption algorithm are compatible.
verifyKeyTypeAndAlgorithm(type, encryptionAlgorithm);
verifyKeyTypeAndAlgorithm(keyUsage, encryptionAlgorithm);
let kmsKeyMaterial: Buffer | null = null;
if (type === KmsKeyIntent.ENCRYPT_DECRYPT) {
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
kmsKeyMaterial = randomSecureBytes(
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyEncryptDecrypt)
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyAlgorithm)
);
} else if (type === KmsKeyIntent.SIGN_VERIFY) {
} else if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
const { generateAsymmetricPrivateKey, getPublicKeyFromPrivateKey } = signingService(
encryptionAlgorithm as AsymmetricKeySignVerify
encryptionAlgorithm as AsymmetricKeyAlgorithm
);
kmsKeyMaterial = await generateAsymmetricPrivateKey();
@@ -118,18 +118,18 @@ export const kmsServiceFactory = ({
if (!kmsKeyMaterial) {
throw new BadRequestError({
message: `Invalid KMS key type. No key material was created for key type '${type}' using algorithm '${encryptionAlgorithm}'`
message: `Invalid KMS key type. No key material was created for key usage '${keyUsage}' using algorithm '${encryptionAlgorithm}'`
});
}
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
const sanitizedName = name ? slugify(name) : slugify(alphaNumericNanoId(8).toLowerCase());
const dbQuery = async (db: Knex) => {
const kmsDoc = await kmsDAL.create(
{
name: sanitizedName,
type,
keyUsage,
orgId,
isReserved,
projectId,
@@ -169,7 +169,7 @@ export const kmsServiceFactory = ({
*/
const encryptWithInputKey = async ({ key }: Omit<TEncryptionWithKeyDTO, "plainText">) => {
// akhilmhdh: as more encryption are added do a check here on kmsDoc.encryptionAlgorithm
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
const encryptedPlainTextBlob = cipher.encrypt(plainText, key);
// Buffer#1 encrypted text + Buffer#2 version number
@@ -184,7 +184,7 @@ export const kmsServiceFactory = ({
* This can be even later exposed directly as api for encryption as function
*/
const decryptWithInputKey = async ({ key }: Omit<TDecryptWithKeyDTO, "cipherTextBlob">) => {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return ({ cipherTextBlob: versionedCipherTextBlob }: Pick<TDecryptWithKeyDTO, "cipherTextBlob">) => {
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
@@ -262,7 +262,7 @@ export const kmsServiceFactory = ({
};
const encryptWithRootKey = () => {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return (plainTextBuffer: Buffer) => {
const encryptedBuffer = cipher.encrypt(plainTextBuffer, ROOT_ENCRYPTION_KEY);
@@ -271,7 +271,7 @@ export const kmsServiceFactory = ({
};
const decryptWithRootKey = () => {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return (cipherTextBuffer: Buffer) => {
return cipher.decrypt(cipherTextBuffer, ROOT_ENCRYPTION_KEY);
@@ -290,9 +290,9 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyEncryptDecrypt;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.ENCRYPT_DECRYPT
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.ENCRYPT_DECRYPT
});
if (kmsDoc.externalKms) {
@@ -356,7 +356,7 @@ export const kmsServiceFactory = ({
}
// internal KMS
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const dataCipher = symmetricCipherService(encryptionAlgorithm);
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -385,22 +385,22 @@ export const kmsServiceFactory = ({
});
}
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
return kmsKey;
};
const importKeyMaterial = async (
{ key, algorithm, name, isReserved, projectId, orgId, type }: TImportKeyMaterialDTO,
{ key, algorithm, name, isReserved, projectId, orgId, keyUsage }: TImportKeyMaterialDTO,
tx?: Knex
) => {
// daniel: currently we only support imports for encrypt/decrypt keys
verifyKeyTypeAndAlgorithm(type, algorithm, { forceType: KmsKeyIntent.ENCRYPT_DECRYPT });
verifyKeyTypeAndAlgorithm(keyUsage, algorithm, { forceType: KmsKeyUsage.ENCRYPT_DECRYPT });
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const expectedByteLength = getByteLengthForSymmetricEncryptionAlgorithm(algorithm as SymmetricKeyEncryptDecrypt);
const expectedByteLength = getByteLengthForSymmetricEncryptionAlgorithm(algorithm as SymmetricKeyAlgorithm);
if (key.byteLength !== expectedByteLength) {
throw new BadRequestError({
message: `Invalid key length for ${algorithm}. Expected ${expectedByteLength} bytes but got ${key.byteLength} bytes`
@@ -413,7 +413,7 @@ export const kmsServiceFactory = ({
const kmsDoc = await kmsDAL.create(
{
name: sanitizedName,
type: KmsKeyIntent.ENCRYPT_DECRYPT,
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
orgId,
isReserved,
projectId
@@ -443,13 +443,13 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.SIGN_VERIFY
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.SIGN_VERIFY
});
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
const publicKeyBuffer = signingService(encryptionAlgorithm).getPublicKeyFromPrivateKey(kmsKey);
@@ -469,12 +469,12 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.SIGN_VERIFY
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.SIGN_VERIFY
});
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const { sign } = signingService(encryptionAlgorithm);
return ({ data, signingAlgorithm }: Pick<TSignWithKmsDTO, "data" | "signingAlgorithm">) => {
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -493,12 +493,12 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.SIGN_VERIFY
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.SIGN_VERIFY
});
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const { verify, getPublicKeyFromPrivateKey } = signingService(encryptionAlgorithm);
return ({ data, signature }: Pick<TVerifyWithKmsDTO, "data" | "signature">) => {
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -515,9 +515,9 @@ export const kmsServiceFactory = ({
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
}
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyEncryptDecrypt;
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
forceType: KmsKeyIntent.ENCRYPT_DECRYPT
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyAlgorithm;
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
forceType: KmsKeyUsage.ENCRYPT_DECRYPT
});
if (kmsDoc.externalKms) {
@@ -575,7 +575,7 @@ export const kmsServiceFactory = ({
}
// internal KMS
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const dataCipher = symmetricCipherService(encryptionAlgorithm);
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
@@ -850,7 +850,7 @@ export const kmsServiceFactory = ({
// case 2: root key is encrypted with software encryption
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Software) {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const encryptionKeyBuffer = $getBasicEncryptionKey();
return cipher.decrypt(kmsRootConfig.encryptedRootKey, encryptionKeyBuffer);
@@ -870,7 +870,7 @@ export const kmsServiceFactory = ({
}
if (strategy === RootKeyEncryptionStrategy.Software) {
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
const encryptionKeyBuffer = $getBasicEncryptionKey();
return cipher.encrypt(plainKeyBuffer, encryptionKeyBuffer);
@@ -886,7 +886,7 @@ export const kmsServiceFactory = ({
const createCipherPairWithDataKey = async (encryptionContext: TEncryptWithKmsDataKeyDTO, trx?: Knex) => {
const dataKey = await $getDataKey(encryptionContext, trx);
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
return {
encryptor: ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
+7 -7
View File
@@ -1,7 +1,7 @@
import { Knex } from "knex";
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign/types";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
export enum KmsDataKey {
Organization,
@@ -14,7 +14,7 @@ export enum KmsType {
Internal = "internal"
}
export enum KmsKeyIntent {
export enum KmsKeyUsage {
ENCRYPT_DECRYPT = "encrypt-decrypt",
SIGN_VERIFY = "sign-verify"
}
@@ -31,8 +31,8 @@ export type TEncryptWithKmsDataKeyDTO =
export type TGenerateKMSDTO = {
orgId: string;
projectId?: string;
encryptionAlgorithm?: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
type?: KmsKeyIntent;
encryptionAlgorithm?: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
keyUsage?: KmsKeyUsage;
isReserved?: boolean;
name?: string;
description?: string;
@@ -91,10 +91,10 @@ export type TGetKeyMaterialDTO = {
export type TImportKeyMaterialDTO = {
key: Buffer;
algorithm: SymmetricKeyEncryptDecrypt;
algorithm: SymmetricKeyAlgorithm;
name?: string;
isReserved: boolean;
projectId: string;
orgId: string;
type: KmsKeyIntent;
keyUsage: KmsKeyUsage;
};