Compartilhar via


Modelo de criptografia do .NET

O .NET fornece implementações de muitos algoritmo de criptografia padrão.

Herança de objetos

O sistema de criptografia .NET implementa um padrão extensível de herança de classe derivada. A hierarquia é a seguinte:

Esse padrão de classes derivadas permite adicionar um algoritmo ou uma implementação de um algoritmo existente. Por exemplo, para criar um algoritmo de chave pública, você herdaria da classe AsymmetricAlgorithm. Para criar uma implementação de um algoritmo específico, você criaria uma classe derivada não abstrata desse algoritmo.

De agora em diante, esse modelo de herança não será mais utilizado para novos tipos de primitivos, como AesGcm ou Shake128. Esses algoritmos são sealed. Se você precisar de um padrão de extensibilidade ou abstração sobre esses tipos, a implementação da abstração será de responsabilidade do desenvolvedor.

APIs de um disparo

A partir do .NET 5, APIs mais simples foram introduzidas para hash e HMAC. Embora um pouco menos flexíveis, estas APIs de um disparo:

  • São mais fáceis de usar (e menos propensas a uso indevido)
  • Reduzem alocações ou são livres de alocação
  • São seguras para thread
  • Usam a melhor implementação disponível para a plataforma

Os primitivos de hash e HMAC expõem uma API de um disparo por meio de um método HashData estático no tipo, como SHA256.HashData. As APIs estáticas não oferecem nenhum mecanismo interno de extensibilidade. Se você estiver implementando seus próprios algoritmos, é recomendável oferecer também APIs estáticas semelhantes ao algoritmo.

A classe RandomNumberGenerator também oferece métodos estáticos para criar ou preencher buffers com dados criptográficos aleatórios. Esses métodos sempre utilizarão o gerador de números pseudoaleatórios criptograficamente seguro (CSPRNG) do sistema.

Como os algoritmos são implementados no .NET

Como exemplo das diferentes implementações disponíveis para um algoritmo, considere algoritmos simétricos. A base para todos os algoritmos simétricos é SymmetricAlgorithm, que é herdada por Aes, TripleDES e outras que não são mais recomendadas.

Aes é herdado por AesCryptoServiceProvider, AesCng e AesManaged.

No .NET Framework no Windows:

  • As classes de algoritmo *CryptoServiceProvider, como AesCryptoServiceProvider, são wrappers em torno da implementação da CAPI (API de Criptografia do Windows) de um algoritmo.
  • As classes de algoritmo *Cng, como ECDiffieHellmanCng, são wrappers em torno da implementação CNG (Cryptography Next Generation) do Windows.
  • As classes *Managed, como AesManaged, são escritas inteiramente em código gerenciado. As implementações de *Managed não são certificadas pelos FIPS (Padrões Federais de Processamento de Informações) e podem ser mais lentas do que as classes de wrapper *CryptoServiceProvider e *Cng.

No .NET Core e no .NET 5 e versões posteriores, todas as classes de implementação (*CryptoServiceProvider, *Managed e *Cng) são wrappers para os algoritmos do SO (sistema operacional). Se os algoritmos do SO forem certificados por FIPS, o .NET usará algoritmos certificados por FIPS. Para mais informações, confira Criptografia multiplataforma.

Na maioria dos casos, você não precisa fazer referência direta a uma classe de implementação de algoritmo, como AesCryptoServiceProvider. Os métodos e propriedades de que você normalmente precisa estão na classe de algoritmo base, como Aes. Crie uma instância de uma classe de implementação padrão usando um método de fábrica na classe de algoritmo base e confira a classe de algoritmo base. Por exemplo, confira a linha de código realçada no seguinte exemplo:

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

Selecionar um algoritmo

Você pode selecionar um algoritmo por motivos diferentes: por exemplo, para integridade dos dados, para privacidade de dados ou para gerar uma chave. Algoritmos simétricos e hash se destinam à proteção de dados por motivos de integridade (proteger contra alterações) ou de privacidade (proteger contra exibição). Os algoritmos de hash são usados principalmente para integridade dos dados.

Aqui está uma lista de algoritmos recomendados pelo aplicativo:

Confira também