Partilhar via


Visão geral de criptografia, assinaturas digitais e algoritmos de hash no .NET

Este artigo fornece uma visão geral dos métodos e práticas de criptografia suportados pelo .NET, incluindo os manifestos ClickOnce.

Introdução à criptografia

As redes públicas, como a Internet, não fornecem um meio de comunicação seguro entre entidades. A comunicação através de tais redes é suscetível de ser lida ou mesmo modificada por terceiros não autorizados. A criptografia ajuda a proteger os dados de serem visualizados, fornece maneiras de detetar se os dados foram modificados e ajuda a fornecer um meio seguro de comunicação através de canais não seguros. Por exemplo, os dados podem ser encriptados usando um algoritmo criptográfico, transmitidos num estado encriptado e posteriormente desencriptados pela parte pretendida. Se um terceiro intercetar os dados criptografados, será difícil decifrar.

No .NET, as System.Security.Cryptography classes no namespace gerenciam muitos detalhes de criptografia para você. Alguns são wrappers para implementações de sistema operacional, enquanto outros são implementações puramente gerenciadas. Você não precisa ser um especialista em criptografia para usar essas classes. Quando você cria uma nova instância de uma das classes de algoritmo de criptografia, as chaves são geradas automaticamente para facilitar o uso e as propriedades padrão são tão seguras quanto possível.

Primitivos criptográficos

Em uma situação típica onde a criptografia é usada, duas partes (Alice e Bob) se comunicam por um canal não seguro. Alice e Bob querem garantir que a sua comunicação permaneça incompreensível por qualquer pessoa que possa estar a ouvir. Além disso, como Alice e Bob estão em locais remotos, Alice deve certificar-se de que a informação que recebe de Bob não foi modificada por ninguém durante a transmissão. Além disso, ela deve se certificar de que as informações realmente se originam de Bob e não de alguém que está se passando por Bob.

A criptografia é usada para atingir os seguintes objetivos:

  • Confidencialidade: para ajudar a proteger a identidade ou os dados de um utilizador contra a leitura.

  • Integridade dos dados: para ajudar a proteger os dados contra alterações.

  • Autenticação: para garantir que os dados são originários de uma parte específica.

  • Não repúdio: Para evitar que uma determinada parte negue que enviou uma mensagem.

Para atingir esses objetivos, você pode usar uma combinação de algoritmos e práticas conhecidas como primitivos criptográficos para criar um esquema criptográfico. A tabela a seguir lista as primitivas criptográficas e seus usos.

Primitiva criptográfica Utilizar
Encriptação de chave secreta (encriptação simétrica) Executa uma transformação nos dados para evitar que sejam lidos por terceiros. Este tipo de encriptação utiliza uma única chave secreta partilhada para encriptar e desencriptar dados.
Encriptação de chave pública (encriptação assimétrica) Executa uma transformação nos dados para evitar que sejam lidos por terceiros. Este tipo de encriptação utiliza um par de chaves pública/privada para encriptar e desencriptar dados.
Assinatura criptográfica Ajuda a verificar se os dados são originários de uma parte específica, criando uma assinatura digital exclusiva para essa parte. Esse processo também usa funções hash.
Hashes criptográficos Mapeia dados de qualquer comprimento para uma sequência de bytes de comprimento fixo. Os hashes são estatisticamente únicos; uma sequência de dois bytes diferente não terá hash para o mesmo valor.

Criptografia de chave secreta

Os algoritmos de encriptação de chave secreta usam uma única chave secreta para encriptar e desencriptar dados. Você deve proteger a chave contra o acesso por agentes não autorizados, porque qualquer parte que tenha a chave pode usá-la para descriptografar seus dados ou criptografar seus próprios dados, alegando que eles se originaram de você.

A criptografia de chave secreta também é conhecida como criptografia simétrica porque a mesma chave é usada para criptografia e descriptografia. Os algoritmos de criptografia de chave secreta são muito rápidos (em comparação com algoritmos de chave pública) e são adequados para executar transformações criptográficas em grandes fluxos de dados. Os algoritmos de encriptação assimétrica, como o RSA, são limitados matematicamente na quantidade de dados que podem encriptar. Os algoritmos de encriptação simétrica geralmente não têm esses problemas.

