MiniCurso : Criptografia na plataforma .NET - Aula 4


  Chaves Simétricas (Privada)

Para proteger a confidencialidade da informação transmitida/trocada , ela pode ser cifrada pelo remetente e decifrada pelo destinatário. Ambas as partes podem usar a mesma chave para cifrar e decifrar os dados usando um algoritmo de criptografia simétrica.

Assim um algoritmo de criptografia simétrica é um processo de criptografia em dois sentidos que usa a mesma chave para cifrar/decifrar a informação.

O emissor/remetente utiliza essa chave para cifrar a informação, e o receptor/destinatário utiliza a mesma chave para decifrá-la.  Assim as chaves são compartilhadas e por utilizar a mesma chave no processo ele é conhecido como criptografia simétrica.

 
 

A dificuldade é que as chaves necessitam ser enviadas de forma segura entre as partes, pois qualquer pessoa que possua a chave pode ter acesso à informação trocada/transmitida.

Os algoritmos de chave simétrica podem cair em duas categorias :

  1. Cifragem de fluxo (stream) - cada byte é cifrado um de cada vez;
  2. Cifragem de bloco - os dados são cifrados em blocos. Onde os blocos podem ser de tamanhos diferentes dependendo do algoritmo usado;

Nota:  O Advanced Encryption Standard (AES) utiliza a cifragem de bloco de 128 bits.

A seguir temos os algoritmos de criptografia simétrica incluídos na plataforma .NET

  1. DESCryptoServiceProvider
  2. RC2CryptoServiceProvider
  3. RijndaelManaged
  4. TripleDESCryptoServiceProvider

Os algoritmos AES, DES e Triple DES compartilham a classe base abstrata comum e todos herdam de SymmetricAlgorithm.

Dessa forma, uma informação sendo enviada de Maria para José onde os dois possuem acesso à mesma chave de encriptação(cifragem) pode ser cifrada por Maria.

Depois de receber a informação José pode usar o mesmo algoritmo para decifrar a informação preservando a confidencialidade da mesma.

Devido ao risco da chave ser interceptada durante a transmissão a integridade dos dados pode estar comprometida.

Outro problema enfrentado neste processo é o número de chaves necessárias para realizar a comunicação com mais de duas pessoas.

Se 3 pessoas desejam se comunicar usando chaves secretas serão necessárias 3 chaves  :

  1. Uma chave compartilhada entre a pessoa A e a pessoa B

  2. Uma chave compartilhada entre a pessoa A e a pessoa C

  3. Uma chave compartilhada entre a pessoa B e a pessoa C

Assim para realizar a comunicação entre n pessoas usando chaves privadas (secretas) seriam necessários (n) (n-1) / 2 chaves o que traz um grande problema de gerenciamento de chaves.

Uma tentativa de solucionar este problema é a criação de um centro de distribuição de chaves que faria a comunicação entre as pessoas aos pares, mas para isso a central de gerenciamento teria que possuir as chaves de todas as pessoas envolvidas no processo.

 Criando chaves Simétricas

Para começar vamos definir o conceito de cifras.

Uma cifra é definida sobre um par de algoritmos de encriptação (Enc) e um algoritmo de desencriptação (Des) da seguinte forma:

1- Processo de encriptação

  texto cifrado  = Encriptação( chave simétrica,  mensagem(texto plano) )   ou   tcf = Enc ( k, m)

2- Processo de desencriptação  

  mensagem(texto plano)  = Desencriptação( chave simétrica,  texto cifrado )  ou   m = Des ( k, tcf)

Vejamos a seguir uma aplicação prática definida na plataforma .NET.

Encriptação e desencriptação com chave simétrica usando o algoritmo Rijndael

Em Criptografia, o Advanced Encryption Standard (AES, ou Padrão de Criptografia Avançada), também conhecido por Rijndael, é uma cifra de bloco adotada como padrão de criptografia pelo governo dos Estados Unidos.

Na plataforma .NET temos que a classe RijndaelManaged é a implementação concreta desse algoritmo.

No exemplo vamos demonstrar como gerar uma chave simétrica usando o algoritmo Rijndael e usar essa chave para criptogragar e descriptografar uma cadeia de texto. A chave será derivada de várias características que iremos informar para a rotina.

Vamos criar uma aplicação do tipo Windows Forms Application  no Visual Studio Community 2015 e criar uma classe chamada Criptografia.

Nesta classe vamos implementar dois métodos estáticos (Shared) :

A seguir a implementação dos métodos Encriptar() e Descriptar() no VB .NET :

