~~NOTOC~~ ====== Scenario 11.5: Key Destruction ====== **Category:** [[.:start|Key Management]] \\ **Complexity:** ⭐⭐⭐⭐ (High) \\ **Prerequisites:** Key no longer needed, backups verified \\ **Estimated Time:** 20-30 Minutes ---- ===== Description ===== This scenario describes the **secure and irreversible destruction of cryptographic keys**. Proper key destruction is the final step in the key lifecycle and critical for security. **Destruction Reasons:** * **End of Life** - Key lifecycle ended * **Compromise** - Key possibly known * **Compliance** - Retention periods expired * **Decommissioning** - System being retired * **Algorithm Migration** - Old keys after PQ transition **WARNING:** Key destruction is irreversible! Ensure: * All encrypted data is decrypted or no longer needed * All signatures are validated or no longer relevant * Backups have also been destroyed ---- ===== Workflow ===== flowchart TD INIT[Initiate destruction] --> CHECK{Checks} CHECK --> DEP[Check dependencies] DEP --> BAK[Locate backups] BAK --> APPROVE{Approval?} APPROVE -->|No| ABORT[Abort] APPROVE -->|Yes| DESTROY[Overwrite key] DESTROY --> BACKUP_DEL[Destroy backups] BACKUP_DEL --> HSM_DEL[Delete HSM keys] HSM_DEL --> LOG[Audit log] LOG --> CERT[Certificate] style DESTROY fill:#ffebee style BACKUP_DEL fill:#ffebee style HSM_DEL fill:#ffebee ---- ===== Code Example: Secure Memory Deletion ===== using System.Security.Cryptography; using System.Runtime.InteropServices; public class SecureKeyDestruction { public void DestroyKeyInMemory(byte[] keyMaterial) { if (keyMaterial == null || keyMaterial.Length == 0) return; // 1. Overwrite with random data RandomNumberGenerator.Fill(keyMaterial); // 2. Overwrite with zeros Array.Clear(keyMaterial, 0, keyMaterial.Length); // 3. Overwrite again with random data RandomNumberGenerator.Fill(keyMaterial); // 4. Final overwrite with zeros CryptographicOperations.ZeroMemory(keyMaterial); Console.WriteLine($"Memory cleared: {keyMaterial.Length} bytes"); } public void DestroyKeyOnDisk(string keyFilePath) { if (!File.Exists(keyFilePath)) { Console.WriteLine($"File not found: {keyFilePath}"); return; } var fileInfo = new FileInfo(keyFilePath); var fileLength = fileInfo.Length; // Multiple overwrites (DoD 5220.22-M Standard) using (var fs = new FileStream(keyFilePath, FileMode.Open, FileAccess.Write)) { var buffer = new byte[4096]; // Pass 1: Overwrite with 0x00 OverwriteFile(fs, fileLength, 0x00); // Pass 2: Overwrite with 0xFF OverwriteFile(fs, fileLength, 0xFF); // Pass 3: Overwrite with random data OverwriteFileRandom(fs, fileLength); // Pass 4: Again with 0x00 OverwriteFile(fs, fileLength, 0x00); fs.Flush(); } // Rename file (obscure metadata) var randomName = Path.Combine( Path.GetDirectoryName(keyFilePath), Guid.NewGuid().ToString() ); File.Move(keyFilePath, randomName); // Delete file File.Delete(randomName); Console.WriteLine($"Key file securely deleted: {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; } } } ---- ===== Code Example: Complete Destruction with Protocol ===== public class KeyDestructionService { private readonly ILogger _logger; private readonly IAuditLog _auditLog; public async Task 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. Check dependencies await ValidateDestructionAsync(keyId, certificate); // 2. Destroy active key await DestroyPrimaryKeyAsync(keyId, certificate); // 3. Destroy all backups if (options.DestroyBackups) { await DestroyBackupsAsync(keyId, certificate); } // 4. Destroy HSM keys if (options.DestroyHsmKeys) { await DestroyHsmKeyAsync(keyId, certificate); } // 5. Create 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( "Key {KeyId} successfully destroyed. Certificate: {DestructionId}", keyId, certificate.DestructionId); return certificate; } catch (Exception ex) { certificate.Status = DestructionStatus.Failed; certificate.Error = ex.Message; _logger.LogError(ex, "Key destruction failed: {KeyId}", keyId); throw; } } private async Task ValidateDestructionAsync(string keyId, DestructionCertificate cert) { // Check if active certificates still exist var activeCerts = await _certStore.FindByKeyIdAsync(keyId); if (activeCerts.Any(c => c.NotAfter > DateTime.UtcNow)) { throw new InvalidOperationException( $"Key {keyId} is still used by {activeCerts.Count} active certificates"); } cert.ValidationsPassed.Add("No active certificates"); // Check if retention period expired var metadata = await _keyStore.GetMetadataAsync(keyId); if (metadata.RetentionUntil > DateTime.UtcNow) { throw new InvalidOperationException( $"Retention period runs until {metadata.RetentionUntil:d}"); } cert.ValidationsPassed.Add("Retention period expired"); } } 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 ValidationsPassed { get; set; } = new(); public bool PrimaryKeyDestroyed { get; set; } public int BackupsDestroyed { get; set; } public bool HsmKeyDestroyed { get; set; } public List DestroyedLocations { get; set; } = new(); public string Error { get; set; } } public enum DestructionStatus { InProgress, Completed, Failed } ---- ===== Destruction Standards ===== ^ Standard ^ Overwrites ^ Pattern ^ Application ^ | **DoD 5220.22-M** | 3 | 0x00, 0xFF, Random | US Military | | **NIST SP 800-88** | 1-3 | Depends on media type | US Government | | **BSI-TL 03423** | 3 | Random, 0x00, 0xFF | German Authorities | | **Gutmann** | 35 | Various patterns | Paranoid | For SSDs and flash storage: Secure deletion requires special firmware commands (TRIM, Secure Erase). Software overwriting is not reliable! ---- ===== Industry-Specific Destruction Requirements ===== ^ Industry ^ Requirement ^ Witnesses ^ Documentation ^ | **Financial Sector** | PCI-DSS 3.6.6 | 2 persons | Destruction protocol | | **Healthcare** | HIPAA | 1 witness | Audit log | | **Government** | VS-NfD | Security Officer | Destruction certificate | | **KRITIS** | BSI | 2 persons | Certificate + Protocol | ---- ===== Related Scenarios ===== ^ Relationship ^ Scenario ^ Description ^ | **Prerequisite** | [[.:backup|11.4 Key Backup]] | Identify all backups | | **Prerequisite** | [[.:rotation|11.3 Key Rotation]] | New keys before destruction | | **Related** | [[en:int:pqcrypt:szenarien:widerruf:zertifikat_widerrufen|6.4 Revoke Certificate]] | Revoke before destruction | | **Related** | [[en:int:pqcrypt:szenarien:verwaltung:archivierung|4.3 Archival]] | Alternative: Archive instead of destroy | ---- << [[.:backup|← 11.4 Key Backup]] | [[.:start|↑ Key Overview]] | [[en:int:pqcrypt:szenarien:start|→ All Scenarios]] >> {{tag>scenario key destruction security compliance audit}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//