Um tipo de algoritmo de chave secreta chamado cifra de bloco é usado para criptografar um bloco de dados de cada vez. Cifras de bloco, como Data Encryption Standard (DES), TripleDES e Advanced Encryption Standard (AES), transformam criptograficamente um bloco de entrada de n bytes em um bloco de saída de bytes criptografados. Se quiser encriptar ou desencriptar uma sequência de bytes, tem de o fazer bloco a bloco. Como n é pequeno (8 bytes para DES e TripleDES; 16 bytes [o padrão], 24 bytes ou 32 bytes para AES), os valores de dados maiores que n precisam ser criptografados um bloco de cada vez. Os valores de dados menores que n precisam ser expandidos para n para serem processados.

Uma forma simples de cifra de bloco é chamada de modo de livro de códigos eletrônico (ECB). O modo ECB não é considerado seguro, porque não usa um vetor de inicialização para inicializar o primeiro bloco de texto sem formatação. Para uma determinada chave secreta k, uma cifra de bloco simples que não usa um vetor de inicialização criptografará o mesmo bloco de entrada de texto sem formatação no mesmo bloco de saída de texto cifrado. Portanto, se você tiver blocos duplicados em seu fluxo de texto sem formatação de entrada, você terá blocos duplicados em seu fluxo de texto cifrado de saída. Esses blocos de saída duplicados alertam os usuários não autorizados sobre a criptografia fraca usada, os algoritmos que podem ter sido empregados e os possíveis modos de ataque. O modo de cifra do BCE é, portanto, bastante vulnerável à análise e, em última análise, à descoberta de chaves.

As classes de codificação de bloco fornecidas na biblioteca de classes base usam um modo de encadeamento padrão chamado encadeamento de blocos de codificação (CBC), embora você possa alterar esse padrão se desejar.

As cifras CBC superam os problemas associados às cifras do BCE usando um vetor de inicialização (IV) para criptografar o primeiro bloco de texto sem formatação. Cada bloco subsequente de texto simples passa por uma operação OR (XOR) exclusiva bit a bit com o bloco de texto cifrado anterior antes de ser criptografado. Cada bloco de texto cifrado é, portanto, dependente de todos os blocos anteriores. Quando esse sistema é usado, cabeçalhos de mensagens comuns que podem ser conhecidos por um usuário não autorizado não podem ser usados para fazer engenharia reversa de uma chave.

Uma maneira de comprometer os dados criptografados com uma cifra CBC é realizar uma pesquisa exaustiva de todas as chaves possíveis. Dependendo do tamanho da chave que é usada para executar a criptografia, esse tipo de pesquisa é muito demorado usando até mesmo os computadores mais rápidos e, portanto, é inviável. Tamanhos de chave maiores são mais difíceis de decifrar. Embora a criptografia não torne teoricamente impossível para um adversário recuperar os dados criptografados, ela aumenta o custo de fazer isso. Se forem necessários três meses para realizar uma pesquisa exaustiva para recuperar dados que são significativos apenas por alguns dias, o método de pesquisa exaustiva é impraticável.

A desvantagem da criptografia de chave secreta é que ela presume que duas partes concordaram com uma chave e IV, e comunicaram seus valores. O IV não é considerado um segredo e pode ser transmitido em texto simples com a mensagem. No entanto, a chave deve ser mantida em segredo de usuários não autorizados. Devido a esses problemas, a criptografia de chave secreta é frequentemente usada em conjunto com a criptografia de chave pública para comunicar de forma privada os valores da chave e do IV.

Supondo que Alice e Bob são duas partes que querem se comunicar através de um canal não seguro, eles podem usar criptografia de chave secreta da seguinte forma: Alice e Bob concordam em usar um algoritmo específico (AES, por exemplo) com uma chave específica e IV. Alice compõe uma mensagem e cria um fluxo de rede (talvez um pipe nomeado ou e-mail de rede) para enviar a mensagem. Em seguida, ela criptografa o texto usando a chave e IV, e envia a mensagem criptografada e IV para Bob pela intranet. Bob recebe o texto encriptado e desencripta-o usando a chave IV e previamente acordada. Se a transmissão for intercetada, o intercetador não pode recuperar a mensagem original, porque eles não sabem a chave. Nesse cenário, apenas a chave deve permanecer secreta. Em um cenário do mundo real, Alice ou Bob gera uma chave secreta e usa criptografia de chave pública (assimétrica) para transferir a chave secreta (simétrica) para a outra parte. Para obter mais informações sobre criptografia de chave pública, consulte a próxima seção.

