Modelo de criptografía de .NET
.NET proporciona implementaciones de muchos algoritmos criptográficos estándar.
Herencia de objetos
La criptografía .NET implementa un patrón extensible de herencia de clases derivadas. La jerarquía es la siguiente:
Clase de tipo de algoritmo, como SymmetricAlgorithm, AsymmetricAlgorithm o HashAlgorithm. Este nivel es abstracto.
Clase de algoritmo que hereda de una clase de tipo de algoritmo, como, por ejemplo, Aes, RSA o ECDiffieHellman. Este nivel es abstracto.
Implementación de una clase de algoritmo que hereda de una clase de algoritmo, como, por ejemplo, AesManaged, RC2CryptoServiceProvider o ECDiffieHellmanCng. Este nivel está completamente implementado.
Este modelo de clases derivadas permite agregar un nuevo algoritmo o una nueva implementación de un algoritmo existente. Por ejemplo, para crear un nuevo algoritmo de clave pública, heredaría de la clase AsymmetricAlgorithm. Para crear una nueva implementación de un algoritmo específico, crearía una clase derivada no abstracta de ese algoritmo.
A partir de ahora, este modelo de herencia no se usará para nuevos tipos de primitivos, como AesGcm o Shake128. Estos algoritmos son sealed
. Si necesita un patrón de extensibilidad o abstracción sobre estos tipos, la implementación de la abstracción es responsabilidad del desarrollador.
API de un solo uso
A partir de .NET 5, se introdujeron API más sencillas para hashing y HMAC. Aunque son ligeramente menos flexibles, estas API de un solo uso:
- Son más fáciles de usar (y menos propensas a usos indebidos).
- Reducen las asignaciones o están exentas de ellas.
- Son seguras para los subprocesos.
- Usan la mejor implementación disponible para la plataforma.
Los primitivos hash y HMAC exponen una API de un solo uso través de un método HashData
estático en el tipo, como SHA256.HashData. Las API estáticas no ofrecen ningún mecanismo de extensibilidad integrado. Si va a implementar sus propios algoritmos, también es recomendable ofrecer API estáticas similares del algoritmo.
La clase RandomNumberGenerator también ofrece métodos estáticos para crear o rellenar búferes con datos aleatorios criptográficos. Estos métodos siempre usarán el generador de números pseudoaleatorios criptográficamente seguro (CSPRNG) del sistema.
Cómo se implementan los algoritmos en .NET
Como ejemplo de las distintas implementaciones disponibles de un algoritmo, considere los algoritmos simétricos. La base de todos los algoritmos simétricos es SymmetricAlgorithm, que hereda Aes, TripleDESy otras que ya no se recomiendan.
Aes es heredado por AesCryptoServiceProvider, AesCng y AesManaged.
En .NET Framework en Windows:
- Las clases de algoritmo
*CryptoServiceProvider
, como AesCryptoServiceProvider, son contenedores alrededor de la implementación de la API de criptografía de Windows (CAPI) de un algoritmo. - Las clases de algoritmo
*Cng
, como ECDiffieHellmanCng, son contenedores alrededor de la implementación de Windows Cryptography Next Generation (CNG). - Las clases
*Managed
, como AesManaged, se escriben completamente en código administrado. Las implementaciones*Managed
administradas no disponen del certificado de Estándares de procesamiento de información federal (FIPS) y pueden ser más lentas que las clases contenedoras*CryptoServiceProvider
y*Cng
.
En .NET Core y .NET 5 y versiones posteriores, todas las clases de implementación (*CryptoServiceProvider
, *Managed
y *Cng
) son contenedores para los algoritmos del sistema operativo (SO). Si los algoritmos del sistema operativo están certificados con FIPS, .NET usa algoritmos certificados con FIPS. Para obtener más información, consulte el artículo sobre proyectos multiplataforma de criptografía.
En la mayoría de los casos, no es necesario hacer referencia directamente a una clase de implementación de algoritmo, como AesCryptoServiceProvider
. Los métodos y propiedades que normalmente necesita se encuentran en la clase de algoritmo base, como Aes
. Cree una instancia de una clase de implementación predeterminada mediante un método factory en la clase de algoritmo base y haga referencia a la clase de algoritmo base. Por ejemplo, vea la línea de código resaltada en el ejemplo siguiente:
using System.Security.Cryptography;
try
{
using (FileStream fileStream = new("TestData.txt", FileMode.OpenOrCreate))
{
using (Aes aes = Aes.Create())
{
byte[] key =
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16
};
aes.Key = key;
byte[] iv = aes.IV;
fileStream.Write(iv, 0, iv.Length);
using (CryptoStream cryptoStream = new(
fileStream,
aes.CreateEncryptor(),
CryptoStreamMode.Write))
{
// By default, the StreamWriter uses UTF-8 encoding.
// To change the text encoding, pass the desired encoding as the second parameter.
// For example, new StreamWriter(cryptoStream, Encoding.Unicode).
using (StreamWriter encryptWriter = new(cryptoStream))
{
encryptWriter.WriteLine("Hello World!");
}
}
}
}
Console.WriteLine("The file was encrypted.");
}
catch (Exception ex)
{
Console.WriteLine($"The encryption failed. {ex}");
}
Imports System
Imports System.IO
Imports System.Security.Cryptography
Module Module1
Sub Main()
Try
' Create a file stream
Using fileStream As New FileStream("TestData.txt", FileMode.OpenOrCreate)
' Create a new instance of the default Aes implementation class
' and configure encryption key.
Using aes As Aes = Aes.Create()
'Encryption key used to encrypt the stream.
'The same value must be used to encrypt and decrypt the stream.
Dim key As Byte() = {
&H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8,
&H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16
}
aes.Key = key
' Stores IV at the beginning of the file.
' This information will be used for decryption.
Dim iv As Byte() = aes.IV
fileStream.Write(iv, 0, iv.Length)
' Create a CryptoStream, pass it the FileStream, and encrypt
' it with the Aes class.
Using cryptoStream As New CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write)
' By default, the StreamWriter uses UTF-8 encoding.
' To change the text encoding, pass the desired encoding as the second parameter.
' For example, New StreamWriter(cryptoStream, Encoding.Unicode).
Using sWriter As New StreamWriter(cryptoStream)
'Write to the stream.
sWriter.WriteLine("Hello World!")
End Using
End Using
End Using
End Using
'Inform the user that the message was written
'to the stream.
Console.WriteLine("The text was encrypted.")
Catch
'Inform the user that an exception was raised.
Console.WriteLine("The encryption failed.")
Throw
End Try
End Sub
End Module
Selección de un algoritmo
Puede seleccionar un algoritmo por diferentes motivos: por ejemplo, para proteger la integridad de los datos, para proteger la privacidad de los datos o para generar una clave. Los algoritmos simétricos y hash están diseñados para proteger los datos por motivos de integridad (impedir los cambios) o por motivos de privacidad (impedir la visualización). Los algoritmos hash se usan principalmente para proteger la integridad de los datos.
Esta es una lista de los algoritmos recomendados en función de la aplicación:
- Privacidad de los datos:
- Integridad de los datos:
- Firma digital:
- Intercambio de claves:
- Generación de números aleatorios:
- Generar una clave a partir de una contraseña: