VB .NET  -  Armazenando o hash de senhas no registro do sistema


 Neste artigo vou mostrar uma alternativa para tratar informação sensível como senhas de uma forma mais segura armazenando o hash da senha no registro do sistema.

Essa abordagem pode ser usada se você desejar testar uma senha informada contra um valor armazenado, mas você não deseja que qualquer pessoa possa descubrir a senha usada.

A solução usada e mostrada neste artigo armazena o hash da senha no registro do sistema e testa a senha informada comparando seu hash contra e entrada do registro.

Vamos recordar os conceitos sobre Hash e sobre o Registro do sistema.

Hash

Um hash é uma seqüencia de letras ou números geradas por um algorítimo de Hash.

Na criptografia, o hash serve para garantir a integridade da mensagem, onde o gerador (ou emissor) da mensagem, submete-a a um algoritmo hash, o qual produzirá um valor hash.

Este valor é enviado junto com a mensagem para o destinatário. O destinatário fará a verificação da integridade da mensagem aplicando o mesmo algoritmo na mensagem original e obterá um valor hash que deverá ser igual ao valor hash gerado na origem.

O algoritmo hash é composto por fórmulas matemáticas complexas, para poder garantir a irreversibilidade e a unicidade do MD gerado - textos diferentes não produzem o mesmo MD. A alteração de um simples bit na mensagem gera um MD completamente diferente e o valor de conferência ("check-sum") muda se um único bit for alterado, acrescentado ou retirado da mensagem.

Registro

O registro do Windows é um banco de dados central que armazena as definições das configurações e outra informação exigida pelas aplicações. As duas únicas tarefas que você consegue fazer com o registro é ler e escrever nele.

Para poder trabalhar como registro a livraria .NET Framework fornece duas classes - Registy e RegistryKey.

Estas classes estão definidas no namespace - Microsoft.Win32 ; de forma que para que possamos usá-las devemos fazer referência a este namespace.

A classe Registry

Podemos definir as chaves do registro na seguinte ordem:

CurrentUser - Armazena informação sobre as preferências do usuário.
LocalMachine - Armazena a configuração da informação para a máquina local
ClassesRoot - Armazena informação sobre tipos e classes e suas propriedades.
Users - Armazena informação sobre a configuração padrão do usuário.
PerformanceData - Armazena informação de desempenho para os componentes de software.
CurrentConfig - Armazena informação sobre hardware.
DynData - Armazena dados dinâmicos.

A classe Registry contém membros que fornecem acesso as chaves do registro. Os membros correspondentes a cada um dos tipos das chaves acima citadas estão descritos abaixo:

ClassesRoot Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_CLASSES_ROOT
CurrentConfig Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_CURRENT_CONFIG
CurrentUser Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_CURRENT_USER
DynData Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_DYN_DATA
LocalMachine Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_LOCAL_MACHINE.
PerformanceData Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_PERFORMANCE_DATA
Users Retorna um tipo RegistryKey o qual fornece acesso a chave HKEY_USERS

Vamos usar essas informações para realizar duas tarefas :

  1. Armazenar o usuário e o hash da senha no registro do sistema

  2. Verificar se um usuário e senha informados conferem com os dados armazenados

Recursos usados:

Criando o projeto Windows Forms

Abra o VS 2015 Community e crie um novo projeto (File-> New Project) usando a linguagem VB .NET e o template Windows Forms Application.

No formulário padrão Form1.vb inclua os controles :

Disponha os controles conforme o leiaute da figura abaixo:

Criando a função com os métodos para armazenar e verificar a senha

A seguir vamos criar uma classe no projeto chamada Servicos.cs com o seguinte código :

