암호 키 생성 및 등록시 HSK도 함께 생성 및 등록하도록 변경

This commit is contained in:
static
2025-01-12 21:52:41 +09:00
parent 805d7df182
commit 59c8523e25
15 changed files with 183 additions and 33 deletions

View File

@@ -1,10 +1,11 @@
<script lang="ts">
import { onMount } from "svelte";
import type { Writable } from "svelte/store";
import { goto } from "$app/navigation";
import { TopBar } from "$lib/components";
import { FloatingButton } from "$lib/components/buttons";
import { getDirectoryInfo } from "$lib/modules/file";
import { masterKeyStore, type DirectoryInfo } from "$lib/stores";
import { masterKeyStore, hmacSecretStore, type DirectoryInfo } from "$lib/stores";
import CreateBottomSheet from "./CreateBottomSheet.svelte";
import CreateDirectoryModal from "./CreateDirectoryModal.svelte";
import DeleteDirectoryEntryModal from "./DeleteDirectoryEntryModal.svelte";
@@ -12,6 +13,7 @@
import DirectoryEntryMenuBottomSheet from "./DirectoryEntryMenuBottomSheet.svelte";
import RenameDirectoryEntryModal from "./RenameDirectoryEntryModal.svelte";
import {
requestHmacSecretDownload,
requestDirectoryCreation,
requestFileUpload,
requestDirectoryEntryRename,
@@ -44,11 +46,19 @@
const file = fileInput?.files?.[0];
if (!file) return;
requestFileUpload(file, data.id, $masterKeyStore?.get(1)!).then(() => {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
});
requestFileUpload(file, data.id, $masterKeyStore?.get(1)!, $hmacSecretStore?.get(1)!).then(
() => {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
},
);
};
onMount(async () => {
if (!$hmacSecretStore && !(await requestHmacSecretDownload($masterKeyStore?.get(1)?.key!))) {
throw new Error("Failed to download hmac secrets");
}
});
$effect(() => {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
});

View File

@@ -1,12 +1,22 @@
import { callPostApi } from "$lib/hooks";
import { generateDataKey, wrapDataKey, encryptData, encryptString } from "$lib/modules/crypto";
import { callGetApi, callPostApi } from "$lib/hooks";
import { storeHmacSecrets } from "$lib/indexedDB";
import {
encodeToBase64,
generateDataKey,
wrapDataKey,
unwrapHmacSecret,
encryptData,
encryptString,
signMessageHmac,
} from "$lib/modules/crypto";
import type {
DirectoryRenameRequest,
DirectoryCreateRequest,
FileRenameRequest,
FileUploadRequest,
HmacSecretListResponse,
} from "$lib/server/schemas";
import type { MasterKey } from "$lib/stores";
import { hmacSecretStore, type MasterKey, type HmacSecret } from "$lib/stores";
export interface SelectedDirectoryEntry {
type: "directory" | "file";
@@ -16,6 +26,26 @@ export interface SelectedDirectoryEntry {
name: string;
}
export const requestHmacSecretDownload = async (masterKey: CryptoKey) => {
// TODO: MEK rotation
const res = await callGetApi("/api/hsk/list");
if (!res.ok) return false;
const { hsks: hmacSecretsWrapped }: HmacSecretListResponse = await res.json();
const hmacSecrets = await Promise.all(
hmacSecretsWrapped.map(async ({ version, state, hsk: hmacSecretWrapped }) => {
const { hmacSecret } = await unwrapHmacSecret(hmacSecretWrapped, masterKey);
return { version, state, secret: hmacSecret };
}),
);
await storeHmacSecrets(hmacSecrets);
hmacSecretStore.set(new Map(hmacSecrets.map((hmacSecret) => [hmacSecret.version, hmacSecret])));
return true;
};
export const requestDirectoryCreation = async (
name: string,
parentId: "root" | number,
@@ -37,11 +67,15 @@ export const requestFileUpload = async (
file: File,
parentId: "root" | number,
masterKey: MasterKey,
hmacSecret: HmacSecret,
) => {
const { dataKey, dataKeyVersion } = await generateDataKey();
const fileEncrypted = await encryptData(await file.arrayBuffer(), dataKey);
const nameEncrypted = await encryptString(file.name, dataKey);
const fileBuffer = await file.arrayBuffer();
const fileSigned = await signMessageHmac(fileBuffer, hmacSecret.secret);
const fileEncrypted = await encryptData(fileBuffer, dataKey);
const form = new FormData();
form.set(
"metadata",
@@ -50,6 +84,8 @@ export const requestFileUpload = async (
mekVersion: masterKey.version,
dek: await wrapDataKey(dataKey, masterKey.key),
dekVersion: dataKeyVersion.toISOString(),
hskVersion: hmacSecret.version,
contentHmac: encodeToBase64(fileSigned),
contentType: file.type,
contentIv: fileEncrypted.iv,
name: nameEncrypted.ciphertext,