~~NOTOC~~ ====== Scenario 11.4: Backup chiavi ====== **Categoria:** [[.:start|Gestione chiavi]] \\ **Complessità:** Alta \\ **Prerequisiti:** Chiavi generate, infrastruttura di backup \\ **Tempo stimato:** 25-35 minuti ---- ===== Descrizione ===== Questo scenario descrive il **backup sicuro delle chiavi crittografiche**. Un concetto di backup ben pianificato è fondamentale per la Business Continuity e il Disaster Recovery. **Strategie di backup:** * **Backup crittografato** - AES-256 o PQ-ibrido * **Key Splitting** - Shamir's Secret Sharing * **Distribuzione geografica** - Più sedi * **Backup offline** - Sistemi air-gapped * **Backup HSM** - Basato su hardware ---- ===== Workflow ===== flowchart TD KEY[Chiave privata] --> ENCRYPT[Crittografare] ENCRYPT --> SPLIT{Splitting?} SPLIT -->|Sì| SHAMIR[Shamir Split n-of-m] SPLIT -->|No| SINGLE[Backup singolo] SHAMIR --> DIST[Distribuire] SINGLE --> STORE[Salvare] DIST --> LOC1[Sede 1] DIST --> LOC2[Sede 2] DIST --> LOC3[Sede 3] STORE --> OFFSITE[Offsite Storage] LOC1 --> VERIFY[Test Restore] LOC2 --> VERIFY LOC3 --> VERIFY OFFSITE --> VERIFY style ENCRYPT fill:#fff3e0 style VERIFY fill:#e8f5e9 ---- ===== Esempio codice: Backup crittografato ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography; public class KeyBackupService { public void CreateEncryptedBackup( AsymmetricAlgorithm privateKey, string backupPath, string backupPassword, BackupOptions options = null) { options ??= BackupOptions.Default; using var ctx = PqCryptoContext.Initialize(); // 1. Esportare chiave privata come PKCS#8 byte[] pkcs8 = privateKey switch { RSA rsa => rsa.ExportPkcs8PrivateKey(), ECDsa ecdsa => ecdsa.ExportPkcs8PrivateKey(), _ => ctx.ExportPrivateKey(privateKey) }; // 2. Derivare Key Encryption Key (KEK) var salt = RandomNumberGenerator.GetBytes(32); var kek = ctx.DeriveKey( backupPassword, salt, outputLength: 32, algorithm: KeyDerivationAlgorithm.Argon2id, iterations: 4, memoryKiB: 65536, parallelism: 4 ); // 3. Crittografare con AES-256-GCM var nonce = RandomNumberGenerator.GetBytes(12); var ciphertext = new byte[pkcs8.Length]; var tag = new byte[16]; using var aes = new OpenSslAesGcm(kek); aes.Encrypt(nonce, pkcs8, ciphertext, tag); // 4. Creare file backup var backup = new KeyBackup { Version = 1, Algorithm = "ML-DSA-65", CreatedAt = DateTime.UtcNow, KdfAlgorithm = "Argon2id", KdfSalt = Convert.ToBase64String(salt), KdfIterations = 4, KdfMemoryKiB = 65536, EncryptionAlgorithm = "AES-256-GCM", Nonce = Convert.ToBase64String(nonce), Tag = Convert.ToBase64String(tag), EncryptedKey = Convert.ToBase64String(ciphertext), Checksum = ComputeChecksum(pkcs8) }; // 5. Salvare come JSON var json = JsonSerializer.Serialize(backup, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(backupPath, json); // 6. Pulire memoria CryptographicOperations.ZeroMemory(pkcs8); CryptographicOperations.ZeroMemory(kek); Console.WriteLine($"Backup creato: {backupPath}"); Console.WriteLine($" Checksum: {backup.Checksum}"); } public AsymmetricAlgorithm RestoreFromBackup( string backupPath, string backupPassword) { using var ctx = PqCryptoContext.Initialize(); // 1. Caricare backup var json = File.ReadAllText(backupPath); var backup = JsonSerializer.Deserialize(json); // 2. Derivare KEK (stessi parametri del backup) var salt = Convert.FromBase64String(backup.KdfSalt); var kek = ctx.DeriveKey( backupPassword, salt, outputLength: 32, algorithm: KeyDerivationAlgorithm.Argon2id, iterations: backup.KdfIterations, memoryKiB: backup.KdfMemoryKiB, parallelism: 4 ); // 3. Decrittografare var nonce = Convert.FromBase64String(backup.Nonce); var tag = Convert.FromBase64String(backup.Tag); var ciphertext = Convert.FromBase64String(backup.EncryptedKey); var pkcs8 = new byte[ciphertext.Length]; using var aes = new OpenSslAesGcm(kek); aes.Decrypt(nonce, ciphertext, tag, pkcs8); // 4. Verificare checksum var checksum = ComputeChecksum(pkcs8); if (checksum != backup.Checksum) { throw new CryptographicException("Checksum backup non valido"); } // 5. Importare chiave var key = ctx.ImportPrivateKey(pkcs8, backup.Algorithm); CryptographicOperations.ZeroMemory(pkcs8); CryptographicOperations.ZeroMemory(kek); Console.WriteLine($"Backup ripristinato: {backup.Algorithm}"); return key; } private string ComputeChecksum(byte[] data) { var hash = SHA256.HashData(data); return Convert.ToHexString(hash).Substring(0, 16); } } public class KeyBackup { public int Version { get; set; } public string Algorithm { get; set; } public DateTime CreatedAt { get; set; } public string KdfAlgorithm { get; set; } public string KdfSalt { get; set; } public int KdfIterations { get; set; } public int KdfMemoryKiB { get; set; } public string EncryptionAlgorithm { get; set; } public string Nonce { get; set; } public string Tag { get; set; } public string EncryptedKey { get; set; } public string Checksum { get; set; } } ---- ===== Esempio codice: Shamir Secret Sharing ===== using SecretSharingDotNet.Cryptography; public class ShamirKeyBackup { public ShamirShares SplitKey( byte[] privateKey, int totalShares, int threshold) { // Shamir's Secret Sharing: schema n-of-m // es. 3-of-5: necessari almeno 3 di 5 share var gf = new ExtendedEuclideanAlgorithm(); var shamir = new ShamirsSecretSharing(gf); // Chiave come BigInteger var secret = new BigInteger(privateKey, isUnsigned: true); // Dividere in share var shares = shamir.MakeShares( (uint)threshold, (uint)totalShares, secret ); var result = new ShamirShares { Threshold = threshold, TotalShares = totalShares, Shares = shares.Select((s, i) => new Share { Index = i + 1, Value = Convert.ToBase64String(s.Y.ToByteArray()) }).ToList() }; Console.WriteLine($"Chiave divisa in {totalShares} share (Threshold: {threshold})"); return result; } public byte[] RecombineKey(ShamirShares shares, List shareIndices) { if (shareIndices.Count < shares.Threshold) { throw new ArgumentException( $"Necessari almeno {shares.Threshold} share, ma presenti solo {shareIndices.Count}" ); } var gf = new ExtendedEuclideanAlgorithm(); var shamir = new ShamirsSecretSharing(gf); // Raccogliere share var selectedShares = shareIndices .Select(i => shares.Shares.First(s => s.Index == i)) .Select(s => new FinitePoint( s.Index, new BigInteger(Convert.FromBase64String(s.Value), isUnsigned: true) )) .ToArray(); // Ricostruire segreto var secret = shamir.Reconstruction(selectedShares); return secret.ToByteArray(); } public void DistributeShares(ShamirShares shares, string[] recipients) { // Distribuire share a diverse persone/sedi for (int i = 0; i < shares.Shares.Count && i < recipients.Length; i++) { var share = shares.Shares[i]; var recipient = recipients[i]; // In pratica: inviare crittografato al destinatario Console.WriteLine($"Share {share.Index} → {recipient}"); // Esempio: come codice QR o chiavetta USB var shareFile = $"share-{share.Index}-{recipient.Replace(" ", "_")}.json"; File.WriteAllText(shareFile, JsonSerializer.Serialize(share)); } } } public class ShamirShares { public int Threshold { get; set; } public int TotalShares { get; set; } public List Shares { get; set; } } public class Share { public int Index { get; set; } public string Value { get; set; } } ---- ===== Strategia di backup per tipo di chiave ===== ^ Tipo chiave ^ Metodo backup ^ Copie ^ Sedi ^ Conservazione ^ | **Root-CA** | Shamir 3-of-5 + HSM | 5 | 3 geo-distribuite | Permanente | | **Intermediate-CA** | Encrypted + HSM | 3 | 2 sedi | 10 anni | | **TLS Server** | Encrypted | 2 | Datacenter + Offsite | 2 anni | | **Code Signing** | Shamir 2-of-3 | 3 | 2 sedi | 5 anni | | **User Keys** | Encrypted | 2 | Locale + Cloud | 1 anno | ---- ===== Requisiti di backup specifici per settore ===== ^ Settore ^ Requisito ^ Metodo ^ Particolarità ^ | **Finanza** | PCI-DSS | HSM + Dual Control | Obbligo Audit-Log | | **Sanità** | HIPAA | Key Escrow | Accesso per emergenze | | **Enti pubblici** | VS-NfD | Cassaforte + 2 persone | Responsabile protezione segreti | | **Energia** | KRITIS | Backup offline | Sistema air-gapped | ---- ===== Scenari correlati ===== ^ Relazione ^ Scenario ^ Descrizione ^ | **Prerequisito** | [[.:speicherung|11.2 Archiviazione chiavi]] | Conservare chiavi in sicurezza | | **Correlato** | [[.:rotation|11.3 Rotazione chiavi]] | Backup prima della rotazione | | **Passo successivo** | [[.:vernichtung|11.5 Distruzione chiavi]] | Eliminare backup vecchi | | **Correlato** | [[it:int:pqcrypt:szenarien:verwaltung:backup|4.4 Backup certificati]] | Backup certificati | ---- << [[.:rotation|11.3 Rotazione chiavi]] | [[.:start|Panoramica chiavi]] | [[.:vernichtung|11.5 Distruzione chiavi]] >> {{tag>scenario chiave backup shamir disaster-recovery hsm}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//