Skip to main content

Command Palette

Search for a command to run...

Criptografía post-cuántica en .NET y Windows

Requerimientos y ejemplos para utilizar esta tecnología en plataformas de Microsoft

Updated
3 min read
Criptografía post-cuántica en .NET y Windows

Microsoft anunció el soporte de criptografía post cuántica para Windows recientemente. Este es un acontecimiento importante porque marca el inicio del soporte nativo en el sistema operativo en lugar de depender de herramientas de terceros.

Pre-requisitos

El soporte para PQC (Post-Quantum Cryptography) se introdujo en el build 27852 y superiores, esto quiere decir que antes de esta versión, si usted intenta abrir un archivo que utilizan estos algoritmos, Windows simplemente va a tirar un error indicando que el certificado tiene un formato inválido.

En la actualidad, la única forma de tener acceso a esa versión de Windows es mediante el Canary Channel, el cual da acceso a las capacidades mas recientes y experimentales de Windows. Es considerado altamente técnico puesto que muchos de los errores que se pueden encontrar podrían no tener una solución adecuada por parte de Microsoft.

Existen varias maneras de habilitar el Canary Channel de Windows, pero el mas sencillo es habilitarlo en el GUI de Windows Update, haciendo click en la pestaña de “Windows Insider Program”, y escogiendo el radio button de “Canary Channel”

El soporte formal para ML-KEM (Key Encapsulation), ML-DSA y SLH-DSA (Signature algorithms) se introdujo en .NET 10, por lo cual vamos a necesitar bajar e instalar la versión más reciente de .NET 10.

Procedimiento

Vamos a enfocarnos en ML-DSA, y el objetivo principal va a ser cubrir las funcionalidades básicas que ofrece esta clase utilizando el lenguaje C#.

Creando un certificado self-signed

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

var dsaAlgorithm = MLDsaAlgorithm.MLDsa65;
var hashAlgorithm = HashAlgorithmName.SHA512;
var subjectName = new X500DistinguishedName($"CN=ML-DSA-Certificate, O=ExampleOrg, C=US");

// Generación de la llave
MLDsa mldsaKey = MLDsa.GenerateKey(dsaAlgorithm);
CertificateRequest certRequest = new CertificateRequest(
    subjectName,
    mldsaKey
);
certRequest.CertificateExtensions.Add(
    new X509BasicConstraintsExtension(true, false, 0, true));
certRequest.CertificateExtensions.Add(
    new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign, true));

DateTimeOffset notBefore = DateTimeOffset.Now.AddDays(-1);
DateTimeOffset notAfter = DateTimeOffset.Now.AddYears(1);

// Creación del certificado
X509Certificate2 certificate = certRequest.CreateSelfSigned(notBefore, notAfter);

Firmando con el certificado y validando la firma

// ------------------------------------------------------------------
// Parte 1: Generando la firma
// ------------------------------------------------------------------

const string originalData = "Mensaje que quiero firmar usando la llave ML-DSA";
byte[] dataToSign = Encoding.UTF8.GetBytes(originalData);

// Definir el hash algorithm del certificado (que es diferente al de la llave)
HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256;

byte[] signatureContext = Encoding.UTF8.GetBytes("Application-Usage-V1");


// Accesar la llave privada del certificado
MLDsa mldsaPrivateKey = certificate.GetMLDsaPrivateKey();

if (mldsaPrivateKey == null)
{
    Console.WriteLine("\nERROR: No se puede obtener la llave privada del certificado.");
    return;
}

byte[] signature;
try
{
    Console.WriteLine("\n--- Firmando datos con la llave privada ---");

    // Llamando al método que firma los datos
    signature = mldsaPrivateKey.SignData(dataToSign, signatureContext);

    Console.WriteLine($"Firma exitosa, utilizando ({signature.Length} bytes).");
    Console.WriteLine($"Firma (Base64): {Convert.ToBase64String(signature).Substring(0, 32)}..."); // Mostrar un fragmento de la firma

}
catch (CryptographicException ex)
{
    Console.WriteLine($"\nERROR durante firma: {ex.Message}");
    return;
}


// ------------------------------------------------------------------
// Parte 2: Verificando la firma
// ------------------------------------------------------------------

// Cargar la llave pública
MLDsa mldsaPublicKey = certificate.GetMLDsaPublicKey();
if (mldsaPublicKey == null)
{
    Console.WriteLine("\nERROR: No se puede obtener la llave pública del certificado.");
    return;
}

// Verificación
Console.WriteLine("\n--- Validando la firma ---");
bool isValid = mldsaPublicKey.VerifyData(
    dataToSign,
    signature,
    signatureContext
);

if (isValid)
{
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("La firma digital es válida!");
}
else
{
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("La firma digital es inválida!");
}
Console.ResetColor();

// Clean up
mldsaPrivateKey.Dispose();
mldsaPublicKey.Dispose();

Exportando el certificado

// Salvar el certificado (incluyendo la llave privada) en un archivo PFX
string pfxFilePath = "mldsa_certificate.pfx";
string pfxPassword = "MySecurePassword";

// Exportar el certificado en un archivo
byte[] pfxBytes = certificate.Export(X509ContentType.Pfx, pfxPassword);
File.WriteAllBytes(pfxFilePath, pfxBytes);

Console.WriteLine($"\nEl certificado se salvó en: {Path.GetFullPath(pfxFilePath)}");
Console.WriteLine($"Contraseña: {pfxPassword}");

Conclusión

En este momento, el soporte para PQC por parte de Windows se encuentra apenas dando sus primeros pasos, sin embargo las bases han sido sentadas y es adecuado aprender sobre estas tecnologías dada la importancia que van a tomar en la segunda mitad de la década tecnológica de los 20s.