Public Shared Function Encriptar _
       (
           ByVal textoPlano As String,
           ByVal palavraPasse As String,
           ByVal valorSal As String,
           ByVal algoritmoHash As String,
           ByVal senhaIteracoes As Integer,
           ByVal vetorInicial As String,
           ByVal tamanhoChave As Integer
       ) _
       As String
        ' Converte strings em um array de byte
        ' Vamos assumir que a string contém somente código ASCII
        ' Se a string incluir caracteres Unicode, utilize o enconding UTF7 ou UTF8 
        Dim vetorInicialBytes As Byte()
        vetorInicialBytes = Encoding.ASCII.GetBytes(vetorInicial)
        Dim valorSalBytes As Byte()
        valorSalBytes = Encoding.ASCII.GetBytes(valorSal)
        ' Converte o texto contido em textoPlano.Text em um array de byte
        ' Vamos assumir que o texto contém somente caracteres UTF8-encoded
        Dim textoPlanoBytes As Byte()
        textoPlanoBytes = Encoding.UTF8.GetBytes(textoPlano)
        ' Primeiro precisamos criar uma senha a partir da qual a chave será derivada,
        ' Esta senha será gerada a partir da palavraPasse informada e o valor do sal.
        ' Ela será criada usando um algoritmo de hash especifico
        Dim password As PasswordDeriveBytes
        password = New PasswordDeriveBytes _
        (
            palavraPasse,
            valorSalBytes,
            algoritmoHash,
            senhaIteracoes
        )
        ' Usa a senha para gerar bytes para a chave de encriptação.
        ' Especifique o tamanho da chave em bytes
        Dim bytesChave As Byte()
        bytesChave = password.GetBytes(tamanhoChave / 8)
        ' Cria um objeto de encriptação Rijndael
        Dim chaveSimetrica As RijndaelManaged
        chaveSimetrica = New RijndaelManaged()
        ' Definindo o modo de cifratem para Block Chaining (CBC)
        chaveSimetrica.Mode = CipherMode.CBC
        ' Gera o encriptador a partri da chave existente e do vetor de inicialização.
        ' O tamanho da chave será defini basedo no número de bytes da chave
        Dim encriptador As ICryptoTransform
        encriptador = chaveSimetrica.CreateEncryptor(bytesChave, vetorInicialBytes)
        ' Define um memory stream o que será usado para tratar os dados cifrados
        Dim memoryStream As MemoryStream
        memoryStream = New MemoryStream()
        ' Define o stream criptrografico
        Dim cryptoStream As CryptoStream
        cryptoStream = New CryptoStream _
        (
            memoryStream,
            encriptador,
            CryptoStreamMode.Write
        )
        ' Inicia a cifragem
        cryptoStream.Write(textoPlanoBytes, 0, textoPlanoBytes.Length)
        ' Termina a cifragem
        cryptoStream.FlushFinalBlock()
        ' Converte os dados cifrados a partir dá memória em um array de byte
        Dim bytesTextoCifrado As Byte()
        bytesTextoCifrado = memoryStream.ToArray()
        ' fecha os streams
        memoryStream.Close()
        cryptoStream.Close()
        ' Converte os dados crifados em uma string base64-encoded.
        Dim textoCifrado As String
        textoCifrado = Convert.ToBase64String(bytesTextoCifrado)
        ' Retorna a string cifrada
        Encriptar = textoCifrado
    End Function
 Public Shared Function Descriptar _
       (
           ByVal textoCifrado As String,
           ByVal palavraPasse As String,
           ByVal valorSal As String,
           ByVal algoritmoHash As String,
           ByVal senhaIteracoes As Integer,
           ByVal vetorInicial As String,
           ByVal tamanhoChave As Integer
       ) _
       As String
        ' Converte strings definindo as caracteristicas da chave de encriptação em um array de bytes
        Dim vetorInicialBytes As Byte()
        vetorInicialBytes = Encoding.ASCII.GetBytes(vetorInicial)
        Dim valorSalBytes As Byte()
        valorSalBytes = Encoding.ASCII.GetBytes(valorSal)
        ' Converte o nosso textoCifrado em um array de byte
        Dim bytesTextoCifrado As Byte()
        bytesTextoCifrado = Convert.FromBase64String(textoCifrado)
        ' Primeiro precisamos criar uma senha a partir da qual a chave será derivada,
        ' Esta senha será gerada a partir da palavraPasse informada e o valor do sal.
        ' Ela será criada usando um algoritmo de hash especifico
        Dim password As PasswordDeriveBytes
        password = New PasswordDeriveBytes _
        (
            palavraPasse,
            valorSalBytes,
            algoritmoHash,
            senhaIteracoes
        )
        ' Usa a senha para gerar bytes para a chave de encriptação.
        ' Especifique o tamanho da cahve em bytes
        Dim bytesChave As Byte()
        bytesChave = password.GetBytes(tamanhoChave / 8)
        ' Cria um objeto Rijndael
        Dim chaveSimetrica As RijndaelManaged
        chaveSimetrica = New RijndaelManaged()
        ' Definindo o modo de cifratem para Block Chaining (CBC)
        chaveSimetrica.Mode = CipherMode.CBC
        ' Gera o  descriptador a partir dos bytes da chave existente e do vetor de inicialização
        ' O tamanho da cahve será definido com base no número de bytes da chave
        Dim descriptador As ICryptoTransform
        descriptador = chaveSimetrica.CreateDecryptor(bytesChave, vetorInicialBytes)
        ' Define um memory stream o que será usado para tratar os dados cifrados
        Dim memoryStream As MemoryStream
        memoryStream = New MemoryStream(bytesTextoCifrado)
        ' Define um memory stream que sera usado para tratar os dados cifrados
        Dim cryptoStream As CryptoStream
        cryptoStream = New CryptoStream _
        (
            memoryStream,
            descriptador,
            CryptoStreamMode.Read
        )
        ' Como não sabemos o tamanho dos dados decifrados
        ' alocamos o buffer com o tamanho suficiente para tratar os dados
        Dim textoPlanoBytes As Byte()
        ReDim textoPlanoBytes(bytesTextoCifrado.Length)
        ' Inicia a desencriptação
        Dim contadorByteDescriptado As Integer
        contadorByteDescriptado = cryptoStream.Read _
        (
            textoPlanoBytes,
            0,
            textoPlanoBytes.Length
        )
        ' fecha os streams
        memoryStream.Close()
        cryptoStream.Close()
        ' Converte o dado decifrado em uma string
        Dim textoPlano As String
        textoPlano = Encoding.UTF8.GetString _
        (
            textoPlanoBytes,
            0,
            contadorByteDescriptado
        )
        ' Retorna a string decifrada
        Descriptar = textoPlano
    End Function

