~~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//