~~NOTOC~~ ====== Scenarij 11.3: Rotacija ključeva ====== **Kategorija:** [[.:start|Upravljanje ključevima]] \\ **Složenost:** ⭐⭐⭐⭐ (Visoka) \\ **Preduvjeti:** Postojeći ključevi, strategija sigurnosnog kopiranja \\ **Procijenjeno vrijeme:** 30-45 minuta ---- ===== Opis ===== Ovaj scenarij opisuje **redovitu rotaciju kriptografskih ključeva**. Rotacija ključeva je kritična sigurnosna mjera koja ograničava rizik kompromitacije. **Razlozi za rotaciju:** * **Vremenski** - Dosegnuta maksimalna životna dob ključa * **Količinski** - Maksimalan broj operacija/volumen podataka * **Sigurnosni incident** - Sumnja na kompromitaciju * **Usklađenost** - Regulatorni zahtjevi * **Nadogradnja algoritma** - Migracija na jače algoritme ---- ===== Tijek rada ===== flowchart TD TRIGGER[Okidač rotacije] --> CHECK{Rotacija potrebna?} CHECK -->|Ne| WAIT[Čekanje] CHECK -->|Da| BACKUP[Sigurnosna kopija starog ključa] BACKUP --> GEN[Generiranje novog ključa] GEN --> MIGRATE[Migracija sustava] MIGRATE --> TEST[Funkcionalni test] TEST --> OVERLAP{Preklapanje OK?} OVERLAP -->|Da| RETIRE[Deaktivacija starog ključa] OVERLAP -->|Ne| ROLLBACK[Rollback] RETIRE --> ARCHIVE[Arhiviranje/Brisanje] style GEN fill:#e8f5e9 style BACKUP fill:#fff3e0 ---- ===== Primjer koda: Automatska rotacija ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; public class KeyRotationService { private readonly IKeyStore _keyStore; private readonly TimeSpan _maxKeyAge = TimeSpan.FromDays(365); private readonly long _maxOperations = 1_000_000; public KeyRotationService(IKeyStore keyStore) { _keyStore = keyStore; } public async Task CheckAndRotateAsync(string keyId) { var metadata = await _keyStore.GetMetadataAsync(keyId); // Provjera uvjeta za rotaciju var needsRotation = ShouldRotate(metadata); if (!needsRotation.Required) { return new RotationResult { KeyId = keyId, Rotated = false, Reason = "Rotacija nije potrebna" }; } return await PerformRotationAsync(keyId, metadata, needsRotation.Reason); } private RotationCheck ShouldRotate(KeyMetadata metadata) { // 1. Vremenska rotacija if (DateTime.UtcNow - metadata.CreatedAt > _maxKeyAge) { return new RotationCheck(true, "Dosegnuta maksimalna starost"); } // 2. Količinska rotacija if (metadata.OperationCount > _maxOperations) { return new RotationCheck(true, "Dosegnut maksimalni broj operacija"); } // 3. Nadogradnja algoritma (RSA → ML-DSA) if (metadata.Algorithm.StartsWith("RSA") && !metadata.Algorithm.Contains("ML-DSA")) { return new RotationCheck(true, "Potrebna PQ-migracija"); } return new RotationCheck(false, null); } private async Task PerformRotationAsync( string keyId, KeyMetadata oldMetadata, string reason) { using var ctx = PqCryptoContext.Initialize(); // 1. Sigurnosna kopija starog ključa await _keyStore.BackupAsync(keyId); // 2. Generiranje novog ključa var newKeyId = $"{keyId}-{DateTime.UtcNow:yyyyMMdd}"; using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65); // 3. Pohrana novog ključa await _keyStore.StoreAsync(newKeyId, newKey, new KeyMetadata { Algorithm = "ML-DSA-65", CreatedAt = DateTime.UtcNow, PreviousKeyId = keyId, RotationReason = reason }); // 4. Označavanje starog ključa kao "u rotaciji" await _keyStore.SetStatusAsync(keyId, KeyStatus.Rotating); return new RotationResult { KeyId = keyId, NewKeyId = newKeyId, Rotated = true, Reason = reason }; } } ---- ===== Primjer koda: Faza preklapanja ===== public class OverlappingKeyManager { public async Task SignWithOverlap( byte[] data, string keyId, IKeyStore keyStore) { using var ctx = PqCryptoContext.Initialize(); // Učitavanje trenutnog ključa var currentKey = await keyStore.GetCurrentKeyAsync(keyId); // Potpisivanje s trenutnim ključem var signature = ctx.SignData( data, currentKey, HashAlgorithmName.SHA256 ); return signature; } public async Task VerifyWithOverlap( byte[] data, byte[] signature, string keyId, IKeyStore keyStore) { using var ctx = PqCryptoContext.Initialize(); // Dohvaćanje svih valjanih verzija ključa var validKeys = await keyStore.GetValidKeysAsync(keyId); foreach (var key in validKeys) { try { if (ctx.VerifyData(data, signature, key.PublicKey, HashAlgorithmName.SHA256)) { return true; } } catch (CryptographicException) { // Pogrešan ključ, pokušaj sljedeći continue; } } return false; } } ---- ===== Primjer koda: HashiCorp Vault rotacija ===== public class VaultKeyRotation { private readonly IVaultClient _vault; public async Task RotateKeyInVault(string keyPath) { // 1. Dohvaćanje trenutne verzije var current = await _vault.V1.Secrets.KeyValue.V2.ReadSecretAsync( path: keyPath, mountPoint: "secret" ); var currentVersion = current.Data.Metadata.Version; // 2. Generiranje novog ključa using var ctx = PqCryptoContext.Initialize(); using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65); // 3. Spremanje kao nova verzija (stara ostaje sačuvana) var secretData = new Dictionary { ["privateKey"] = Convert.ToBase64String(newKey.ExportPkcs8()), ["publicKey"] = Convert.ToBase64String(newKey.PublicKey.Export()), ["algorithm"] = "ML-DSA-65", ["rotatedAt"] = DateTime.UtcNow.ToString("O"), ["previousVersion"] = currentVersion }; await _vault.V1.Secrets.KeyValue.V2.WriteSecretAsync( path: keyPath, data: secretData, mountPoint: "secret" ); Console.WriteLine($"Ključ rotiran: {keyPath} v{currentVersion} → v{currentVersion + 1}"); } public async Task DestroyOldVersions(string keyPath, int keepVersions = 3) { // Brisanje starih verzija (Vault zadržava metapodatke) var metadata = await _vault.V1.Secrets.KeyValue.V2.ReadSecretMetadataAsync( path: keyPath, mountPoint: "secret" ); var currentVersion = metadata.Data.CurrentVersion; var versionsToDestroy = new List(); for (int v = 1; v < currentVersion - keepVersions; v++) { versionsToDestroy.Add(v); } if (versionsToDestroy.Any()) { await _vault.V1.Secrets.KeyValue.V2.DestroySecretVersionsAsync( path: keyPath, versions: versionsToDestroy, mountPoint: "secret" ); Console.WriteLine($"Stare verzije izbrisane: {string.Join(", ", versionsToDestroy)}"); } } } ---- ===== Smjernice za rotaciju ===== ^ Tip ključa ^ Maks. starost ^ Maks. operacije ^ Preklapanje ^ | **Root-CA ključ** | 10-20 godina | N/A | 1 godina | | **Intermediate-CA ključ** | 3-5 godina | N/A | 90 dana | | **TLS serverski ključ** | 1 godina | 10M rukovanja | 7 dana | | **Code Signing ključ** | 2 godine | 100K potpisa | 30 dana | | **Ključ za šifriranje** | 1 godina | 100TB podataka | 30 dana | ---- ===== Zahtjevi za rotaciju specifični za industriju ===== ^ Industrija ^ Ciklus rotacije ^ Zahtjev ^ Posebnost ^ | **Financijski sektor** | 1 godina | PCI-DSS 3.6.4 | Obvezni Audit-Trail | | **Zdravstvo** | 2 godine | HIPAA | Key Escrow | | **Energetika/KRITIS** | 3 godine | BSI KRITIS-VO | Prozor održavanja | | **Vlada** | 2 godine | BSI TR-03116 | Obvezni HSM | ---- ===== Povezani scenariji ===== ^ Povezanost ^ Scenarij ^ Opis ^ | **Preduvjet** | [[.:speicherung|11.2 Pohrana ključeva]] | Sigurno čuvanje | | **Preduvjet** | [[.:backup|11.4 Sigurnosna kopija ključeva]] | Sigurnosna kopija prije rotacije | | **Sljedeći korak** | [[.:vernichtung|11.5 Uništavanje ključeva]] | Brisanje starih ključeva | | **Povezano** | [[hr:int:pqcrypt:szenarien:verwaltung:rekey|4.2 Rekey]] | Certifikat s novim ključem | ---- << [[.:speicherung|← 11.2 Pohrana ključeva]] | [[.:start|↑ Pregled ključeva]] | [[.:backup|11.4 Sigurnosna kopija ključeva →]] >> {{tag>scenarij ključ rotacija životni-ciklus usklađenost}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//