Whitepaper Tecnici

Documentazione tecnica approfondita dell'architettura crittografica di PDF Pro

Pubblicato: 16 aprile 2025 Ultimo aggiornamento: 16 aprile 2026 Versione: 2.0

Indice dei Whitepaper

  1. Trasferimento File con Crittografia End-to-End
  2. Firma Crittografica dei Documenti con Priorità alla Privacy

Trasferimento File con Crittografia End-to-End

PDF Pro Whitepaper WP-001 — Architettura e Sicurezza

1.1 Abstract

Questo whitepaper descrive l'architettura del sistema di Trasferimento Sicuro di PDF Pro, un meccanismo di trasferimento file con crittografia end-to-end in cui i file vengono cifrati lato client tramite AES-256-GCM prima del caricamento. Il server archivia esclusivamente testo cifrato opaco e non è in grado di decifrare, ispezionare o leggere il contenuto dei file in nessun momento. Il sistema supporta due modalità di chiave: una chiave casuale generata automaticamente (trasportata tramite il frammento URL, che non viene mai inviato al server) o una chiave derivata da passphrase tramite PBKDF2. In entrambe le modalità, la chiave di cifratura esiste solo nei browser del mittente e del destinatario. Questo documento dettaglia le primitive crittografiche, il flusso di dati, il modello di minaccia e le limitazioni documentate del sistema. Nota sulla terminologia: questo sistema non utilizza prove a conoscenza zero (ZKP). Quando affermiamo che il server ha "zero conoscenza" dei tuoi file, intendiamo che — come conseguenza della crittografia lato client — il server detiene esclusivamente testo cifrato che non è in grado di decifrare.

1.2 Panoramica dell'Architettura

Il sistema di Trasferimento Sicuro segue una rigida separazione client-server in cui tutte le operazioni crittografiche avvengono esclusivamente nel browser:

Il server è progettato intenzionalmente come un "canale passivo" per i dati cifrati. Non dispone di alcuna conoscenza della chiave di cifratura, della passphrase o del contenuto dei file. Questo è garantito architetturalmente, non semplicemente tramite policy.

Principio di progettazione: Il server deve poter essere compromesso senza compromettere i dati degli utenti. Anche con accesso completo al database e con l'esecuzione di codice lato server, un attaccante non può decifrare i file trasferiti.

1.3 Cifratura: AES-256-GCM tramite Web Crypto API

Tutta la cifratura dei file utilizza l'algoritmo di cifratura autenticata AES-256-GCM, accessibile tramite la Web Crypto API nativa del browser. Questo garantisce sia la riservatezza (i dati non possono essere letti) sia l'integrità (i dati non possono essere modificati senza rilevamento).

1.3.1 Parametri dell'Algoritmo

ParametroValoreMotivazione
AlgoritmoAES-256-GCMApprovato dal NIST, cifratura autenticata con dati associati (AEAD)
Dimensione chiave256 bitLunghezza massima della chiave AES; fornisce sicurezza a 128 bit contro la forza bruta
Dimensione IV96 bit (12 byte)Lunghezza IV raccomandata dal NIST per la modalità GCM
Dimensione tag128 bit (16 byte)Tag di autenticazione a lunghezza intera per la massima protezione dell'integrità
Generazione IVcrypto.getRandomValues()Generatore di numeri casuali crittograficamente sicuro

1.3.2 Implementazione della Cifratura

// Flusso di cifratura semplificato (Web Crypto API)

const iv = crypto.getRandomValues(new Uint8Array(12));
const salt = crypto.getRandomValues(new Uint8Array(16));

// Deriva la chiave dalla passphrase (vedi Sezione 1.4)
const key = await deriveKey(passphrase, salt);

// Cifra il file
const ciphertext = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv: iv },
  key,
  fileArrayBuffer
);

// Pacchetto: [salt (16B)] + [iv (12B)] + [ciphertext + tag]
const blob = concatenate(salt, iv, ciphertext);

