Scenario 11.5: Distruzione chiavi
Categoria: Gestione chiavi
Complessità: Alta
Prerequisiti: Chiave non più necessaria, backup verificati
Tempo stimato: 20-30 minuti
Descrizione
Questo scenario descrive la distruzione sicura e irreversibile delle chiavi crittografiche. Una corretta distruzione delle chiavi è l'ultimo passo nel ciclo di vita delle chiavi ed è critica per la sicurezza.
Motivi di distruzione:
- Fine vita - Ciclo di vita della chiave terminato
- Compromissione - Chiave potenzialmente nota
- Conformità - Periodi di conservazione scaduti
- Dismissione - Sistema in fase di spegnimento
- Migrazione algoritmo - Vecchie chiavi dopo passaggio a PQ
ATTENZIONE: La distruzione delle chiavi è irreversibile! Assicurarsi che:
- Tutti i dati crittografati siano stati decrittografati o non siano più necessari
- Tutte le firme siano state validate o non siano più rilevanti
- Anche i backup siano stati distrutti
Workflow
Esempio codice: Cancellazione sicura memoria
using System.Security.Cryptography; using System.Runtime.InteropServices; public class SecureKeyDestruction { public void DestroyKeyInMemory(byte[] keyMaterial) { if (keyMaterial == null || keyMaterial.Length == 0) return; // 1. Sovrascrivere con dati casuali RandomNumberGenerator.Fill(keyMaterial); // 2. Sovrascrivere con zeri Array.Clear(keyMaterial, 0, keyMaterial.Length); // 3. Sovrascrivere nuovamente con dati casuali RandomNumberGenerator.Fill(keyMaterial); // 4. Sovrascrittura finale con zeri CryptographicOperations.ZeroMemory(keyMaterial); Console.WriteLine($"Memoria cancellata: {keyMaterial.Length} bytes"); } public void DestroyKeyOnDisk(string keyFilePath) { if (!File.Exists(keyFilePath)) { Console.WriteLine($"File non trovato: {keyFilePath}"); return; } var fileInfo = new FileInfo(keyFilePath); var fileLength = fileInfo.Length; // Sovrascrittura multipla (Standard DoD 5220.22-M) using (var fs = new FileStream(keyFilePath, FileMode.Open, FileAccess.Write)) { var buffer = new byte[4096]; // Passaggio 1: sovrascrivere con 0x00 OverwriteFile(fs, fileLength, 0x00); // Passaggio 2: sovrascrivere con 0xFF OverwriteFile(fs, fileLength, 0xFF); // Passaggio 3: sovrascrivere con dati casuali OverwriteFileRandom(fs, fileLength); // Passaggio 4: nuovamente con 0x00 OverwriteFile(fs, fileLength, 0x00); fs.Flush(); } // Rinominare file (offuscare metadati) var randomName = Path.Combine( Path.GetDirectoryName(keyFilePath), Guid.NewGuid().ToString() ); File.Move(keyFilePath, randomName); // Eliminare file File.Delete(randomName); Console.WriteLine($"File chiave eliminato in sicurezza: {keyFilePath}"); } private void OverwriteFile(FileStream fs, long length, byte value) { fs.Seek(0, SeekOrigin.Begin); var buffer = new byte[4096]; Array.Fill(buffer, value); long remaining = length; while (remaining > 0) { int toWrite = (int)Math.Min(remaining, buffer.Length); fs.Write(buffer, 0, toWrite); remaining -= toWrite; } } private void OverwriteFileRandom(FileStream fs, long length) { fs.Seek(0, SeekOrigin.Begin); var buffer = new byte[4096]; long remaining = length; while (remaining > 0) { RandomNumberGenerator.Fill(buffer); int toWrite = (int)Math.Min(remaining, buffer.Length); fs.Write(buffer, 0, toWrite); remaining -= toWrite; } } }
Esempio codice: Distruzione completa con protocollo
public class KeyDestructionService { private readonly ILogger _logger; private readonly IAuditLog _auditLog; public async Task<DestructionCertificate> DestroyKeyAsync( string keyId, string reason, string authorizedBy, DestructionOptions options = null) { options ??= DestructionOptions.Default; var certificate = new DestructionCertificate { KeyId = keyId, DestructionId = Guid.NewGuid().ToString(), InitiatedAt = DateTime.UtcNow, Reason = reason, AuthorizedBy = authorizedBy }; try { // 1. Verificare dipendenze await ValidateDestructionAsync(keyId, certificate); // 2. Distruggere chiave attiva await DestroyPrimaryKeyAsync(keyId, certificate); // 3. Distruggere tutti i backup if (options.DestroyBackups) { await DestroyBackupsAsync(keyId, certificate); } // 4. Distruggere chiavi HSM if (options.DestroyHsmKeys) { await DestroyHsmKeyAsync(keyId, certificate); } // 5. Creare Audit-Log certificate.CompletedAt = DateTime.UtcNow; certificate.Status = DestructionStatus.Completed; await _auditLog.LogAsync(new AuditEntry { Action = "KEY_DESTRUCTION", KeyId = keyId, Details = certificate, Timestamp = DateTime.UtcNow }); _logger.LogInformation( "Chiave {KeyId} distrutta con successo. Certificato: {DestructionId}", keyId, certificate.DestructionId); return certificate; } catch (Exception ex) { certificate.Status = DestructionStatus.Failed; certificate.Error = ex.Message; _logger.LogError(ex, "Distruzione chiave fallita: {KeyId}", keyId); throw; } } private async Task ValidateDestructionAsync(string keyId, DestructionCertificate cert) { // Verificare se esistono ancora certificati attivi var activeCerts = await _certStore.FindByKeyIdAsync(keyId); if (activeCerts.Any(c => c.NotAfter > DateTime.UtcNow)) { throw new InvalidOperationException( $"La chiave {keyId} è ancora utilizzata da {activeCerts.Count} certificati attivi"); } cert.ValidationsPassed.Add("Nessun certificato attivo"); // Verificare se il periodo di conservazione è scaduto var metadata = await _keyStore.GetMetadataAsync(keyId); if (metadata.RetentionUntil > DateTime.UtcNow) { throw new InvalidOperationException( $"Il periodo di conservazione termina il {metadata.RetentionUntil:d}"); } cert.ValidationsPassed.Add("Periodo di conservazione scaduto"); } } public class DestructionCertificate { public string DestructionId { get; set; } public string KeyId { get; set; } public string KeyFingerprint { get; set; } public DateTime InitiatedAt { get; set; } public DateTime? CompletedAt { get; set; } public string Reason { get; set; } public string AuthorizedBy { get; set; } public DestructionStatus Status { get; set; } public List<string> ValidationsPassed { get; set; } = new(); public bool PrimaryKeyDestroyed { get; set; } public int BackupsDestroyed { get; set; } public bool HsmKeyDestroyed { get; set; } public List<string> DestroyedLocations { get; set; } = new(); public string Error { get; set; } } public enum DestructionStatus { InProgress, Completed, Failed }
Standard di distruzione
| Standard | Sovrascritture | Pattern | Applicazione |
|---|---|---|---|
| DoD 5220.22-M | 3 | 0x00, 0xFF, Random | Esercito USA |
| NIST SP 800-88 | 1-3 | Dipende dal tipo di supporto | Governo USA |
| BSI-TL 03423 | 3 | Random, 0x00, 0xFF | Enti tedeschi |
| Gutmann | 35 | Pattern diversi | Paranoico |
Per SSD e memorie flash: la cancellazione sicura richiede comandi firmware speciali (TRIM, Secure Erase). La sovrascrittura software non è affidabile!
Requisiti di distruzione specifici per settore
| Settore | Requisito | Testimoni | Documentazione |
|---|---|---|---|
| Finanza | PCI-DSS 3.6.6 | 2 persone | Protocollo distruzione |
| Sanità | HIPAA | 1 testimone | Audit-Log |
| Enti pubblici | VS-NfD | Resp. protezione segreti | Certificato distruzione |
| KRITIS | BSI | 2 persone | Certificato + Protocollo |
Scenari correlati
| Relazione | Scenario | Descrizione |
|---|---|---|
| Prerequisito | 11.4 Backup chiavi | Identificare tutti i backup |
| Prerequisito | 11.3 Rotazione chiavi | Nuove chiavi prima della distruzione |
| Correlato | 6.4 Revocare certificato | Revocare prima della distruzione |
| Correlato | 4.3 Archiviazione | Alternativa: archiviare invece di distruggere |
« 11.4 Backup chiavi | Panoramica chiavi | Tutti gli scenari »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional