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