Panoramica della Sicurezza
ZeroKeep implementa un'architettura di sicurezza multi-livello basata su standard crittografici militari e best practices dell'industria. Il sistema è progettato per garantire la massima privacy degli utenti attraverso crittografia end-to-end e un modello zero-knowledge che impedisce qualsiasi accesso non autorizzato ai dati, incluso lo stesso fornitore del servizio.
Crittografia Client-Side
Tutti i file vengono crittografati nel browser dell'utente prima della trasmissione. Il server riceve solo ciphertext incomprensibile.
Zero-Knowledge Server
Il server non ha mai accesso alle chiavi di decifratura. Anche in caso di compromissione, i dati rimangono protetti.
Authenticated Encryption
AES-256-GCM garantisce sia confidenzialità che autenticità dei dati, prevenendo manipolazioni.
Forward Secrecy
Ogni file utilizza una chiave unica generata casualmente. Compromettere una chiave non espone altri file.
Audit Trail Completo
Ogni operazione viene registrata con timestamp crittografico per garantire tracciabilità e non-ripudio.
Password Security
PBKDF2 con 100.000 iterazioni e bcrypt server-side garantiscono resistenza a attacchi brute-force.
ZeroKeep utilizza solo algoritmi crittografici standardizzati e verificati dalla comunità crittografica internazionale. Nessun algoritmo proprietario o offuscato viene utilizzato. Il codice sorgente client è ispezionabile per verificare l'implementazione corretta degli standard di sicurezza.
Architettura Zero-Knowledge
Il concetto di "Zero-Knowledge" significa che il server non ha mai accesso ai dati in chiaro né alle chiavi di decifratura. Questa architettura garantisce che anche in caso di compromissione completa del server, i dati degli utenti rimangono completamente protetti e inaccessibili.
Principi Fondamentali
Crittografia Lato Client
Principio: Tutta la crittografia avviene nel browser dell'utente utilizzando Web Crypto API nativa.
Implementazione:
- Generazione chiavi casuali (CSPRNG)
- Cifratura AES-256-GCM prima dell'upload
- Decifratura solo dopo il download
- Chiavi mai trasmesse al server
Derivazione Chiavi Sicura
Principio: Le chiavi master sono derivate dalle password utente utilizzando funzioni crittografiche robuste.
Implementazione:
- PBKDF2 con 100.000 iterazioni
- Salt unico per utente (256-bit)
- SHA-256 come funzione hash
- Argon2id sul server per ulteriore protezione
Metadata Crittografati
Principio: Anche i metadati dei file (nome, dimensione, tipo) sono crittografati.
Implementazione:
- Metadata serializzati in JSON
- Crittografati con chiave master utente
- Server vede solo hash e dimensione ciphertext
- Nomi file obfuscati con hash
Separazione Chiavi
Principio: Ogni tipo di dato utilizza chiavi diverse e indipendenti.
Implementazione:
- DEK (Data Encryption Key) per file
- KEK (Key Encryption Key) per wrapping
- Master Key per metadata
- RSA Keys per condivisione E2EE
Il server ZeroKeep non può:
- Vedere il contenuto dei file
- Leggere i nomi dei file
- Conoscere il tipo di file caricati
- Accedere alle password degli utenti
- Decifrare le comunicazioni E2EE
A causa dell'architettura zero-knowledge, se un utente perde la propria password, non esiste modo di recuperare i file. ZeroKeep non può reimpostare la password o fornire accesso alternativo. È fondamentale che gli utenti conservino le proprie password in modo sicuro.
Standard Crittografici Implementati
ZeroKeep utilizza esclusivamente algoritmi crittografici standardizzati da NIST e raccomandati da ENISA, implementati attraverso le API native del browser (Web Crypto API) per garantire sicurezza e prestazioni ottimali.
Algoritmi e Parametri
AES-256-GCM
Cifratura Simmetrica AEAD
Utilizzo: Crittografia file e dati sensibili
Algorithm: AES-GCM
Key Length: 256-bit (32 bytes)
IV Length: 96-bit (12 bytes)
Tag Length: 128-bit (16 bytes)
Mode: Galois/Counter Mode (AEAD)
// Web Crypto API Implementation
const key = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: iv },
key,
plaintext
);
Proprietà:
- Confidenzialità (encryption)
- Autenticità (authentication tag)
- Integrità (tamper detection)
- Prestazioni elevate (hardware-accelerated)
RSA-4096-OAEP
Crittografia Asimmetrica
Utilizzo: Condivisione E2EE tra utenti
Algorithm: RSA-OAEP
Modulus Length: 4096-bit
Hash Function: SHA-256
MGF: MGF1 with SHA-256
Public Exponent: 65537 (0x10001)
// Key Generation
const keyPair = await crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
["encrypt", "decrypt"]
);
// Encrypt DEK for recipient
const encryptedDEK = await crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
recipientPublicKey,
dek
);
Proprietà:
- Scambio chiavi sicuro
- Resistente a quantum (fino al 2030)
- Non-ripudio crittografico
- Protezione padding (OAEP)
PBKDF2-SHA256
Derivazione Chiavi Password
Utilizzo: Derivazione master key da password
Algorithm: PBKDF2
Hash Function: SHA-256
Iterations: 100,000
Salt Length: 256-bit (32 bytes)
Output Length: 256-bit (32 bytes)
// Key Derivation
const masterKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 100000,
hash: "SHA-256"
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt", "wrapKey", "unwrapKey"]
);
Proprietà:
- Resistenza a brute-force
- Resistenza a rainbow tables
- Slow by design (computazionalmente costoso)
- Salt unico per utente
AES-KW (Key Wrap)
Wrapping Chiavi Simmetriche
Utilizzo: Protezione e storage sicuro delle DEK
Algorithm: AES-KW
Key Length: 256-bit
Standard: RFC 3394
// Wrap DEK with Master Key
const wrappedDEK = await crypto.subtle.wrapKey(
"raw",
dekKey,
masterKey,
{ name: "AES-KW" }
);
// Unwrap DEK
const unwrappedDEK = await crypto.subtle.unwrapKey(
"raw",
wrappedDEK,
masterKey,
{ name: "AES-KW" },
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
Proprietà:
- Protezione chiavi simmetriche
- Integrità chiave wrappata
- Dimensione output compatta
- Verifica autenticità al unwrap
Tutti gli algoritmi crittografici implementati sono conformi agli standard internazionali:
- NIST (National Institute of Standards and Technology)
- FIPS 140-2/140-3 (Federal Information Processing Standards)
- ENISA (European Union Agency for Cybersecurity)
- RFC IETF (Internet Engineering Task Force)
Modello di Minaccia e Difese
ZeroKeep è progettato per resistere a molteplici vettori di attacco. Di seguito l'analisi completa delle minacce considerate e delle relative contromisure implementate.
Vettori di Attacco Analizzati
Compromissione Server
RISCHIO: ALTO | IMPATTO: ZERO
Scenario: Attaccante ottiene accesso completo al server (root access, database, storage S3)
Cosa può ottenere:
- File cifrati (inutilizzabili senza chiavi)
- DEK wrappate (protette da master key utente)
- Metadata cifrati (illeggibili)
- Hash password (bcrypt con salt)
- NON può decifrare nulla
Difese:
Man-in-the-Middle (MITM)
RISCHIO: MEDIO | IMPATTO: BASSO
Scenario: Attaccante intercetta comunicazioni tra client e server
Cosa può ottenere:
- Ciphertext in transito (inutilizzabile)
- Wrapped DEK (ancora cifrata)
- NON può vedere file in chiaro
- NON può ottenere password
Difese:
Brute-Force Password
RISCHIO: BASSO | IMPATTO: UTENTE-SPECIFICO
Scenario: Attaccante tenta di indovinare password utente
Difese Multi-Livello:
- Client: PBKDF2 100k iterations (rallenta attacchi offline)
- Server: bcrypt (rallenta attacchi online)
- Network: Rate limiting (5 tentativi/minuto)
- Account: Lockout temporaneo dopo N tentativi
Tempo stimato per crack:
Password 12 caratteri (lettere+numeri+simboli): - Entropia: ~75 bit - PBKDF2 100k: ~10ms per tentativo - Tempo crack: > 2^75 * 10ms = ~1.2 * 10^15 anni Con GPU cluster (1 trilione hash/sec): - Ancora > 10^7 anni per password forte
Phishing & Social Engineering
RISCHIO: MEDIO | IMPATTO: UTENTE-SPECIFICO
Scenario: Attaccante cerca di ottenere credenziali utente via phishing
Difese:
- Domain verification chiara nell'UI
- 2FA opzionale (TOTP)
- Email alerts per login da nuovo dispositivo
- Session management con device fingerprinting
- User education e security awareness
Responsabilità Utente: Anche con architettura zero-knowledge, gli utenti devono proteggere le proprie password. Raccomandiamo l'uso di password manager e autenticazione a due fattori.
Vulnerabilità Implementazione
RISCHIO: BASSO | IMPATTO: VARIABILE
Scenario: Bug nel codice client/server espone vulnerabilità
Difese:
- Input Validation: Sanitizzazione completa lato server
- SQL Injection: Prepared statements (Go database/sql)
- XSS: Content Security Policy + output escaping
- CSRF: Token anti-CSRF per tutte le operazioni sensibili
- Path Traversal: Validazione strict dei percorsi file
- Code Audits: Review regolari del codice
- Dependency Updates: Monitoring vulnerabilità CVE
Quantum Computing
RISCHIO: FUTURO | IMPATTO: ALTO (post-2030)
Scenario: Computer quantistici rendono RSA-4096 vulnerabile
Status Attuale:
- RSA-4096 sicuro fino a ~2030-2035
- AES-256 resistente anche a quantum (Grover's algorithm richiede 2^128 operazioni)
- SHA-256 resistente a quantum
Piano Mitigazione:
- Monitoring sviluppi NIST post-quantum cryptography
- Migrazione futura a algoritmi quantum-resistant (es. CRYSTALS-Kyber)
- Architettura modulare permette aggiornamento algoritmi
ZeroKeep implementa una strategia di difesa in profondità (defense in depth) con multipli livelli di sicurezza. Anche se un singolo meccanismo venisse compromesso, gli altri livelli continuano a proteggere i dati degli utenti.
Flusso 1: Registrazione Utente
Il processo di registrazione inizializza l'architettura zero-knowledge generando tutte le chiavi crittografiche necessarie sul client.
La password non viene mai inviata al server. Solo l'hash SHA-256 viene trasmesso, e il server applica un ulteriore bcrypt. Questo sistema di double hashing offre protezione anche se il database venisse compromesso.
Flusso 2: Upload File Sicuro
Ogni file viene crittografato con una chiave unica (DEK) generata casualmente, garantendo forward secrecy e isolamento tra file.
Cosa il Server NON Può Fare
Vedere Contenuto File
Il server riceve solo il ciphertext cifrato con AES-256-GCM. Senza la DEK (che è wrappata con la master key dell'utente), il file è completamente illeggibile.
Conoscere Nome File
I metadata (nome, tipo, dimensione) sono crittografati con la master key. Il server vede solo un blob cifrato e uno hash.
Ottenere la DEK
La DEK è wrappata con AES-KW usando la master key dell'utente, derivata dalla password. Impossibile unwrappare senza password.
Correlare File tra Utenti
Ogni utente ha tenant isolato, nomi file hashati, DEK uniche. Impossibile correlare file anche se identici.
Flow 3: Download & Decryption
Il server invia solo dati cifrati. La decryption avviene interamente nel browser con le chiavi locali dell'utente.
Server Non Vede il File
Il server trasmette solo blob cifrato. Impossibile leggere contenuto senza password utente.
Derivazione KEK Client-Side
PBKDF2 eseguito nel browser. La password non lascia mai il client.
Verifica Integrità con GCM
Il tag GCM garantisce che il file non sia stato alterato durante storage o trasmissione.
Flow 6: RSA Key Generation & Exchange
Ogni utente genera una coppia RSA-4096 durante la registrazione. La chiave privata è cifrata con KEK e mai trasmessa in chiaro.
4096-bit Strength
RSA-4096 garantisce sicurezza anche contro attacchi futuri. Resistente a quantum computing fino a ~2030.
Private Key Mai in Chiaro
La chiave privata è sempre cifrata con KEK (derivato da password). Server memorizza solo versione cifrata.
Public Key Distribuibile
La chiave pubblica è accessibile a tutti gli utenti per permettere condivisione E2EE.
In-Memory Session
Dopo login, private key decrypted è tenuta in memoria (sessionStorage/variable). Scompare al logout.
API Reference Completo
Documentazione completa di tutti gli endpoint API di ZeroKeep, con esempi di richieste e risposte.
Authentication
/api/register
Registra un nuovo utente con crittografia E2EE.
Request Body:
{
"email": "user@example.com",
"password_hash": "pbkdf2_sha256_hash", // PBKDF2 client-side
"salt": "base64_encoded_salt",
"rsa_public_key": "-----BEGIN PUBLIC KEY-----...",
"rsa_encrypted_private_key": "base64_encrypted_private_key",
"rsa_private_key_iv": "base64_iv"
}
Response (201 Created):
{
"message": "User registered successfully",
"user_id": "uuid-v4",
"email": "user@example.com"
}
Errors:
400 Bad Request: "Email already exists"
400 Bad Request: "Invalid RSA public key format"
500 Internal Server Error
/api/login
Autentica utente e restituisce JWT token.
Request Body:
{
"email": "user@example.com",
"password_hash": "pbkdf2_sha256_hash"
}
Response (200 OK):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user_id": "uuid-v4",
"email": "user@example.com",
"rsa_encrypted_private_key": "base64_encrypted",
"rsa_private_key_iv": "base64_iv"
}
Errors:
401 Unauthorized: "Invalid credentials"
404 Not Found: "User not found"
/api/logout
Invalida il token JWT corrente.
Headers:
Authorization: Bearer {jwt_token}
Response (200 OK):
{
"message": "Logged out successfully"
}
File Management
/api/files/upload
Carica un file cifrato con metadata E2EE.
Headers:
Authorization: Bearer {jwt_token}
Content-Type: application/json
Request Body:
{
"encrypted_file": "base64_encrypted_blob",
"encrypted_metadata": {
"encrypted_filename": "base64_encrypted_name",
"encrypted_filetype": "base64_encrypted_type",
"file_size_encrypted": 123456, // Size of encrypted blob
"iv": "base64_iv",
"tag": "base64_gcm_tag"
},
"encrypted_dek_with_kek": "base64_wrapped_dek",
"file_hash": "sha256_hex_digest"
}
Response (201 Created):
{
"file_id": "uuid-v4",
"s3_path": "tenant_id/file_id.enc",
"uploaded_at": "2025-12-23T10:30:00Z"
}
Errors:
400 Bad Request: "Missing encrypted metadata"
401 Unauthorized: "Invalid or expired token"
413 Payload Too Large: "File exceeds 5GB limit"
507 Insufficient Storage: "Storage quota exceeded"
/api/files
Elenca tutti i file dell'utente.
Headers:
Authorization: Bearer {jwt_token}
Query Parameters:
?folder_id=uuid // Filter by folder (optional)
&limit=50 // Pagination limit (default: 100)
&offset=0 // Pagination offset (default: 0)
&sort_by=created_at // Sort field (created_at, size, name)
&order=desc // Sort order (asc, desc)
Response (200 OK):
{
"files": [
{
"file_id": "uuid-v4",
"encrypted_metadata": {
"encrypted_filename": "base64...",
"encrypted_filetype": "base64...",
"file_size_encrypted": 123456,
"iv": "base64...",
"tag": "base64..."
},
"encrypted_dek_with_kek": "base64...",
"s3_path": "tenant_id/file_id.enc",
"created_at": "2025-12-23T10:30:00Z",
"is_favorite": false
}
],
"total": 42,
"limit": 50,
"offset": 0
}
/api/files/:id/download
Scarica un file cifrato.
Headers:
Authorization: Bearer {jwt_token}
Response (200 OK):
{
"encrypted_file": "base64_blob",
"encrypted_metadata": { /* ... */ },
"encrypted_dek_with_kek": "base64...",
"file_hash": "sha256..."
}
Errors:
404 Not Found: "File not found"
403 Forbidden: "Access denied"
/api/files/:id
Elimina un file (da DB e S3).
Headers:
Authorization: Bearer {jwt_token}
Response (200 OK):
{
"message": "File deleted successfully",
"file_id": "uuid-v4"
}
Errors:
404 Not Found: "File not found"
403 Forbidden: "Cannot delete shared file"
Sharing (Public & E2EE)
/api/shares/public
Crea un link di condivisione pubblico con password.
Request Body:
{
"file_id": "uuid-v4",
"encrypted_dek_share": "base64_dek_wrapped_with_share_password",
"share_salt": "base64_salt_for_share_password",
"expiration_days": 7,
"max_downloads": 10
}
Response (201 Created):
{
"share_id": "uuid-v4",
"share_url": "https://onionedcloud.onion/share/uuid-v4",
"expires_at": "2025-12-30T10:30:00Z"
}
/api/shares/:id
Accesso a file condiviso (richiede password).
Query Parameters:
?password_hash=pbkdf2_hash // Hash della share password
Response (200 OK):
{
"encrypted_file": "base64_blob",
"encrypted_dek_share": "base64...",
"share_salt": "base64...",
"encrypted_metadata": { /* ... */ },
"downloads_remaining": 9
}
Errors:
401 Unauthorized: "Invalid password"
404 Not Found: "Share expired or not found"
429 Too Many Requests: "Max downloads reached"
/api/shares/e2ee
Condividi file E2EE con utente registrato (RSA).
Request Body:
{
"file_id": "uuid-v4",
"recipient_email": "recipient@example.com",
"encrypted_dek_rsa": "base64_dek_encrypted_with_recipient_public_key",
"permissions": "read" // Future: "read", "write", "admin"
}
Response (201 Created):
{
"share_id": "uuid-v4",
"recipient_id": "uuid-v4",
"created_at": "2025-12-23T10:30:00Z"
}
Errors:
404 Not Found: "Recipient not found"
400 Bad Request: "Cannot share with yourself"
403 Forbidden: "File already shared with this user"
/api/shares/received
Elenca file condivisi CON ME (E2EE).
Response (200 OK):
{
"shares": [
{
"share_id": "uuid-v4",
"file_id": "uuid-v4",
"sender_email": "sender@example.com",
"encrypted_dek_rsa": "base64...",
"encrypted_metadata": { /* ... */ },
"shared_at": "2025-12-23T10:30:00Z",
"permissions": "read"
}
]
}
/api/shares/:id
Revoca una condivisione (solo owner).
Response (200 OK):
{
"message": "Share revoked successfully"
}
User & Keys Management
/api/users/:email/public-key
Ottiene la chiave pubblica RSA di un utente (per E2EE sharing).
Response (200 OK):
{
"email": "user@example.com",
"rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhki...\n-----END PUBLIC KEY-----",
"user_id": "uuid-v4"
}
Errors:
404 Not Found: "User not found"
/api/keys/private
Recupera la propria chiave privata cifrata (per decrypt dopo login).
Headers:
Authorization: Bearer {jwt_token}
Response (200 OK):
{
"rsa_encrypted_private_key": "base64_encrypted_private_key_pkcs8",
"rsa_private_key_iv": "base64_iv"
}
/api/user/storage
Statistiche storage dell'utente.
Response (200 OK):
{
"used_bytes": 1234567890,
"quota_bytes": 5368709120, // 5 GB
"percentage_used": 23.0,
"file_count": 42
}
HTTP Status Codes & Errors
Le API implementano rate limiting per prevenire abusi:
- Authentication: 5 tentativi / 15 minuti per IP
- File Upload: 100 upload / ora per utente
- Downloads: 1000 download / ora per utente
- Public Shares: 50 accessi / ora per share_id
Headers risposta quando rate limit si avvicina:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 23
X-RateLimit-Reset: 1672329600 // Unix timestamp