O .NET fornece as seguintes classes que implementam algoritmos de criptografia de chave secreta:

  • Aes

  • HMACSHA256HMACSHA512e HMACSHA384 . (Estes são tecnicamente algoritmos de chave secreta porque representam códigos de autenticação de mensagem que são calculados usando uma função hash criptográfica combinada com uma chave secreta. Consulte Valores de hash, mais adiante neste artigo.)

Encriptação de Chave Pública

A criptografia de chave pública usa uma chave privada que deve ser mantida em segredo de usuários não autorizados e uma chave pública que pode ser tornada pública para qualquer pessoa. A chave pública e a chave privada estão matematicamente ligadas; Os dados encriptados com a chave pública só podem ser desencriptados com a chave privada e os dados assinados com a chave privada só podem ser verificados com a chave pública. A chave pública pode ser disponibilizada a qualquer pessoa; Ele é usado para criptografar dados a serem enviados para o detentor da chave privada. Os algoritmos criptográficos de chave pública também são conhecidos como algoritmos assimétricos porque uma chave é necessária para criptografar dados e outra chave é necessária para descriptografar dados. Uma regra criptográfica básica proíbe a reutilização de chaves, e ambas as chaves devem ser exclusivas para cada sessão de comunicação. No entanto, na prática, as chaves assimétricas são geralmente de longa duração.

Duas partes (Alice e Bob) podem usar a criptografia de chave pública da seguinte maneira: Primeiro, Alice gera um par de chaves públicas/privadas. Se Bob quiser enviar uma mensagem encriptada a Alice, pede-lhe a sua chave pública. Alice envia a Bob sua chave pública através de uma rede não segura, e Bob usa essa chave para criptografar uma mensagem. Bob envia a mensagem encriptada para Alice e ela desencripta-a usando a sua chave privada. Se Bob recebeu a chave de Alice através de um canal não seguro, como uma rede pública, Bob está aberto a um ataque man-in-the-middle. Portanto, Bob deve verificar com Alice se ele tem uma cópia correta de sua chave pública.

Durante a transmissão da chave pública de Alice, um agente não autorizado pode intercetar a chave. Além disso, o mesmo agente pode intercetar a mensagem criptografada de Bob. No entanto, o agente não pode desencriptar a mensagem com a chave pública. A mensagem só pode ser desencriptada com a chave privada de Alice, que não foi transmitida. Alice não usa sua chave privada para criptografar uma mensagem de resposta para Bob, porque qualquer pessoa com a chave pública pode descriptografar a mensagem. Se Alice quiser enviar uma mensagem de volta para Bob, ela pede a Bob sua chave pública e criptografa sua mensagem usando essa chave pública. Bob então descriptografa a mensagem usando sua chave privada associada.

Nesse cenário, Alice e Bob usam criptografia de chave pública (assimétrica) para transferir uma chave secreta (simétrica) e usam criptografia de chave secreta para o restante da sessão.

