~~NOTOC~~
====== Szenario 11.5: Schlüsselvernichtung ======
**Kategorie:** [[.:start|Schlüsselmanagement]] \\
**Komplexität:** ⭐⭐⭐⭐ (Hoch) \\
**Voraussetzungen:** Schlüssel nicht mehr benötigt, Backups geprüft \\
**Geschätzte Zeit:** 20-30 Minuten
----
===== Beschreibung =====
Dieses Szenario beschreibt die **sichere und unwiderrufliche Vernichtung kryptographischer Schlüssel**. Eine ordnungsgemäße Schlüsselvernichtung ist der letzte Schritt im Schlüssel-Lebenszyklus und kritisch für die Sicherheit.
**Vernichtungs-Gründe:**
* **End of Life** - Schlüssel-Lebenszyklus beendet
* **Kompromittierung** - Schlüssel möglicherweise bekannt
* **Compliance** - Aufbewahrungsfristen abgelaufen
* **Außerbetriebnahme** - System wird stillgelegt
* **Algorithmus-Migration** - Alte Schlüssel nach PQ-Umstellung
**WARNUNG:** Schlüsselvernichtung ist unwiderruflich! Stellen Sie sicher:
* Alle verschlüsselten Daten sind entschlüsselt oder nicht mehr benötigt
* Alle Signaturen sind validiert oder nicht mehr relevant
* Backups wurden ebenfalls vernichtet
----
===== Workflow =====
flowchart TD
INIT[Vernichtung initiieren] --> CHECK{Prüfungen}
CHECK --> DEP[Abhängigkeiten prüfen]
DEP --> BAK[Backups lokalisieren]
BAK --> APPROVE{Genehmigung?}
APPROVE -->|Nein| ABORT[Abbruch]
APPROVE -->|Ja| DESTROY[Schlüssel überschreiben]
DESTROY --> BACKUP_DEL[Backups vernichten]
BACKUP_DEL --> HSM_DEL[HSM-Keys löschen]
HSM_DEL --> LOG[Audit-Log]
LOG --> CERT[Bescheinigung]
style DESTROY fill:#ffebee
style BACKUP_DEL fill:#ffebee
style HSM_DEL fill:#ffebee
----
===== Code-Beispiel: Sichere Speicher-Löschung =====
using System.Security.Cryptography;
using System.Runtime.InteropServices;
public class SecureKeyDestruction
{
public void DestroyKeyInMemory(byte[] keyMaterial)
{
if (keyMaterial == null || keyMaterial.Length == 0)
return;
// 1. Mit Zufallsdaten überschreiben
RandomNumberGenerator.Fill(keyMaterial);
// 2. Mit Nullen überschreiben
Array.Clear(keyMaterial, 0, keyMaterial.Length);
// 3. Nochmals mit Zufallsdaten überschreiben
RandomNumberGenerator.Fill(keyMaterial);
// 4. Final mit Nullen überschreiben
CryptographicOperations.ZeroMemory(keyMaterial);
Console.WriteLine($"Speicher gelöscht: {keyMaterial.Length} Bytes");
}
public void DestroyKeyOnDisk(string keyFilePath)
{
if (!File.Exists(keyFilePath))
{
Console.WriteLine($"Datei nicht gefunden: {keyFilePath}");
return;
}
var fileInfo = new FileInfo(keyFilePath);
var fileLength = fileInfo.Length;
// Mehrfaches Überschreiben (DoD 5220.22-M Standard)
using (var fs = new FileStream(keyFilePath, FileMode.Open, FileAccess.Write))
{
var buffer = new byte[4096];
// Pass 1: Mit 0x00 überschreiben
OverwriteFile(fs, fileLength, 0x00);
// Pass 2: Mit 0xFF überschreiben
OverwriteFile(fs, fileLength, 0xFF);
// Pass 3: Mit Zufallsdaten überschreiben
OverwriteFileRandom(fs, fileLength);
// Pass 4: Nochmals mit 0x00
OverwriteFile(fs, fileLength, 0x00);
fs.Flush();
}
// Datei umbenennen (Metadaten verschleiern)
var randomName = Path.Combine(
Path.GetDirectoryName(keyFilePath),
Guid.NewGuid().ToString()
);
File.Move(keyFilePath, randomName);
// Datei löschen
File.Delete(randomName);
Console.WriteLine($"Schlüsseldatei sicher gelöscht: {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-Beispiel: Vollständige Vernichtung mit Protokoll =====
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. Abhängigkeiten prüfen
await ValidateDestructionAsync(keyId, certificate);
// 2. Aktiven Schlüssel vernichten
await DestroyPrimaryKeyAsync(keyId, certificate);
// 3. Alle Backups vernichten
if (options.DestroyBackups)
{
await DestroyBackupsAsync(keyId, certificate);
}
// 4. HSM-Schlüssel vernichten
if (options.DestroyHsmKeys)
{
await DestroyHsmKeyAsync(keyId, certificate);
}
// 5. Audit-Log erstellen
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(
"Schlüssel {KeyId} erfolgreich vernichtet. Zertifikat: {DestructionId}",
keyId, certificate.DestructionId);
return certificate;
}
catch (Exception ex)
{
certificate.Status = DestructionStatus.Failed;
certificate.Error = ex.Message;
_logger.LogError(ex, "Schlüsselvernichtung fehlgeschlagen: {KeyId}", keyId);
throw;
}
}
private async Task ValidateDestructionAsync(string keyId, DestructionCertificate cert)
{
// Prüfen ob noch aktive Zertifikate existieren
var activeCerts = await _certStore.FindByKeyIdAsync(keyId);
if (activeCerts.Any(c => c.NotAfter > DateTime.UtcNow))
{
throw new InvalidOperationException(
$"Schlüssel {keyId} wird noch von {activeCerts.Count} aktiven Zertifikaten verwendet");
}
cert.ValidationsPassed.Add("Keine aktiven Zertifikate");
// Prüfen ob Aufbewahrungsfrist abgelaufen
var metadata = await _keyStore.GetMetadataAsync(keyId);
if (metadata.RetentionUntil > DateTime.UtcNow)
{
throw new InvalidOperationException(
$"Aufbewahrungsfrist läuft bis {metadata.RetentionUntil:d}");
}
cert.ValidationsPassed.Add("Aufbewahrungsfrist abgelaufen");
}
private async Task DestroyPrimaryKeyAsync(string keyId, DestructionCertificate cert)
{
var keyPath = await _keyStore.GetPathAsync(keyId);
var destruction = new SecureKeyDestruction();
// Schlüssel laden und Fingerprint für Zertifikat speichern
var keyData = await File.ReadAllBytesAsync(keyPath);
cert.KeyFingerprint = Convert.ToHexString(SHA256.HashData(keyData)).Substring(0, 32);
// Sicher vernichten
destruction.DestroyKeyOnDisk(keyPath);
destruction.DestroyKeyInMemory(keyData);
cert.PrimaryKeyDestroyed = true;
cert.DestroyedLocations.Add(keyPath);
}
private async Task DestroyBackupsAsync(string keyId, DestructionCertificate cert)
{
var backupLocations = await _backupStore.FindBackupsAsync(keyId);
var destruction = new SecureKeyDestruction();
foreach (var backupPath in backupLocations)
{
destruction.DestroyKeyOnDisk(backupPath);
cert.DestroyedLocations.Add(backupPath);
}
cert.BackupsDestroyed = backupLocations.Count;
}
private async Task DestroyHsmKeyAsync(string keyId, DestructionCertificate cert)
{
// HSM-Key löschen (PKCS#11)
using var pkcs11 = new Pkcs11Library(_hsmConfig.LibraryPath);
var slot = pkcs11.GetSlotList(SlotsType.WithTokenPresent).First();
using var session = slot.OpenSession(SessionType.ReadWrite);
session.Login(CKU.CKU_USER, _hsmConfig.UserPin);
try
{
var key = session.FindAllObjects(new List
{
new ObjectAttribute(CKA.CKA_LABEL, keyId)
}).FirstOrDefault();
if (key != null)
{
session.DestroyObject(key);
cert.HsmKeyDestroyed = true;
cert.DestroyedLocations.Add($"HSM:{keyId}");
}
}
finally
{
session.Logout();
}
}
}
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
}
----
===== Code-Beispiel: DPAPI-Schlüssel vernichten =====
public class DpapiKeyDestruction
{
public void DestroyDpapiKey(string keyId)
{
var keyPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"WvdS", "Keys",
$"{keyId}.dpapi"
);
if (!File.Exists(keyPath))
{
Console.WriteLine($"DPAPI-Key nicht gefunden: {keyId}");
return;
}
var destruction = new SecureKeyDestruction();
// Datei sicher löschen
destruction.DestroyKeyOnDisk(keyPath);
// Auch evtl. Registry-Einträge entfernen
try
{
using var key = Registry.CurrentUser.OpenSubKey(
@"Software\WvdS\CryptoKeys", writable: true);
key?.DeleteValue(keyId, throwOnMissingValue: false);
}
catch (Exception ex)
{
Console.WriteLine($"Registry-Bereinigung fehlgeschlagen: {ex.Message}");
}
Console.WriteLine($"DPAPI-Key vernichtet: {keyId}");
}
}
----
===== Vernichtungsstandards =====
^ Standard ^ Überschreibungen ^ Pattern ^ Anwendung ^
| **DoD 5220.22-M** | 3 | 0x00, 0xFF, Random | US-Militär |
| **NIST SP 800-88** | 1-3 | Abhängig von Medientyp | US-Regierung |
| **BSI-TL 03423** | 3 | Random, 0x00, 0xFF | Deutsche Behörden |
| **Gutmann** | 35 | Verschiedene Pattern | Paranoid |
Für SSDs und Flash-Speicher: Sicheres Löschen erfordert spezielle Firmware-Befehle (TRIM, Secure Erase). Software-Überschreiben ist nicht zuverlässig!
----
===== Branchenspezifische Vernichtungsanforderungen =====
^ Branche ^ Anforderung ^ Zeugen ^ Dokumentation ^
| **Finanzsektor** | PCI-DSS 3.6.6 | 2 Personen | Vernichtungsprotokoll |
| **Healthcare** | HIPAA | 1 Zeuge | Audit-Log |
| **Behörden** | VS-NfD | Geheimschutzbeauftragter | Vernichtungsbescheinigung |
| **KRITIS** | BSI | 2 Personen | Zertifikat + Protokoll |
----
===== Verwandte Szenarien =====
^ Beziehung ^ Szenario ^ Beschreibung ^
| **Voraussetzung** | [[.:backup|11.4 Schlüssel-Backup]] | Alle Backups identifizieren |
| **Voraussetzung** | [[.:rotation|11.3 Schlüssel-Rotation]] | Neue Keys vor Vernichtung |
| **Verwandt** | [[de:int:pqcrypt:szenarien:widerruf:zertifikat_widerrufen|6.4 Zertifikat widerrufen]] | Vor Vernichtung widerrufen |
| **Verwandt** | [[de:int:pqcrypt:szenarien:verwaltung:archivierung|4.3 Archivierung]] | Alternative: Archivieren statt Vernichten |
----
<< [[.:backup|← 11.4 Schlüssel-Backup]] | [[.:start|↑ Schlüssel-Übersicht]] | [[de:int:pqcrypt:szenarien:start|→ Alle Szenarien]] >>
{{tag>szenario schluessel vernichtung sicherheit compliance audit}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//