Para testar a nossa implementação vamos incluir no formulário form1.vb  os seguintes controles:

Conforme o leiaute da figura abaixo:

A seguir defina o código abaixo para este formulário:

Public Class Form1
    Dim plainText As String
    Dim cipherText As String
    Dim palavraPasse As String = "Pas5pr@se"              ' pode ser qualquer string
    Dim valorSal As String = "s@1tValue"                      ' pode ser qualquer string
    Dim algoritmoHash As String = "SHA1"                  ' pode ser MD5
    Dim senhaIteracoes As Integer = 2
    Dim vetorInicial As String = "@1B2c3D4e5F6g7H8"   ' tem que ser 16 bytes
    Dim tamanhoChave As Integer = 256                        ' pode ser 192 ou 128
    Private Sub btnCifrar_Click(sender As Object, e As EventArgs) Handles btnCifrar.Click
        If txtTexto.Text = String.Empty Then
            MessageBox.Show("Informe o texto")
            Return
        Else
            txtTextoCifrado.Text = ""
            txtTextoCifrado.Text = Criptografia.Encriptar(txtTexto.Text,
                                                          palavraPasse,
                                                          valorSal,
                                                          algoritmoHash,
                                                          senhaIteracoes,
                                                          vetorInicial,
                                                          tamanhoChave)
        End If
    End Sub
    Private Sub bnDecifrar_Click(sender As Object, e As EventArgs) Handles bnDecifrar.Click
        If txtTextoCifrado.Text = String.Empty Then
            MessageBox.Show("Não existe texto cifrado a decifrar")
            Return
        Else
            txtTextoDecifrado.Text = ""
            txtTextoDecifrado.Text = Criptografia.Descriptar(txtTextoCifrado.Text,
                                                          palavraPasse,
                                                          valorSal,
                                                          algoritmoHash,
                                                          senhaIteracoes,
                                                          vetorInicial,
                                                          tamanhoChave)
        End If
    End Sub
End Class

Observe que estamos definindo alguns valores padrão para os parâmetros usados pelo método Encriptar().

Executando o projeto e realizando as operações de cifragem e decifragem iremos obter o seguinte resultado:

Pegue o projeto completo com as implementações feitas em CSharp e VB .NET aqui : CriptografiaChaveSimetrica.zip

Na próxima aula vamos continuar a ver as demais técnicas de criptografia.

Na verdade, na verdade vos digo que quem ouve a minha palavra, e crê naquele que me enviou, tem a vida eterna, e não entrará em condenação, mas passou da morte para a vida.
João 5:24

Referências :


José Carlos Macoratti