Création d'un composable pour la gestion de la crypto, mise en place de l'initialisation de la première liste et sauvegarde de celle-ci. TODO NEXT : Récupération de la liste en la déchiffrant, mise en place d'une masterKey dérivée du mot de passe pour les utilisateurs non google, basculement vers la page des listes après connexion google etc.

This commit is contained in:
2026-03-15 08:15:42 +01:00
parent d9d84634e8
commit 5d582461e2
10 changed files with 562 additions and 29 deletions

199
app/composables/crypto.ts Normal file
View File

@@ -0,0 +1,199 @@
import sodium from "libsodium-wrappers"
export type KeyPair = {
publicKey: Uint8Array
privateKey: Uint8Array
}
export type EncryptedPayload = {
nonce: Uint8Array
cipher: Uint8Array
}
export type EncryptedPrivateKey = {
nonce: Uint8Array
cipher: Uint8Array
salt: Uint8Array
}
export const useCryptoStore = () => {
let ready = false
const init = async (): Promise<void> => {
if (!ready) {
await sodium.ready
ready = true
}
}
/**
* USER KEY PAIR
*/
const generateUserKeyPair = (): KeyPair => {
const pair = sodium.crypto_box_keypair()
return {
publicKey: pair.publicKey,
privateKey: pair.privateKey
}
}
/**
* MASTER KEY
*/
const generateMasterKey = (): Uint8Array => {
return sodium.randombytes_buf(
sodium.crypto_secretbox_KEYBYTES
)
}
/**
* ENCRYPT PRIVATE KEY
*/
const encryptPrivateKey = (
privateKey: Uint8Array,
masterKey: Uint8Array
): EncryptedPayload => {
const nonce = sodium.randombytes_buf(
sodium.crypto_secretbox_NONCEBYTES
)
const cipher = sodium.crypto_secretbox_easy(
privateKey,
nonce,
masterKey
)
return { nonce, cipher }
}
/**
* DECRYPT PRIVATE KEY
*/
const decryptPrivateKey = (
encrypted: EncryptedPayload,
masterKey: Uint8Array
): Uint8Array => {
return sodium.crypto_secretbox_open_easy(
encrypted.cipher,
encrypted.nonce,
masterKey
)
}
/**
* LIST KEY
*/
const generateListKey = (): Uint8Array => {
return sodium.randombytes_buf(
sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES
)
}
/**
* ENCRYPT LIST DATA
*/
const encryptList = (
data: string,
listKey: Uint8Array
): EncryptedPayload => {
const nonce = sodium.randombytes_buf(
sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
)
const cipher = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
sodium.from_string(data),
null,
null,
nonce,
listKey
)
return { nonce, cipher }
}
/**
* DECRYPT LIST DATA
*/
const decryptList = (
encrypted: EncryptedPayload,
listKey: Uint8Array
): string => {
const decrypted = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
null,
encrypted.cipher,
null,
encrypted.nonce,
listKey
)
return sodium.to_string(decrypted)
}
/**
* ENCRYPT LIST KEY FOR USER
*/
const encryptListKeyForUser = (
listKey: Uint8Array,
recipientPublicKey: Uint8Array,
senderPrivateKey: Uint8Array
): EncryptedPayload => {
const nonce = sodium.randombytes_buf(
sodium.crypto_box_NONCEBYTES
)
const cipher = sodium.crypto_box_easy(
listKey,
nonce,
recipientPublicKey,
senderPrivateKey
)
return { nonce, cipher }
}
/**
* DECRYPT LIST KEY
*/
const decryptListKey = (
encrypted: EncryptedPayload,
senderPublicKey: Uint8Array,
recipientPrivateKey: Uint8Array
): Uint8Array => {
return sodium.crypto_box_open_easy(
encrypted.cipher,
encrypted.nonce,
senderPublicKey,
recipientPrivateKey
)
}
return {
init,
generateUserKeyPair,
generateMasterKey,
encryptPrivateKey,
decryptPrivateKey,
generateListKey,
encryptList,
decryptList,
encryptListKeyForUser,
decryptListKey
}
}