A lista a seguir oferece comparações entre algoritmos criptográficos de chave pública e de chave secreta:

  • Os algoritmos criptográficos de chave pública usam um tamanho de buffer fixo, enquanto os algoritmos criptográficos de chave secreta usam um buffer de comprimento variável.

  • Os algoritmos de chave pública não podem ser usados para encadear dados em fluxos da mesma forma que os algoritmos de chave secreta, porque apenas pequenas quantidades de dados podem ser criptografadas. Portanto, as operações assimétricas não usam o mesmo modelo de streaming que as operações simétricas.

  • A criptografia de chave pública tem um espaço de chave muito maior (intervalo de valores possíveis para a chave) do que a criptografia de chave secreta. Portanto, a criptografia de chave pública é menos suscetível a ataques exaustivos que tentam todas as chaves possíveis.

  • As chaves públicas são fáceis de distribuir porque não precisam ser protegidas, desde que exista alguma maneira de verificar a identidade do remetente.

  • Alguns algoritmos de chave pública (como RSA e DSA, mas não Diffie-Hellman) podem ser usados para criar assinaturas digitais para verificar a identidade do remetente dos dados.

  • Os algoritmos de chave pública são muito lentos em comparação com os algoritmos de chave secreta e não são projetados para criptografar grandes quantidades de dados. Os algoritmos de chave pública são úteis apenas para transferir quantidades muito pequenas de dados. Normalmente, a criptografia de chave pública é usada para criptografar uma chave e IV para ser usada por um algoritmo de chave secreta. Depois que a chave e o IV são transferidos, a criptografia de chave secreta é usada para o restante da sessão.

O .NET fornece as seguintes classes que implementam algoritmos de chave pública:

O RSA permite criptografia e assinatura, mas o DSA só pode ser usado para assinatura. O DSA não é tão seguro quanto o RSA, e recomendamos o RSA. Diffie-Hellman pode ser usado apenas para geração de chaves. Em geral, os algoritmos de chave pública são mais limitados em seus usos do que os algoritmos de chave privada.

Assinaturas Digitais

Algoritmos de chave pública também podem ser usados para formar assinaturas digitais. As assinaturas digitais autenticam a identidade de um remetente (se você confiar na chave pública do remetente) e ajudam a proteger a integridade dos dados. Usando uma chave pública gerada por Alice, o destinatário dos dados de Alice pode verificar se Alice os enviou, comparando a assinatura digital com os dados de Alice e a chave pública de Alice.

Para usar a criptografia de chave pública para assinar digitalmente uma mensagem, Alice primeiro aplica um algoritmo de hash à mensagem para criar um resumo da mensagem. O resumo da mensagem é uma representação compacta e única dos dados. Alice então criptografa o resumo da mensagem com sua chave privada para criar sua assinatura pessoal. Ao receber a mensagem e a assinatura, Bob descriptografa a assinatura usando a chave pública de Alice para recuperar o resumo da mensagem e hashes a mensagem usando o mesmo algoritmo de hash que Alice usou. Se o resumo da mensagem que Bob calcula corresponder exatamente ao resumo da mensagem recebida de Alice, Bob tem certeza de que a mensagem veio do detentor da chave privada e que os dados não foram modificados. Se Bob confia que Alice é a detentora da chave privada, ele sabe que a mensagem veio de Alice.

Nota

Uma assinatura pode ser verificada por qualquer pessoa porque a chave pública do remetente é de conhecimento comum e normalmente está incluída no formato de assinatura digital. Este método não mantém o sigilo da mensagem; Para que a mensagem seja secreta, ela também deve ser criptografada.

O .NET fornece as seguintes classes que implementam algoritmos de assinatura digital:

Valores de hash

Os algoritmos de hash mapeiam valores binários de um comprimento arbitrário para valores binários menores de um comprimento fixo, conhecidos como valores de hash. Um valor de hash é uma representação numérica de um pedaço de dados. Se você hash um parágrafo de texto sem formatação e alterar até mesmo uma letra do parágrafo, um hash subsequente produzirá um valor diferente. Se o hash for criptograficamente forte, seu valor mudará significativamente. Por exemplo, se um único bit de uma mensagem for alterado, uma função de hash forte pode produzir uma saída que difere em 50%. Muitos valores de entrada podem hash para o mesmo valor de saída. No entanto, é computacionalmente inviável encontrar duas entradas distintas que hash para o mesmo valor.

