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

Microsoft [anunció el soporte de criptografía post cuántica para Windows](https://techcommunity.microsoft.com/blog/microsoft-security-blog/post-quantum-cryptography-comes-to-windows-insiders-and-linux/4413803) 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](https://www.ninjaone.com/blog/change-windows-insider-program-channels-in-windows-11/#:~:text=Canary%20channel:%20This%20previews%20highly,but%20still%20have%20low%20stability.), 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”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1760488660962/49b1d21f-7ce8-403d-a91d-41b0cb389756.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1760488628764/e1f917b3-1a02-47b6-9e71-1832e7432f60.png align="center")

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](https://dotnet.microsoft.com/en-us/download/dotnet/10.0).

# 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

```csharp
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

```csharp
// ------------------------------------------------------------------
// 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

```csharp
// 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}");
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1760488147663/69b5a5f4-4e7f-4558-af2e-ed8f3cb2850a.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1760488181077/26aedd22-95db-47bb-8e4d-f57118668adb.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1760488206956/df06414e-e9ed-43f6-a58d-f245e0f3c089.png align="center")

# 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.
