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

flowchart TD INIT[Avviare distruzione] --> CHECK{Verifiche} CHECK --> DEP[Verificare dipendenze] DEP --> BAK[Localizzare backup] BAK --> APPROVE{Approvazione?} APPROVE -->|No| ABORT[Annullare] APPROVE -->|Sì| DESTROY[Sovrascrivere chiave] DESTROY --> BACKUP_DEL[Distruggere backup] BACKUP_DEL --> HSM_DEL[Eliminare chiavi HSM] HSM_DEL --> LOG[Audit-Log] LOG --> CERT[Certificato] style DESTROY fill:#ffebee style BACKUP_DEL fill:#ffebee style HSM_DEL fill:#ffebee


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

Zuletzt geändert: il 30/01/2026 alle 06:41