SignatureExtensions

Namespace: WvdS.System.Security.Cryptography.Signatures

Estensioni Drop-In Replacement per firme digitali con supporto Post-Quantum. Estende RSA, ECDsa e X509Certificate2 con funzioni di firma ibride PQ.

Panoramica

Questa classe offre tre tipi di firme:

Modalita Classico ML-DSA Utilizzo
Classic - Comportamento standard .NET
Hybrid Massima sicurezza
PostQuantum - Puramente post-quantum

RSA SignData/VerifyData

using var rsa = RSA.Create(2048);
byte[] data = Encoding.UTF8.GetBytes("Dati importanti");
 
// Firmare con modalita esplicita
byte[] signature = rsa.SignData(
    data,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1,
    CryptoMode.Hybrid);
 
// Verificare
bool isValid = rsa.VerifyData(
    data,
    signature,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1,
    CryptoMode.Hybrid);

Firma Stream

using var fileStream = File.OpenRead("document.pdf");
 
byte[] signature = rsa.SignData(
    fileStream,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1,
    CryptoMode.Hybrid);

ECDsa SignData/VerifyData

using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
byte[] data = GetDataToSign();
 
// Firmare
byte[] signature = ecdsa.SignData(
    data,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);
 
// Verificare
bool isValid = ecdsa.VerifyData(
    data,
    signature,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);

Firme basate su certificato

var certificate = GetSigningCertificate();
byte[] data = GetDataToSign();
 
// Firmare (utilizza automaticamente RSA o ECDSA)
byte[] signature = certificate.SignData(
    data,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);
 
// Verificare
bool isValid = certificate.VerifyData(
    data,
    signature,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);

Il tipo di chiave viene rilevato automaticamente:

  • Certificato RSA → RSA.SignData + ML-DSA
  • Certificato ECDSA → ECDsa.SignData + ML-DSA

Standalone ML-DSA

Firme ML-DSA dirette senza chiave classica:

// Generare coppia di chiavi
var (publicKey, privateKey) = SignatureExtensions.GenerateMlDsaKeyPair();
 
// Firmare
byte[] data = GetDataToSign();
byte[] signature = SignatureExtensions.SignMlDsa(data, privateKey);
 
// Verificare
bool isValid = SignatureExtensions.VerifyMlDsa(data, signature, publicKey);

Formato firma ibrida

┌────────────────────────────────────────────┐
│ [4 Bytes] Lunghezza firma classica         │
│ [n Bytes] Firma classica (RSA/ECDSA)       │
│ [m Bytes] Firma PQ (ML-DSA-65)             │
└────────────────────────────────────────────┘
Componente Dimensione tipica
Campo lunghezza 4 Bytes
Firma RSA-2048 256 Bytes
Firma ECDSA P-256 ~70 Bytes
Firma ML-DSA-65 3.293 Bytes
Hybrid RSA ~3.553 Bytes
Hybrid ECDSA ~3.367 Bytes

Chiavi PQ transienti

Per firme standalone (senza certificato) vengono utilizzate chiavi transienti thread-local:

// Impostare proprie chiavi
var (pubKey, privKey) = SignatureExtensions.GenerateMlDsaKeyPair();
SignatureExtensions.SetTransientPqKey(pubKey, privKey);
 
// Ora SignData/VerifyData possono essere utilizzati senza certificato
byte[] sig = rsa.SignData(data, HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1, CryptoMode.Hybrid);
 
// Solo chiave pubblica per verifica
SignatureExtensions.SetTransientPqPublicKey(pubKey);
bool valid = rsa.VerifyData(data, sig, HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1, CryptoMode.Hybrid);
 
// Pulizia (sovrascrive la chiave privata con zeri)
SignatureExtensions.ClearTransientPqKey();

Panoramica metodi

Estensioni RSA

Metodo Parametri Ritorno
SignData(data, hash, padding, mode) byte[], HashAlgorithmName, RSASignaturePadding, CryptoMode? byte[]
SignData(stream, hash, padding, mode) Stream, HashAlgorithmName, RSASignaturePadding, CryptoMode? byte[]
VerifyData(data, sig, hash, padding, mode) byte[], byte[], HashAlgorithmName, RSASignaturePadding, CryptoMode? bool

Estensioni ECDsa

Metodo Parametri Ritorno
SignData(data, hash, mode) byte[], HashAlgorithmName, CryptoMode? byte[]
SignData(stream, hash, mode) Stream, HashAlgorithmName, CryptoMode? byte[]
VerifyData(data, sig, hash, mode) byte[], byte[], HashAlgorithmName, CryptoMode? bool

Estensioni X509Certificate2

Metodo Parametri Ritorno
SignData(data, hash, mode) byte[], HashAlgorithmName, CryptoMode? byte[]
VerifyData(data, sig, hash, mode) byte[], byte[], HashAlgorithmName, CryptoMode? bool

Standalone ML-DSA

Metodo Parametri Ritorno
GenerateMlDsaKeyPair() - (byte[] PublicKey, byte[] PrivateKey)
SignMlDsa(data, privateKey) byte[], byte[] byte[]
VerifyMlDsa(data, sig, publicKey) byte[], byte[], byte[] bool

Gestione chiavi transienti

Metodo Descrizione
SetTransientPqKey(pub, priv) Imposta coppia di chiavi per thread
SetTransientPqPublicKey(pub) Imposta solo chiave pubblica
ClearTransientPqKey() Cancella chiavi in modo sicuro

Esempio: Workflow completo

// 1. Configurare CryptoMode
CryptoConfig.DefaultMode = CryptoMode.Hybrid;
 
// 2. Caricare certificato (con chiavi PQ)
var cert = X509Certificate2ExportExtensions.ImportPfx(
    "signing-cert.pfx",
    "password");
 
// 3. Firmare documento
byte[] documentData = File.ReadAllBytes("contract.pdf");
byte[] signature = cert.SignData(documentData, HashAlgorithmName.SHA256);
 
// 4. Salvare firma
File.WriteAllBytes("contract.sig", signature);
 
// 5. Verificare successivamente
var verifyCert = new X509Certificate2("signing-cert.cer");
bool isValid = verifyCert.VerifyData(
    File.ReadAllBytes("contract.pdf"),
    File.ReadAllBytes("contract.sig"),
    HashAlgorithmName.SHA256);
 
Console.WriteLine($"Firma valida: {isValid}");

Note di sicurezza

  • In modalita PostQuantum non viene creata alcuna firma classica - non retrocompatibile
  • Le chiavi transienti vengono memorizzate thread-local - non condividere tra thread
  • Chiamare ClearTransientPqKey() quando le chiavi non sono piu necessarie

Vedi anche


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: il 30/01/2026 alle 00:12