Il blob cifrato finale è una concatenazione di tre componenti: il salt di 16 byte (usato per la derivazione della chiave), l'IV di 12 byte (usato per AES-GCM) e il testo cifrato con il tag di autenticazione GCM di 16 byte aggiunto in coda. Questo blob è ciò che il server riceve e archivia.

1.4 Generazione & Trasporto della Chiave

Il Trasferimento Sicuro supporta due modalità di chiave mutuamente esclusive. La modalità viene selezionata dal mittente al momento della creazione del trasferimento.

1.4.1 Modalità A — Chiave Generata Automaticamente (Predefinita)

Nella modalità predefinita, non è coinvolta alcuna passphrase. Il browser genera direttamente una chiave AES a 256 bit casuale e crittograficamente sicura:

1.4.2 Modalità B — Trasferimento Protetto da Passphrase

Quando il mittente sceglie di impostare una passphrase, la chiave viene derivata da essa tramite PBKDF2:

1.4.3 Parametri PBKDF2 (Modalità B)

ParametroValoreMotivazione
AlgoritmoPBKDF2Raccomandato dal NIST SP 800-132; ampiamente verificato
Funzione hashSHA-256Hash crittografico standard; output a 256 bit
Iterazioni600.000Soddisfa la raccomandazione OWASP 2023 per PBKDF2-SHA256
Dimensione salt128 bit (16 byte)Unico per trasferimento; previene attacchi rainbow table
Lunghezza chiave di output256 bitCorrisponde al requisito della chiave AES-256

1.4.4 Implementazione della Derivazione della Chiave (Modalità B)

async function deriveKey(passphrase, salt) {
  // Importa la passphrase come materiale grezzo della chiave
  const keyMaterial = await crypto.subtle.importKey(
    "raw",
    new TextEncoder().encode(passphrase),
    { name: "PBKDF2" },
    false,
    ["deriveKey"]
  );

  // Deriva la chiave AES-256-GCM
  return crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: salt,
      iterations: 600000,
      hash: "SHA-256"
    },
    keyMaterial,
    { name: "AES-GCM", length: 256 },
    false,
    ["encrypt", "decrypt"]
  );
}

Nota sulla sicurezza: La sicurezza nella Modalità B dipende dall'entropia della passphrase. Si raccomandano passphrase di almeno 12 caratteri che combinino maiuscole, minuscole, cifre e simboli.

1.5 Flusso di Dati

Il ciclo di vita completo di un trasferimento sicuro segue questo percorso:

1.5.1 Invio (Caricamento) — Modalità A (Chiave Generata Automaticamente)

  1. Il mittente seleziona un file nel browser.
  2. Il browser genera una chiave AES-GCM casuale a 256 bit e un IV casuale di 12 byte tramite crypto.getRandomValues().
  3. Il browser cifra il file usando AES-256-GCM, producendo testo cifrato + tag di autenticazione.
  4. Il browser concatena [IV | testo cifrato+tag] in un unico blob.
  5. Il browser carica il blob cifrato sul server tramite HTTPS.
  6. Il server archivia il blob in Supabase Storage e crea un record di metadati (ID trasferimento, scadenza, limite di download, nome file, dimensione file).
  7. Il server restituisce un URL di trasferimento. Il browser aggiunge la chiave esportata al frammento URL (#).
  8. Il mittente condivide l'URL completo (con frammento) con il destinatario.

1.5.2 Invio (Caricamento) — Modalità B (Passphrase)

  1. Il mittente seleziona un file e inserisce una passphrase nel browser.
  2. Il browser genera un salt casuale di 16 byte e un IV di 12 byte tramite crypto.getRandomValues().
  3. Il browser deriva una chiave AES-256 dalla passphrase usando PBKDF2 (600K iterazioni).
  4. Il browser cifra il file usando AES-256-GCM, producendo testo cifrato + tag di autenticazione.
  5. Il browser concatena [salt | IV | testo cifrato+tag] in un unico blob.
  6. Il browser carica il blob cifrato sul server tramite HTTPS.
  7. Il server archivia il blob in Supabase Storage e crea un record di metadati (ID trasferimento, scadenza, limite di download, nome file, dimensione file).
  8. Il server restituisce un URL di trasferimento contenente l'ID del trasferimento.
  9. Il mittente condivide l'URL di trasferimento e la passphrase con il destinatario attraverso canali separati.

1.5.3 Ricezione (Download) — Modalità A

  1. Il destinatario apre l'URL di trasferimento completo (con la chiave nel frammento).
  2. Il browser estrae la chiave AES dal frammento URL (non viene mai inviata al server).
  3. Il browser scarica il blob cifrato dal server tramite HTTPS.
  4. Il browser estrae l'IV (primi 12 byte) dal blob.
  5. Il browser decifra il testo cifrato usando AES-256-GCM con la chiave e l'IV estratti.
  6. Se la decifratura ha esito positivo (il tag GCM è valido), il file in chiaro viene presentato all'utente.
  7. Il server aggiorna il contatore dei download e, se è abilitata la modalità burn-on-read, elimina il blob.

1.5.4 Ricezione (Download) — Modalità B

  1. Il destinatario apre l'URL di trasferimento e inserisce la passphrase nel browser.
  2. Il browser scarica il blob cifrato dal server tramite HTTPS.
  3. Il browser estrae il salt (primi 16 byte) e l'IV (successivi 12 byte) dal blob.
  4. Il browser deriva la chiave AES-256 dalla passphrase + salt usando PBKDF2 (600K iterazioni).
  5. Il browser decifra il testo cifrato usando AES-256-GCM con la chiave derivata e l'IV.
  6. Se la decifratura ha esito positivo (il tag GCM è valido), il file in chiaro viene presentato all'utente.
  7. Se la decifratura fallisce (passphrase errata = chiave errata = tag GCM non valido), viene mostrato un errore.
  8. Il server aggiorna il contatore dei download e, se è abilitata la modalità burn-on-read, elimina il blob.

1.6 Cosa Archivia il Server e Cosa Non Vede Mai

Elemento DatiIl Server ha Accesso?Dettagli
Blob cifrato (salt + IV + testo cifrato + tag)Dati binari opachi; il server non può interpretarne il contenuto
ID trasferimentoGli identificatori di trasferimento sono valori UUID v4 generati da gen_random_uuid() di PostgreSQL, che fornisce 122 bit di casualità crittografica dal CSPRNG del server
Nome file originaleArchiviato nei metadati per la visualizzazione al destinatario
Dimensione file originaleArchiviata nei metadati a scopo di visualizzazione
Timestamp di scadenzaUtilizzato per l'applicazione dell'eliminazione automatica
Contatore/limite downloadUtilizzato per burn-on-read e applicazione del limite di download
ID utente mittente (se autenticato)Collega il trasferimento all'account per la gestione
PassphraseNo — maiNon viene mai inviata al server; non lascia mai il browser
Chiave di cifratura derivataNo — maiEsiste solo nella memoria del browser durante le operazioni di cifratura/decifratura
Contenuto del file in chiaroNo — maiSolo il testo cifrato raggiunge il server
Contatore di iterazioni PBKDF2NoHardcoded nel client; non viene trasmesso al server

1.7 Scadenza Automatica e Burn-on-Read

Tutti i trasferimenti sicuri sono effimeri per design. Non è disponibile alcuna opzione di archiviazione permanente.

1.7.1 Opzioni di Scadenza

OpzioneComportamentoApplicazione
Burn on readIl blob cifrato viene eliminato immediatamente dopo il primo download avvenuto con successoLato server: il blob viene eliminato dallo storage al termine del flusso di download
1 oraEliminato automaticamente dopo 1 ora indipendentemente dallo stato del downloadLato server: job di pulizia pianificato + verifica scadenza all'accesso
24 oreEliminato automaticamente dopo 24 oreCome sopra
7 giorniConservazione massima; eliminato automaticamente dopo 7 giorniCome sopra

1.7.2 Garanzia di Eliminazione

Quando un trasferimento scade o viene bruciato alla lettura, il blob cifrato viene eliminato definitivamente da Supabase Storage. Il record dei metadati viene conservato per 30 giorni in uno stato di eliminazione temporanea (per indagini su abusi) prima di essere eliminato definitivamente. Il record dei metadati non contiene la chiave di cifratura, la passphrase né alcuna informazione che possa essere utilizzata per ricostruire il file.

1.8 Modello di Minaccia e Mitigazioni

MinacciaVettore di AttaccoMitigazione
Compromissione del server L'attaccante ottiene accesso completo al database e allo storage Tutti i dati archiviati sono testo cifrato AES-256-GCM. L'attaccante ottiene solo blob opachi. Senza la passphrase, forzare AES a 256 bit è computazionalmente non fattibile.
Intercettazione di rete (MITM) L'attaccante intercetta i dati in transito Tutto il traffico utilizza TLS 1.3. Anche se TLS venisse violato, l'attaccante otterrebbe solo blob cifrati (come nel caso di compromissione del server).
Passphrase debole L'attaccante esegue un attacco a forza bruta su una passphrase breve o comune PBKDF2 con 600K iterazioni rende ogni tentativo computazionalmente costoso. Una passphrase di 4 caratteri richiederebbe comunque risorse computazionali significative. L'interfaccia utente applica una lunghezza minima della passphrase e fornisce un feedback sulla robustezza.
Intercettazione della passphrase L'attaccante intercetta la passphrase condivisa tra mittente e destinatario La passphrase viene condivisa fuori banda (non tramite il nostro sistema). Si consiglia di condividerla tramite un canale diverso dall'URL di trasferimento. Questa è una responsabilità dell'utente.
Manomissione del codice lato client L'attaccante modifica il JavaScript servito all'utente Tutti gli asset vengono serviti tramite HTTPS con la CDN di Vercel. Gli hash di integrità delle sottorisorse (SRI) proteggono dalla manomissione a livello CDN. Gli utenti possono verificare il codice sorgente negli strumenti di sviluppo del browser.
Estrazione dalla memoria L'attaccante estrae la chiave di cifratura dalla memoria del browser Le chiavi dell'API Web Crypto sono contrassegnate come non estraibili ove possibile. Le chiavi derivate esistono in memoria solo durante l'operazione di cifratura/decifratura. L'isolamento della memoria del browser fornisce protezione a livello di sistema operativo.
Attacco replay L'attaccante riproduce un blob cifrato catturato Ogni trasferimento ha un ID univoco ed è protetto da limiti di download e scadenza. I trasferimenti burn-on-read vengono eliminati dopo il primo accesso.

1.8.1 Assunzioni

1.8.2 Fuori Ambito

1.9 Limitazioni e Dichiarazione Trasparente

Limitazioni documentate: Nessun sistema di sicurezza è perfetto. Crediamo nella divulgazione trasparente delle limitazioni note.


Firma Crittografica dei Documenti con Priorità alla Privacy

PDF Pro Whitepaper WP-002 — Architettura e Sicurezza

2.1 Abstract

Questo whitepaper descrive l'architettura del sistema di Firma Privacy di PDF Pro, un meccanismo di firma crittografica dei documenti in cui il documento PDF non lascia mai il browser del firmatario. Il sistema utilizza ECDSA con la curva P-256 e l'hashing SHA-256 per produrre firme digitali distaccate. Solo l'hash del documento, la firma crittografica e la chiave pubblica vengono trasmessi al server. Le chiavi private vengono generate, cifrate e archiviate esclusivamente nel browser dell'utente tramite IndexedDB, protette dalla derivazione della chiave PBKDF2 (600.000 iterazioni) e dalla cifratura AES-256-GCM. Questo documento dettaglia l'architettura completa di firma e verifica, il modello di gestione delle chiavi, lo schema del payload firmato, il design della catena di audit, il modello di minaccia e le limitazioni documentate.

2.2 Panoramica dell'Architettura

Il sistema di Firma Privacy è progettato attorno a un vincolo fondamentale: il documento PDF non deve mai essere trasmesso al server. Questo è garantito architetturalmente tramite un modello di firma distaccata.

Garanzia fondamentale: Il server non vede, riceve né elabora mai il documento PDF. L'unico dato correlato al documento che il server riceve è un hash SHA-256 — un valore a dimensione fissa di 256 bit dal quale il documento originale non può essere ricostruito.

2.3 Algoritmo di Firma: ECDSA P-256 / SHA-256

2.3.1 Parametri dell'Algoritmo

ParametroValoreMotivazione
Algoritmo di firmaECDSA (Elliptic Curve Digital Signature Algorithm)NIST FIPS 186-4; firme compatte; elevata sicurezza per bit di chiave
CurvaP-256 (secp256r1 / prime256v1)Approvata dal NIST; livello di sicurezza a 128 bit; ampio supporto della Web Crypto API
Funzione hashSHA-256NIST FIPS 180-4; digest a 256 bit; resistente alle collisioni
Dimensione chiaveChiave privata a 256 bit, chiave pubblica a 512 bit (non compressa)Standard per P-256; equivalente a RSA a ~3072 bit
Dimensione firma64 byte (r: 32 byte, s: 32 byte)Compatta; adatta all'archiviazione e alla trasmissione
Formato firmaIEEE P1363 (r || s grezzo)Output nativo della Web Crypto API; codificato in base64url per l'archiviazione

Codifica della firma: L'ECDSA della Web Crypto API con P-256 produce una firma grezza di 64 byte composta da due interi di 32 byte (r || s) in formato big-endian a larghezza fissa. Questo output grezzo viene codificato in base64url per l'archiviazione. NON è codificato DER — è il formato IEEE P1363 prodotto nativamente dalla Web Crypto API.

2.3.2 Flusso di Firma

// 1. Hash del documento PDF (lato client)
const fileBuffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest("SHA-256", fileBuffer);
const hashHex = Array.from(new Uint8Array(hashBuffer))
  .map(b => b.toString(16).padStart(2, '0')).join('');

// 2. Firma l'hash con la chiave privata (lato client)
const signature = await crypto.subtle.sign(
  { name: "ECDSA", hash: "SHA-256" },
  privateKey,   // CryptoKey da IndexedDB (decifrata)
  hashBuffer
);

// 3. Invia al server: hash + firma + chiave pubblica (NON il PDF)
await submitSignature({
  documentHash: hashHex,
  signature: base64Encode(signature),
  publicKey: exportedPublicKeyJWK
});

2.4 Gestione delle Chiavi: Effimera vs. Persistente

Tipo di ChiaveContestoCiclo di VitaArchiviazione
Effimera Utenti ospiti (non autenticati) Generata per sessione; distrutta alla chiusura della scheda Solo in memoria (oggetto CryptoKey); mai persistita
Persistente Utenti autenticati (con accesso effettuato) Generata una volta; persistita tra le sessioni; revocabile IndexedDB (cifrata con PBKDF2 + AES-256-GCM)

2.4.1 Generazione della Chiave

// Genera coppia di chiavi ECDSA P-256 (Web Crypto API)
const keyPair = await crypto.subtle.generateKey(
  {
    name: "ECDSA",
    namedCurve: "P-256"
  },
  true,   // estraibile (necessario per cifratura + archiviazione)
  ["sign", "verify"]
);

// Esporta la chiave pubblica come JWK per la registrazione sul server
const publicKeyJWK = await crypto.subtle.exportKey("jwk", keyPair.publicKey);

// Esporta la chiave privata come JWK per l'archiviazione cifrata
const privateKeyJWK = await crypto.subtle.exportKey("jwk", keyPair.privateKey);

Formato chiave pubblica: Le chiavi pubbliche vengono esportate e archiviate in formato JWK (JSON Web Key). L'impronta digitale della chiave è calcolata come SHA-256 del JWK canonico contenente solo i campi pubblici {crv, kty, x, y} con le chiavi ordinate alfabeticamente.

2.5 Protezione della Chiave Privata: PBKDF2 + AES-GCM → IndexedDB

Le chiavi private persistenti non vengono mai archiviate in chiaro. Prima di essere scritte su IndexedDB, la chiave privata (esportata come JSON JWK) viene cifrata usando lo stesso schema del Trasferimento Sicuro:

2.5.1 Parametri di Protezione

ParametroValore
Derivazione chiavePBKDF2-SHA256, 600.000 iterazioni
Salt16 byte casuali (per chiave)
CifraturaAES-256-GCM
IV12 byte casuali (per cifratura)
InputJWK della chiave privata (stringa JSON, codificata UTF-8)
Output archiviato in IndexedDB{ salt, iv, ciphertext, publicKeyJWK, keyId, createdAt }

2.5.2 Schema di Archiviazione

// Struttura del record IndexedDB per una chiave di firma cifrata
{
  "keyId":       "uuid-v4-unique-identifier",
  "publicKey":   { /* formato JWK, non cifrato */ },
  "encryptedPrivateKey": {
    "salt":       "base64-encoded-16-bytes",
    "iv":         "base64-encoded-12-bytes",
    "ciphertext": "base64-encoded-aes-gcm-ciphertext"
  },
  "algorithm":   "ECDSA",
  "curve":       "P-256",
  "createdAt":   "2026-04-16T00:00:00.000Z",
  "userId":      "supabase-auth-user-id"
}

Recupero della chiave: Se l'utente dimentica la passphrase di firma, la chiave privata non può essere recuperata. Non disponiamo della passphrase, della chiave derivata né di alcun meccanismo per aggirare la protezione PBKDF2 + AES-GCM. Gli utenti dovrebbero esportare backup delle chiavi.

2.6 Modello di Firma Distaccata

PDF Pro utilizza un modello di firma distaccata, il che significa che la firma viene archiviata separatamente dal documento. Questo è il meccanismo critico per la privacy: il documento non lascia mai il dispositivo del firmatario.

2.6.1 Cosa Viene Inviato al Server

2.6.2 Cosa NON Viene Inviato al Server

Garanzia crittografica: SHA-256 è una funzione hash unidirezionale. Dato solo l'hash e3b0c44298fc1c14..., fornisce una solida garanzia crittografica, nell'ambito delle assunzioni di sicurezza di ECDSA e SHA-256, che il documento originale non possa essere ricostruito. L'hash non rivela nulla sul contenuto, la lunghezza o la struttura del documento, se non la conferma dell'identità al momento del ricalcolo dell'hash.

2.7 Schema del Payload Firmato v1.0

Il seguente schema JSON definisce il record di firma completo archiviato sul server:

{
  "schemaVersion":  "1.0",
  "signatureId":    "uuid-v4",
  "documentHash":   "sha256-hex-64-chars",
  "hashAlgorithm":  "SHA-256",
  "signature":      "base64-encoded-ecdsa-signature",
  "signatureAlgorithm": "ECDSA",
  "curve":          "P-256",
  "publicKey": {
    "kty": "EC",
    "crv": "P-256",
    "x":   "base64url-encoded-x-coordinate",
    "y":   "base64url-encoded-y-coordinate"
  },
  "signer": {
    "identityLevel": "authenticated | self-asserted",
    "displayName":   "string or null",
    "email":         "string or null",
    "userId":        "supabase-uid or null"
  },
  "timestamp":      "ISO-8601-UTC",
  "metadata": {
    "fileName":     "original-file-name.pdf",
    "fileSize":     123456,
    "pageCount":    12,
    "clientVersion": "2.0.0",
    "userAgent":    "browser-user-agent-string"
  },
  "auditChain": {
    "previousEventHash": "sha256-of-previous-audit-event or null",
    "eventHash":         "sha256-of-this-record"
  }
}

2.8 Flusso di Verifica

La verifica della firma è un processo in due fasi: verifica crittografica lato client seguita da una verifica incrociata lato server.

2.8.1 Fase 1: Verifica Crittografica Lato Client

  1. L'utente carica un PDF nel browser.
  2. Il browser calcola l'hash SHA-256 del PDF caricato.
  3. Il browser interroga il server per eventuali record di firma corrispondenti a questo hash.
  4. Per ogni record di firma restituito, il browser esegue la verifica ECDSA:
    const isValid = await crypto.subtle.verify(
      { name: "ECDSA", hash: "SHA-256" },
      importedPublicKey,
      signatureBuffer,
      hashBuffer
    );
  5. Se isValid === true, la firma è crittograficamente valida: il documento non è stato modificato dalla firma e la firma è stata prodotta dal titolare della chiave privata corrispondente.

2.8.2 Fase 2: Verifica Incrociata Lato Server

  1. Il server conferma che la chiave pubblica nel record di firma è registrata a un utente noto (per le firme autenticate).
  2. Il server conferma che il record di firma non è stato revocato.
  3. Il server conferma l'integrità della catena di audit (validazione della catena hash).
  4. Il server restituisce il livello di identità del firmatario e lo stato di registrazione.

2.8.3 Risultati della Verifica

RisultatoSignificato
Valida (Autenticata)La firma è crittograficamente valida E la chiave pubblica appartiene a un utente PDF Pro registrato e autenticato.
Valida (Auto-dichiarata)La firma è crittograficamente valida ma l'identità del firmatario è auto-dichiarata (utente ospite o nome non verificato).
Non validaLa verifica crittografica ha fallito. Il documento è stato modificato dopo la firma, oppure la firma è danneggiata.
RevocataLa firma era valida ma è stata esplicitamente revocata dal firmatario.
Nessuna firma trovataNon esiste alcun record di firma per questo hash del documento.

2.9 Catena di Audit: Eventi con Hash Concatenati

Ogni evento di firma e verifica viene registrato in una catena di audit a prova di manomissione. Gli eventi sono concatenati tramite hash: ogni evento include l'hash SHA-256 dell'evento precedente, formando una catena solo-aggiunta simile a una blockchain.

2.9.1 Tipi di Evento di Audit

Tipo di EventoTriggerDati Registrati
KEY_REGISTEREDL'utente registra una nuova chiave pubblicaJWK della chiave pubblica, ID utente, timestamp
DOCUMENT_SIGNEDL'utente firma un documentoHash del documento, firma, chiave pubblica, identità del firmatario, timestamp
SIGNATURE_VERIFIEDQualsiasi utente verifica una firmaHash del documento, risultato della verifica, informazioni sul verificatore (se autenticato), timestamp
SIGNATURE_REVOKEDIl firmatario revoca una firmaID firma, motivo della revoca, timestamp
KEY_REVOKEDL'utente revoca una chiave pubblicaID chiave pubblica, motivo della revoca, timestamp

2.9.2 Struttura della Catena Hash

// Ogni evento di audit include:
{
  "eventId":            "uuid-v4",
  "eventType":          "DOCUMENT_SIGNED",
  "timestamp":          "ISO-8601-UTC",
  "data":               { /* payload specifico dell'evento */ },
  "previousEventHash": "sha256-of-previous-event-json",
  "eventHash":          "sha256-of-this-event-json-without-eventHash"
}

// Rilevamento delle manomissioni: per verificare la catena, calcolare:
// SHA-256(JSON.stringify(evento senza campo eventHash))
// e confermare che corrisponda a eventHash.
// Poi confermare che previousEventHash corrisponda all'eventHash dell'evento precedente.

Se viene modificato qualsiasi evento nella catena, tutti i collegamenti hash successivi si romperanno, rendendo immediatamente rilevabile la manomissione. Questo fornisce una solida garanzia di integrità della catena di audit.

Limitazione importante: La catena hash rende rilevabile la manomissione all'interno della sequenza di eventi registrati. Tuttavia, un amministratore del database con accesso diretto potrebbe teoricamente eliminare e ricostruire la catena. Garanzie più forti richiederebbero una marcatura temporale esterna o un'attestazione di terze parti, che non è implementata in questa versione.

2.10 Livelli di Identità

LivelloRequisitiProprietà di FiduciaCaso d'Uso
Autenticato Utente PDF Pro con accesso effettuato ed email verificata; coppia di chiavi persistente registrata sull'account Email verificata da Supabase Auth; chiave pubblica associata all'account autenticato; catena di audit collegata all'ID utente Documenti aziendali, contratti, accordi formali
Auto-dichiarato Utente ospite o utente autenticato con nome inserito autonomamente; coppia di chiavi effimera o persistente Integrità crittografica garantita; l'identità del firmatario è auto-dichiarata e non verificata in modo indipendente Firma rapida, documenti personali, accordi informali

Nota: Nell'interfaccia del prodotto, 'self_asserted' può essere visualizzato come 'Identità Auto-dichiarata' o 'Firma Ospite'. 'authenticated' può essere visualizzato come 'Account Autenticato'. Queste sono etichette di visualizzazione per gli stessi livelli di identità sottostanti.

Associazione dell'identità: Una firma "autenticata" significa che la chiave pubblica è registrata a un account PDF Pro con email verificata. NON significa che l'identità reale del firmatario sia stata verificata tramite documento d'identità governativo, dati biometrici o verifica di persona. Non eseguiamo controlli Know Your Customer (KYC).

2.11 Modello di Minaccia

MinacciaVettore di AttaccoMitigazione
Attacco replay L'attaccante copia una firma valida e la applica a un documento diverso La firma è associata all'hash SHA-256 del documento specifico. Un documento diverso avrà un hash diverso e la verifica ECDSA fallirà.
Contraffazione L'attaccante crea una firma valida senza la chiave privata La sicurezza di ECDSA P-256 si basa sul Problema del Logaritmo Discreto su Curve Ellittiche (ECDLP). Contraffare una firma senza la chiave privata è computazionalmente non fattibile (livello di sicurezza a 128 bit).
Sostituzione della chiave L'attaccante registra la propria chiave pubblica e afferma che una firma è stata effettuata da qualcun altro Le firme autenticate associano la chiave pubblica a un'email verificata. La catena di audit registra quale chiave ha firmato quale documento. Gli eventi di registrazione della chiave sono concatenati tramite hash.
Sostituzione del documento L'attaccante modifica un PDF firmato e afferma che la firma sia ancora valida Qualsiasi modifica al PDF cambia il suo hash SHA-256. La firma esistente fallirà la verifica contro il nuovo hash. Trovare una collisione (documento diverso con lo stesso hash) richiede ~2^128 operazioni.
Furto della chiave privata L'attaccante estrae la chiave privata cifrata da IndexedDB La chiave privata è cifrata con AES-256-GCM, con chiave derivata da PBKDF2 (600K iterazioni). Senza la passphrase, decifrare la chiave è computazionalmente non fattibile.
Compromissione del server L'attaccante ottiene accesso completo al server Il server dispone solo di chiavi pubbliche e record di firma. Le chiavi private non raggiungono mai il server. Un attaccante non può contraffare nuove firme. Potrebbe eliminare o modificare record esistenti, ma le interruzioni nella catena hash sarebbero rilevabili.
Manomissione della catena di audit L'attaccante modifica gli eventi della catena di audit sul server Eventi con hash concatenati: la modifica di qualsiasi evento rompe la catena da quel punto in avanti. Gli strumenti di verifica indipendenti possono rilevare le interruzioni della catena.

2.11.1 Assunzioni

2.11.2 Fuori Ambito

2.12 Dichiarazione Trasparente

Cosa NON sono le firme PDF Pro:

2.12.1 Per Cosa SONO Adatte le Firme PDF Pro

Il nostro impegno: Costruiamo la sicurezza attraverso l'architettura, non il marketing. Questi whitepaper descrivono esattamente come funzionano i nostri sistemi, comprese le loro limitazioni. Crediamo che gli utenti attenti alla sicurezza meritino una completa trasparenza tecnica. Se hai domande su qualsiasi aspetto della nostra architettura, contattaci all'indirizzo info@webdesign9.com.