Imports System.Security.Cryptography
Imports System.Text
Public Class Servicos
    Public Sub ArmazenaUsuarioSenha(ByVal nomeUsuario As String, ByVal senhaTexto As String)
        Try
           ' ----- Salva a senha cifrada no registro
          Dim hashSenha As String = GetHash(senhaTexto)
          My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\SenhaTeste", nomeUsuario, hashSenha)
        Catch ex As Exception
             Throw ex
        End Try
    End Sub
    Public Function VerificaSenha(ByVal nomeUsuario As String, ByVal senhaTexto As String) As Boolean
         Try
        ' ----- Verifica se o nome do usuário e senha passados conferem no registro
        Dim hashSenha As String = GetHash(senhaTexto)
        ' ----- Retorna qualquer valor armazenado
        Dim hashSenhaLido As String =
          Convert.ToString(My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Software\SenhaTeste", nomeUsuario, Nothing))
        ' ----- Compara as senhas
        If (hashSenhaLido = Nothing) Then
            ' ----- usuário inválido
            Return False
        ElseIf (hashSenhaLido = hashSenha) Then
            ' ----- usuário e senha ok
            Return True
        Else
            ' ----- Usuario ok, senha inválida
            Return False
        End If
        Catch ex As Exception
             Throw ex
        End Try
    End Function
    Public Function GetHash(ByVal texto As String) As String
        ' ----- Gera o hash e retorna uma string vazia se houver erros
        Dim plainBytes As Byte()
        Dim hashEngine As MD5CryptoServiceProvider
        Dim hashBytes As Byte()
        Dim hashTexto As String
        Try
            ' ----- Converte o texto para um array de bytes
            plainBytes = Encoding.UTF8.GetBytes(texto)
            ' ----- Selecione um engine para hash
            hashEngine = New MD5CryptoServiceProvider
            ' ----- Pega o hash do texto em bytes.
            hashBytes = hashEngine.ComputeHash(plainBytes)
            ' ----- Converte o hash de bytes para uma string hexadecimal
            hashTexto = Replace(BitConverter.ToString(hashBytes), "-", "")
            Return hashTexto
        Catch
            Return ""
        End Try
    End Function
End Class

Nesta classe criamos os seguintes métodos:

  1. ArmazenaUsuarioSenha - armazena o hash da senha no registro do sistema em HKEY_CURRENT_USER\Software\SenhaTeste;

  2. VerificaSenha - verifica se a senha informada coincide com a armazenada no registro para o usuário informado;

  3. GetHash - Gera o hash para um texto informado usando o MD5CryptoServiceProvider;

Agora basta implementar no formulário do projeto o armazenamento e a verificação da senha.

Implementando o armazenamento e a verificação do hash

No formulário Form1.vb vamos começar criando uma instância da classe Servicos:

 Dim servico As New Servicos()

A seguir no evento Click do botão Armazenar no Registro inclua o código a seguir:

Private Sub btnArmazena_Click(sender As Object, e As EventArgs) Handles btnArmazena.Click
        If String.IsNullOrWhiteSpace(txtUsuario.Text) Then
            MessageBox.Show("Informe o nome do usuário")
            Return
        End If
        If String.IsNullOrWhiteSpace(txtSenha.Text) Then
            MessageBox.Show("Informe a senha")
            Return
        End If
        Try
            servico.ArmazenaUsuarioSenha(txtUsuario.Text, txtSenha.Text)
            MessageBox.Show("Usuário e senha armazenadas com sucesso no Registro")
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

 

No evento Click do botão Verificar inclua o código abaixo:

 Private Sub btnVerifica_Click(sender As Object, e As EventArgs) Handles btnVerifica.Click
        If String.IsNullOrWhiteSpace(txtUsuario1.Text) Then
            MessageBox.Show("Informe o nome do usuário")
            Return
        End If
        If String.IsNullOrWhiteSpace(txtSenha1.Text) Then
            MessageBox.Show("Informe a senha")
            Return
        End If
        Try
            If servico.VerificaSenha(txtUsuario1.Text, txtSenha1.Text) Then
                MessageBox.Show("Usuário e Senha informados conferem...")
            Else
                MessageBox.Show("Usuário e/ou Senha informados NÃO conferem...")
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

 

Executando projeto e armazenando uma senha e depois fazendo a verificação com uma senha incorreta iremos obter:

Pegue o projeto aqui :  Hash_Registro.zip (sem as referências)

Pois, assim como o Pai ressuscita os mortos, e os vivifica, assim também o Filho vivifica aqueles que quer.
E também o Pai a ninguém julga, mas deu ao Filho todo o juízo;
Para que todos honrem o Filho, como honram o Pai. Quem não honra o Filho, não honra o Pai que o enviou.

João 5:21-23

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti