~~NOTOC~~ ====== Scenario 11.2: Archiviazione chiavi ====== **Categoria:** [[.:start|Gestione chiavi]] \\ **Complessità:** Alta \\ **Prerequisiti:** Chiavi generate \\ **Tempo stimato:** 20-30 minuti ---- ===== Descrizione ===== Questo scenario descrive l'**archiviazione sicura delle chiavi crittografiche**. La protezione delle chiavi private è essenziale - chiavi compromesse mettono a rischio tutti i certificati e le firme basati su di esse. **Opzioni di archiviazione:** ^ Opzione ^ Sicurezza ^ Costi ^ Applicazione ^ | **Filesystem (crittografato)** | Media | Basso | Sviluppo, Test | | **Windows DPAPI** | Buona | Basso | Windows Server | | **Azure Key Vault** | Alta | Medio | Cloud | | **HashiCorp Vault** | Alta | Medio | On-Premise/Cloud | | **HSM** | Molto alta | Alto | CA, Sistemi critici | ---- ===== Workflow ===== flowchart TD KEY[Chiave privata] --> ENCRYPT[Crittografare] ENCRYPT --> ACL[Controllo accessi] ACL --> STORE{Ubicazione} STORE --> FILE[Filesystem] STORE --> VAULT[Key Vault] STORE --> HSM[HSM] FILE --> BACKUP[Backup] VAULT --> BACKUP HSM --> BACKUP style ENCRYPT fill:#fff3e0 style ACL fill:#e8f5e9 ---- ===== Esempio codice: File crittografato (PEM) ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using var ctx = PqCryptoContext.Initialize(); // Generare chiave using var keyPair = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65); // Salvare come PEM crittografato (PKCS#8) keyPair.ToEncryptedPemFile( path: "private-key.pem", password: "StrongPassword123!", pbeAlgorithm: PbeAlgorithm.Aes256Cbc, prf: PbePrf.HmacSha256, iterations: 100000 // Iterazioni PBKDF2 ); // Chiave pubblica (non crittografata, condivisibile pubblicamente) keyPair.PublicKey.ToPemFile("public-key.pem"); Console.WriteLine("Chiavi salvate:"); Console.WriteLine(" Privata: private-key.pem (crittografata AES-256-CBC)"); Console.WriteLine(" Pubblica: public-key.pem"); ---- ===== Esempio codice: Windows DPAPI ===== using System.Security.Cryptography; public class DpapiKeyStorage { private readonly string _keyStorePath; public DpapiKeyStorage(string basePath = null) { _keyStorePath = basePath ?? Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WvdS", "Keys" ); Directory.CreateDirectory(_keyStorePath); } public void StoreKey(string keyId, byte[] privateKey, DataProtectionScope scope = DataProtectionScope.CurrentUser) { // Crittografare con DPAPI var protectedData = ProtectedData.Protect( privateKey, entropy: Encoding.UTF8.GetBytes(keyId), // Entropia aggiuntiva scope: scope ); var keyPath = Path.Combine(_keyStorePath, $"{keyId}.dpapi"); File.WriteAllBytes(keyPath, protectedData); // Impostare ACL (solo utente corrente) var fileSecurity = new FileSecurity(); fileSecurity.SetAccessRuleProtection(true, false); // Disabilitare ereditarietà fileSecurity.AddAccessRule(new FileSystemAccessRule( Environment.UserName, FileSystemRights.Read | FileSystemRights.Write, AccessControlType.Allow )); var fileInfo = new FileInfo(keyPath); fileInfo.SetAccessControl(fileSecurity); Console.WriteLine($"Chiave salvata con DPAPI: {keyPath}"); } public byte[] LoadKey(string keyId, DataProtectionScope scope = DataProtectionScope.CurrentUser) { var keyPath = Path.Combine(_keyStorePath, $"{keyId}.dpapi"); if (!File.Exists(keyPath)) { throw new FileNotFoundException($"Chiave non trovata: {keyId}"); } var protectedData = File.ReadAllBytes(keyPath); return ProtectedData.Unprotect( protectedData, entropy: Encoding.UTF8.GetBytes(keyId), scope: scope ); } public void DeleteKey(string keyId) { var keyPath = Path.Combine(_keyStorePath, $"{keyId}.dpapi"); if (File.Exists(keyPath)) { // Cancellazione sicura: sovrascrivere prima di eliminare var fileLength = new FileInfo(keyPath).Length; using (var fs = new FileStream(keyPath, FileMode.Open, FileAccess.Write)) { var zeros = new byte[fileLength]; fs.Write(zeros, 0, zeros.Length); fs.Flush(); } File.Delete(keyPath); Console.WriteLine($"Chiave eliminata: {keyId}"); } } } ---- ===== Esempio codice: Azure Key Vault ===== using Azure.Security.KeyVault.Keys; using Azure.Security.KeyVault.Keys.Cryptography; using Azure.Identity; public class AzureKeyVaultStorage { private readonly KeyClient _keyClient; private readonly string _vaultUrl; public AzureKeyVaultStorage(string vaultUrl) { _vaultUrl = vaultUrl; _keyClient = new KeyClient( new Uri(vaultUrl), new DefaultAzureCredential() ); } public async Task StoreKeyAsync(string keyName, byte[] privateKeyPkcs8) { // Salvare chiave come Secret (per chiavi PQ) var secretClient = new SecretClient( new Uri(_vaultUrl), new DefaultAzureCredential() ); var base64Key = Convert.ToBase64String(privateKeyPkcs8); await secretClient.SetSecretAsync(keyName, base64Key); Console.WriteLine($"Chiave salvata in Key Vault: {keyName}"); return keyName; } public async Task LoadKeyAsync(string keyName) { var secretClient = new SecretClient( new Uri(_vaultUrl), new DefaultAzureCredential() ); var secret = await secretClient.GetSecretAsync(keyName); return Convert.FromBase64String(secret.Value.Value); } public async Task RotateKeyAsync(string keyName, byte[] newPrivateKey) { // Creare nuovo secret (versionato) await StoreKeyAsync(keyName, newPrivateKey); // La vecchia versione rimane disponibile come backup Console.WriteLine($"Chiave ruotata: {keyName}"); } } ---- ===== Esempio codice: HashiCorp Vault ===== using VaultSharp; using VaultSharp.V1.AuthMethods.Token; public class HashiCorpVaultStorage { private readonly IVaultClient _vaultClient; private readonly string _mountPath; public HashiCorpVaultStorage(string vaultAddress, string token, string mountPath = "secret") { var authMethod = new TokenAuthMethodInfo(token); var settings = new VaultClientSettings(vaultAddress, authMethod); _vaultClient = new VaultClient(settings); _mountPath = mountPath; } public async Task StoreKeyAsync(string keyPath, byte[] privateKey, Dictionary metadata = null) { var secretData = new Dictionary { ["privateKey"] = Convert.ToBase64String(privateKey), ["algorithm"] = "ML-DSA-65", ["createdAt"] = DateTime.UtcNow.ToString("O") }; if (metadata != null) { foreach (var (key, value) in metadata) { secretData[key] = value; } } await _vaultClient.V1.Secrets.KeyValue.V2.WriteSecretAsync( path: keyPath, data: secretData, mountPoint: _mountPath ); Console.WriteLine($"Chiave salvata in Vault: {keyPath}"); } public async Task LoadKeyAsync(string keyPath) { var secret = await _vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync( path: keyPath, mountPoint: _mountPath ); var base64Key = secret.Data.Data["privateKey"].ToString(); return Convert.FromBase64String(base64Key); } public async Task> ListKeysAsync(string prefix = "") { var list = await _vaultClient.V1.Secrets.KeyValue.V2.ReadSecretPathsAsync( path: prefix, mountPoint: _mountPath ); return list.Data.Keys; } } ---- ===== Integrazione HSM (PKCS#11) ===== public class HsmKeyStorage { private readonly string _pkcs11LibPath; private readonly string _tokenLabel; public HsmKeyStorage(string pkcs11LibPath, string tokenLabel) { _pkcs11LibPath = pkcs11LibPath; _tokenLabel = tokenLabel; } public void StoreKey(string keyLabel, byte[] privateKey, string userPin) { using var pkcs11Library = new Pkcs11Library(_pkcs11LibPath); var slot = pkcs11Library.GetSlotList(SlotsType.WithTokenPresent) .First(s => s.GetTokenInfo().Label.Trim() == _tokenLabel); using var session = slot.OpenSession(SessionType.ReadWrite); session.Login(CKU.CKU_USER, userPin); try { var keyAttributes = new List { new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY), new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_GENERIC_SECRET), new ObjectAttribute(CKA.CKA_TOKEN, true), new ObjectAttribute(CKA.CKA_PRIVATE, true), new ObjectAttribute(CKA.CKA_SENSITIVE, true), new ObjectAttribute(CKA.CKA_EXTRACTABLE, false), // Non esportabile! new ObjectAttribute(CKA.CKA_LABEL, keyLabel), new ObjectAttribute(CKA.CKA_VALUE, privateKey) }; session.CreateObject(keyAttributes); Console.WriteLine($"Chiave salvata in HSM: {keyLabel}"); } finally { // Sovrascrivere dati chiave in memoria Array.Clear(privateKey, 0, privateKey.Length); session.Logout(); } } } ---- ===== Requisiti di archiviazione specifici per settore ===== ^ Settore ^ Ubicazione ^ Crittografia ^ Controllo accessi ^ | **Sviluppo** | Filesystem | PKCS#8 | Permessi file | | **Enterprise** | Key Vault / Vault | AES-256 | RBAC | | **Finanza** | HSM (FIPS 140-3) | Hardware | Multi-persona | | **Sanità** | HSM o Vault | AES-256 | Audit-Log | | **CA/PKI** | HSM | Hardware | Quorum n-of-m | ---- ===== Scenari correlati ===== ^ Relazione ^ Scenario ^ Descrizione ^ | **Prerequisito** | [[.:generierung|11.1 Generazione chiavi]] | Creare chiavi | | **Passo successivo** | [[.:rotation|11.3 Rotazione chiavi]] | Scambio regolare | | **Correlato** | [[.:backup|11.4 Backup chiavi]] | Copie di sicurezza | | **Correlato** | [[.:vernichtung|11.5 Distruzione chiavi]] | Cancellazione sicura | ---- << [[.:generierung|11.1 Generazione chiavi]] | [[.:start|Panoramica chiavi]] | [[.:rotation|11.3 Rotazione chiavi]] >> {{tag>scenario chiave archiviazione dpapi vault hsm}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//