Duas partes (Alice e Bob) poderiam usar uma função hash para garantir a integridade da mensagem. Eles selecionariam um algoritmo de hash para assinar suas mensagens. Alice escrevia uma mensagem e, em seguida, criava um hash dessa mensagem usando o algoritmo selecionado. Em seguida, seguiriam um dos seguintes métodos:

  • Alice envia a mensagem de texto simples e a mensagem em hash (assinatura digital) para Bob. Bob recebe e faz hash da mensagem e compara seu valor de hash com o valor de hash que ele recebeu de Alice. Se os valores de hash forem idênticos, a mensagem não foi alterada. Se os valores não forem idênticos, a mensagem foi alterada depois que Alice a escreveu.

    Infelizmente, este método não estabelece a autenticidade do remetente. Qualquer pessoa pode fazer-se passar por Alice e enviar uma mensagem a Bob. Eles podem usar o mesmo algoritmo de hash para assinar sua mensagem, e tudo o que Bob pode determinar é que a mensagem corresponde à sua assinatura. Esta é uma forma de ataque man-in-the-middle. Para obter mais informações, consulte Exemplo de comunicação segura de próxima geração (CNG) de criptografia.

  • Alice envia a mensagem de texto simples para Bob através de um canal público não seguro. Ela envia a mensagem em hash para Bob através de um canal privado seguro. Bob recebe a mensagem de texto simples, faz hash e compara o hash com o hash trocado privadamente. Se os hashes corresponderem, Bob sabe duas coisas:

    • A mensagem não foi alterada.

    • O remetente da mensagem (Alice) é autêntico.

    Para que esse sistema funcione, Alice deve ocultar seu valor de hash original de todas as partes, exceto Bob.

  • Alice envia a mensagem de texto simples para Bob através de um canal público não seguro e coloca a mensagem em hash em seu site publicamente visível.

    Esse método impede a adulteração de mensagens, impedindo que qualquer pessoa modifique o valor de hash. Embora a mensagem e seu hash possam ser lidos por qualquer pessoa, o valor de hash só pode ser alterado por Alice. Um invasor que queira se passar por Alice precisaria ter acesso ao site de Alice.

Nenhum dos métodos anteriores impedirá alguém de ler as mensagens de Alice, porque elas são transmitidas em texto simples. A segurança total normalmente requer assinaturas digitais (assinatura de mensagens) e criptografia.

O .NET fornece as seguintes classes que implementam algoritmos de hash:

O .NET também fornece MD5 e SHA1. Mas os algoritmos MD5 e SHA-1 foram encontrados para ser inseguro, e SHA-2 agora é recomendado em vez disso. SHA-2 inclui SHA256, SHA384 e SHA512.

Geração de números aleatórios

A geração de números aleatórios é parte integrante de muitas operações criptográficas. Por exemplo, as chaves criptográficas precisam ser o mais aleatórias possível para que seja inviável reproduzi-las. Os geradores criptográficos de números aleatórios devem gerar resultados que sejam computacionalmente inviáveis de prever com uma probabilidade superior a metade. Portanto, qualquer método de prever o próximo bit de saída não deve ter um desempenho melhor do que a adivinhação aleatória. As classes no .NET usam geradores de números aleatórios para gerar chaves criptográficas.

A RandomNumberGenerator classe é uma implementação de um algoritmo gerador de números aleatórios.

Manifestos ClickOnce

As seguintes classes de criptografia permitem obter e verificar informações sobre assinaturas de manifesto para aplicativos que são implantados usando a tecnologia ClickOnce:

Além disso, as seguintes classes fornecem informações de assinatura específicas:

Classes de Criptografia de Próxima Geração (CNG)

As classes CNG (Cryptography Next Generation) fornecem um wrapper gerenciado em torno das funções CNG nativas. (CNG é o substituto para CryptoAPI.) Essas classes têm "Cng" como parte de seus nomes. Central para as classes de invólucro CNG é a CngKey classe de recipiente chave, que abstrai o armazenamento e o uso de chaves CNG. Essa classe permite armazenar um par de chaves ou uma chave pública com segurança e fazer referência a ela usando um nome de cadeia de caracteres simples. A classe de assinatura baseada em ECDsaCng curva elíptica e a ECDiffieHellmanCng classe de criptografia podem usar CngKey objetos.

A CngKey classe é usada para uma variedade de operações adicionais, incluindo abrir, criar, excluir e exportar chaves. Ele também fornece acesso ao identificador de chave subjacente para usar ao chamar funções nativas diretamente.

O .NET também inclui uma variedade de classes CNG de suporte, como as seguintes:

Consulte também