mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-15 22:38:47 +00:00
프론트엔드 암호 모듈 리팩토링
This commit is contained in:
159
src/lib/modules/crypto/rsa.ts
Normal file
159
src/lib/modules/crypto/rsa.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { encodeToBase64, decodeFromBase64 } from "./util";
|
||||
|
||||
export const generateEncryptionKeyPair = async () => {
|
||||
const keyPair = await window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 4096,
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
hash: "SHA-256",
|
||||
} satisfies RsaHashedKeyGenParams,
|
||||
true,
|
||||
["encrypt", "decrypt", "wrapKey", "unwrapKey"],
|
||||
);
|
||||
return {
|
||||
encryptKey: keyPair.publicKey,
|
||||
decryptKey: keyPair.privateKey,
|
||||
};
|
||||
};
|
||||
|
||||
export const generateSigningKeyPair = async () => {
|
||||
const keyPair = await window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: "RSA-PSS",
|
||||
modulusLength: 4096,
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
hash: "SHA-256",
|
||||
} satisfies RsaHashedKeyGenParams,
|
||||
true,
|
||||
["sign", "verify"],
|
||||
);
|
||||
return {
|
||||
signKey: keyPair.privateKey,
|
||||
verifyKey: keyPair.publicKey,
|
||||
};
|
||||
};
|
||||
|
||||
export const exportRSAKey = async (key: CryptoKey) => {
|
||||
const format = key.type === "public" ? ("spki" as const) : ("pkcs8" as const);
|
||||
return {
|
||||
key: await window.crypto.subtle.exportKey(format, key),
|
||||
format,
|
||||
};
|
||||
};
|
||||
|
||||
export const exportRSAKeyToBase64 = async (key: CryptoKey) => {
|
||||
return encodeToBase64((await exportRSAKey(key)).key);
|
||||
};
|
||||
|
||||
export const makeRSAKeyNonextractable = async (key: CryptoKey) => {
|
||||
const { key: exportedKey, format } = await exportRSAKey(key);
|
||||
return await window.crypto.subtle.importKey(
|
||||
format,
|
||||
exportedKey,
|
||||
key.algorithm,
|
||||
false,
|
||||
key.usages,
|
||||
);
|
||||
};
|
||||
|
||||
export const decryptChallenge = async (challenge: string, decryptKey: CryptoKey) => {
|
||||
return await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
} satisfies RsaOaepParams,
|
||||
decryptKey,
|
||||
decodeFromBase64(challenge),
|
||||
);
|
||||
};
|
||||
|
||||
export const wrapMasterKey = async (masterKey: CryptoKey, encryptKey: CryptoKey) => {
|
||||
return encodeToBase64(
|
||||
await window.crypto.subtle.wrapKey("raw", masterKey, encryptKey, {
|
||||
name: "RSA-OAEP",
|
||||
} satisfies RsaOaepParams),
|
||||
);
|
||||
};
|
||||
|
||||
export const unwrapMasterKey = async (
|
||||
masterKeyWrapped: string,
|
||||
decryptKey: CryptoKey,
|
||||
extractable = false,
|
||||
) => {
|
||||
return {
|
||||
masterKey: await window.crypto.subtle.unwrapKey(
|
||||
"raw",
|
||||
decodeFromBase64(masterKeyWrapped),
|
||||
decryptKey,
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
} satisfies RsaOaepParams,
|
||||
"AES-KW",
|
||||
extractable,
|
||||
["wrapKey", "unwrapKey"],
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
export const signMessage = async (message: BufferSource, signKey: CryptoKey) => {
|
||||
return await window.crypto.subtle.sign(
|
||||
{
|
||||
name: "RSA-PSS",
|
||||
saltLength: 32, // SHA-256
|
||||
} satisfies RsaPssParams,
|
||||
signKey,
|
||||
message,
|
||||
);
|
||||
};
|
||||
|
||||
export const verifySignature = async (
|
||||
message: BufferSource,
|
||||
signature: BufferSource,
|
||||
verifyKey: CryptoKey,
|
||||
) => {
|
||||
return await window.crypto.subtle.verify(
|
||||
{
|
||||
name: "RSA-PSS",
|
||||
saltLength: 32, // SHA-256
|
||||
} satisfies RsaPssParams,
|
||||
verifyKey,
|
||||
signature,
|
||||
message,
|
||||
);
|
||||
};
|
||||
|
||||
export const signRequestBody = async <T>(requestBody: T, signKey: CryptoKey) => {
|
||||
const dataBuffer = new TextEncoder().encode(JSON.stringify(requestBody));
|
||||
const signature = await signMessage(dataBuffer, signKey);
|
||||
return JSON.stringify({
|
||||
data: requestBody,
|
||||
signature: encodeToBase64(signature),
|
||||
});
|
||||
};
|
||||
|
||||
export const signMasterKeyWrapped = async (
|
||||
masterKeyVersion: number,
|
||||
masterKeyWrapped: string,
|
||||
signKey: CryptoKey,
|
||||
) => {
|
||||
const serialized = JSON.stringify({
|
||||
version: masterKeyVersion,
|
||||
key: masterKeyWrapped,
|
||||
});
|
||||
const serializedBuffer = new TextEncoder().encode(serialized);
|
||||
return encodeToBase64(await signMessage(serializedBuffer, signKey));
|
||||
};
|
||||
|
||||
export const verifyMasterKeyWrapped = async (
|
||||
masterKeyVersion: number,
|
||||
masterKeyWrapped: string,
|
||||
masterKeyWrappedSig: string,
|
||||
verifyKey: CryptoKey,
|
||||
) => {
|
||||
const serialized = JSON.stringify({
|
||||
version: masterKeyVersion,
|
||||
key: masterKeyWrapped,
|
||||
});
|
||||
const serializedBuffer = new TextEncoder().encode(serialized);
|
||||
return await verifySignature(serializedBuffer, decodeFromBase64(masterKeyWrappedSig), verifyKey);
|
||||
};
|
||||
Reference in New Issue
Block a user