Files
ChatApp/packages/shared/src/crypto/sessionKeys.ts
T
byGalax 75618637e2
Release desktop app / build (, windows-latest) (push) Has been cancelled
Release desktop app / build (--target universal-apple-darwin --bundles app,updater, macos-14) (push) Has been cancelled
feat(crypto): sender-key per-conversation multi-device E2EE
2026-04-19 19:27:24 +02:00

59 lines
1.8 KiB
TypeScript

import { getCryptoBackend } from './backend.js';
import { decryptFrom, encryptFor, type EncryptedEnvelope } from './box.js';
// Sender-Key (Signal-style) helpers — one symmetric XSalsa20-Poly1305 key per
// conversation, wrapped with `crypto_box` for each recipient device's pubkey.
//
// Flow:
// - generateConvKey() produces 32 random bytes
// - wrapConvKeyForRecipient() encrypts the conv-key with sender's private key
// and recipient's pubkey -> stored in `conversation_keys` table
// - unwrapConvKey() reverses it on the receiving side
// - encryptWithConvKey()/decryptWithConvKey() do the message-payload work
export function generateConvKey(): Uint8Array {
const backend = getCryptoBackend();
return backend.randomBytes(backend.secretboxKeyLength);
}
export async function wrapConvKeyForRecipient(
convKey: Uint8Array,
recipientPublicKey: Uint8Array,
senderPrivateKey: Uint8Array,
): Promise<EncryptedEnvelope> {
return encryptFor(convKey, recipientPublicKey, senderPrivateKey);
}
export async function unwrapConvKey(
encryptedKey: Uint8Array,
nonce: Uint8Array,
senderPublicKey: Uint8Array,
recipientPrivateKey: Uint8Array,
): Promise<Uint8Array> {
return decryptFrom(encryptedKey, nonce, senderPublicKey, recipientPrivateKey);
}
export interface ConvCipher {
ciphertext: Uint8Array;
nonce: Uint8Array;
}
export function encryptWithConvKey(
plaintext: Uint8Array,
convKey: Uint8Array,
): ConvCipher {
const backend = getCryptoBackend();
const nonce = backend.randomBytes(backend.secretboxNonceLength);
const ciphertext = backend.secretbox(plaintext, nonce, convKey);
return { ciphertext, nonce };
}
export function decryptWithConvKey(
ciphertext: Uint8Array,
nonce: Uint8Array,
convKey: Uint8Array,
): Uint8Array {
const backend = getCryptoBackend();
return backend.secretboxOpen(ciphertext, nonce, convKey);
}