fileverse/docs/crypto-comparison.md

131 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Crypto Comparison: @fileverse/crypto vs rSpace DocCrypto vs MIT Primitives
## Overview
Three options for the encryption layer:
1. **Keep DocCrypto** — rSpace's existing AES-256-GCM + HKDF implementation
2. **Adopt @fileverse/crypto** — Drop-in AGPL library with ECIES, NaCl, Argon2id
3. **Build from MIT primitives** — Same capabilities as Fileverse but without AGPL
## Primitive-Level Comparison
### Symmetric Encryption
| | DocCrypto | @fileverse/crypto | MIT Build |
|--|-----------|-------------------|-----------|
| Algorithm | AES-256-GCM | XSalsa20-Poly1305 (NaCl SecretBox) | Either |
| Implementation | Web Crypto API | TweetNaCl.js | Web Crypto or TweetNaCl |
| Key size | 256 bits | 256 bits | 256 bits |
| Nonce | 96 bits (random) | 192 bits (random) | Depends on choice |
| Auth tag | 128 bits | 128 bits (Poly1305) | Depends on choice |
| Bundle size | 0 (native) | ~7KB (tweetnacl) | 07KB |
| Performance | Fastest (hardware) | Fast (pure JS) | Fastest if Web Crypto |
**Analysis:** AES-256-GCM via Web Crypto is faster (hardware acceleration) and adds 0 bundle size. NaCl SecretBox is simpler to use correctly (larger nonce = less collision risk). For rStack, Web Crypto AES-256-GCM is the better choice — it's already battle-tested in DocCrypto.
### Asymmetric Encryption (Gap in DocCrypto)
| | DocCrypto | @fileverse/crypto | MIT Build |
|--|-----------|-------------------|-----------|
| ECIES | Not implemented | ✅ (secp256k1) | Noble curves |
| RSA | Not implemented | ✅ (envelope) | Web Crypto |
| Key exchange | Not implemented | ECDH shared secret | Noble/StableLib x25519 |
**Analysis:** This is the main gap. DocCrypto only does symmetric encryption — it can't share encryption keys between users without a trusted server. ECIES allows encrypting a document key so only a specific collaborator's private key can decrypt it.
### Key Derivation
| | DocCrypto | @fileverse/crypto | MIT Build |
|--|-----------|-------------------|-----------|
| HKDF | ✅ (Web Crypto) | ✅ (StableLib) | Web Crypto |
| Argon2id | Not implemented | ✅ (argon2-browser WASM) | argon2-browser |
| Key hierarchy | Master → Space → Doc | Flat | Custom |
**Analysis:** DocCrypto's key hierarchy is more sophisticated. Fileverse derives keys per-operation. For rStack, keep DocCrypto's hierarchy and add Argon2id for password-protected sharing.
## Recommendation
### Extend DocCrypto with MIT Primitives
```typescript
// Additions to rspace-online/shared/local-first/crypto.ts
import { x25519 } from '@noble/curves/ed25519'
import { hkdf } from '@noble/hashes/hkdf'
import { sha256 } from '@noble/hashes/sha256'
import argon2 from 'argon2-browser'
class DocCrypto {
// ... existing AES-256-GCM + HKDF methods ...
// NEW: Key exchange for multi-user collaboration
static async deriveSharedSecret(
myPrivateKey: Uint8Array,
theirPublicKey: Uint8Array
): Promise<CryptoKey> {
const shared = x25519.getSharedSecret(myPrivateKey, theirPublicKey)
return this.importKey(shared)
}
// NEW: Encrypt document key for a specific collaborator
static async encryptKeyForUser(
docKey: Uint8Array,
recipientPublicKey: Uint8Array,
senderPrivateKey: Uint8Array
): Promise<Uint8Array> {
const sharedSecret = x25519.getSharedSecret(senderPrivateKey, recipientPublicKey)
const wrappingKey = hkdf(sha256, sharedSecret, null, 'rstack-key-wrap', 32)
// Encrypt docKey with wrappingKey using existing AES-256-GCM
return this.encrypt(wrappingKey, docKey)
}
// NEW: Password-protected note sharing
static async deriveKeyFromPassword(
password: string,
salt: Uint8Array
): Promise<CryptoKey> {
const result = await argon2.hash({
pass: password,
salt: salt,
type: argon2.ArgonType.Argon2id,
hashLen: 32,
time: 3,
mem: 65536,
parallelism: 1,
})
return this.importKey(result.hash)
}
}
```
### Dependencies (All MIT)
```json
{
"@noble/curves": "^1.4.0",
"@noble/hashes": "^1.4.0",
"argon2-browser": "^1.18.0"
}
```
### Bundle Size Impact
| Package | Size (min+gzip) |
|---------|----------------|
| @noble/curves (x25519 only) | ~8KB |
| @noble/hashes (sha256+hkdf) | ~4KB |
| argon2-browser (WASM) | ~30KB |
| **Total** | **~42KB** |
vs `@fileverse/crypto` full package: ~45KB (similar, but with AGPL)
## Interoperability
If we build from the same MIT primitives Fileverse uses, we maintain the option to:
- Decrypt content encrypted by Fileverse apps
- Share encrypted documents with Fileverse users
- Participate in Fileverse collaboration rooms
The key is using compatible curve parameters (secp256k1 or x25519) and matching the encryption format (nonce || ciphertext || tag).