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