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