Clique para saber mais...
  Home     Download     Produtos / Cursos     Revista     Vídeo Aulas     Fórum     Contato   Clique aqui para logar | 20 de Julho de 2026
  Login

Codinome
Senha
Salvar informações

 Esqueci minha senha
 Novo Cadastro

  Usuários
46 Usuários Online

  Revista ActiveDelphi
 Assine Já!
 Edições
 Sobre a Revista

  Conteúdo
 Apostilas
 Artigos
 Componentes
 Dicas
 News
 Programas / Exemplos
 Vídeo Aulas

  Serviços
 Active News
 Fórum
 Produtos / Cursos

  Outros
 Colunistas
 Contato
 Top 10

  Publicidade

  [Artigos]  Autenticação em bancos de dados usando RSA
Publicado por icemagno : Quinta, Outubro 21, 2004 - 09:17 GMT-3 (13966 leituras)
Comentários 3 Comentários   Enviar esta notícia a um amigo Enviar para um amigo   Versão para Impressão Versão para impressão
Carlos Magno Em artigos anteriores, mostrei como utilizar hash de MD5 para melhorar a segurança das senhas em bancos de dados. Neste artigo, utilizarei o RSA para criar arquivos que funcionarão como chaves para entrar em um sistema.
A idéia consiste em não armazenar a senha do usuário em nenhum local, nem criptografada, nem em forma de hash.
Um arquivo de chave será criado e o usuário só entrará no sistema se as seguintes condições forem satisfeitas:

a) Ele deverá possuir o arquivo de chave.
b) Ele deverá conhecer a senha do arquivo de chave.
c) Ele deverá estar cadastrado no banco de dados do sistema.
d) A sua chave deverá ser correspondente à chave do banco de dados.

Se qualquer uma das condições acima não for satisfeita, não será possível entrar no sistema.

Para exemplificar o artigo, criei um pequeno programa em Delphi 7, com um banco de dados Interbase. O exemplo poderá ser copiado de http://www.magnoabreu.kit.net, na parte de Delphi. O exemplo também utiliza a biblioteca criptográfica LockBox, uma das melhores que eu conheço que pertencia a TurboPower e agora está disponível com os fontes no SourceForge ou no mesmo link acima.

O uso do RSA foi comentado em meus artigos anteriores, onde foi mostrado que um dos itens que influenciam na segurança do algoritmo é a quantidade de bits em sua chave. Este é um algoritmo amplamente utilizado por bancos e sistemas operacionais, estando todos de comum acordo que as chaves de 1024 bits são suficientemente seguras para uma transação bancária ou uma operação de cartão de crédito. Chaves com menos bits são mais rápidas, mas são muito mais frágeis.

Primeiramente você deverá baixar e instalar a biblioteca de criptografia. Os componentes são instalados na paleta "LockBox". Não vou entrar em detalhes sobre os componentes nem sobre a instalação, pois não estão no escopo deste artigo.

Neste projeto, usarei três componentes Edit, três Labels, dois Buttons, um OpenDialog, um lbRSA, um IBDataBase, um IBTable e um IBTransaction.

Os componentes TEdit serão nomeados na ordem: edtNome, edtSenha e edtLogin. Cada Label irá acompanhar um Edit, rotulados respectivamente "Nome do usuário", "Senha do usuário" e "Senha de Login". Os dois botões serão nomeados "Criar Usuário" para btCriar e "Efetuar Login" para btLogin. Os componentes não-visuais poderão ficar com os nomes originais.

Organize os componentes em duas partes do Form: em cima, a criação do usuário e suas chaves, com edtNome, edtSenha e seus Labels, juntamente com o botão btCriar.
Na parte inferior, o exemplo de login, com btLogin, edtLogin e seu Label.

O banco de dados Interbase contém uma única tabela, com dois campos: NOME, do tipo varchar(100) e CHAVEPUBLICA, do tipo BLOB SUB_TYPE TEXT. Você deverá ter algum conhecimento sobre Interbase para configurar os componentes adequadamente, ou baixar o programa de exemplo, onde tudo já está pronto (inclusive o banco).

O primeiro passo será permitir a criação dos usuários e suas chaves. Cada usuário possuirá duas chaves: uma pública e uma secreta. A chave pública é a que ficará armazenada no banco de dados, enquanto a secreta será entregue ao usuário, onde ele deverá trocar sua senha. As características das chaves RSA foram discutidas em artigo anterior. Quando o usuário tentar ingressar no sistema, ele irá apresentar seu arquivo com a chave secreta e mostrará ao sistema que ele é o dono desta chave, abrindo-a com sua senha. O sistema por sua vez, irá testar se este usuário existe no banco de dados, localizando seu nome e recuperando a chave pública. Em seguida, outro teste será feito: se a chave pública encontrada no banco é a correspondente à chave secreta apresentada. Para isso, uma frase aleatória (ou número) é gerada e criptografada com a chave pública. Pelas características do RSA, somente a chave secreta correspondente será capaz de decifrar a frase original. Tendo sucesso, o usuário é quem diz ser e ele faz parte do sistema.

No código do botão btCriar, crie as seguintes variáveis locais:

Var ChavePublica : TMemoryStream;
ChaveSecreta : String;


agora, o próximo passo é gerar um par de chaves quaisquer. Digite no código do btCriar:

// Gera um par de chaves
Screen.Cursor := crHourGlass;
lbRSA1.GenerateKeyPair;
Screen.Cursor := crDefault;

a mudança de cursor é necessária, pois a criação de chaves pode ser muito demorada. A minha máquina, um Pentium 1.3MHz com aproximadamente 260Mb de RAM demorou cerca de 2 minutos para gerar as chaves. A criptografia é mais rápida se implementada usando a linguagem C++.

Após as chaves serem geradas, elas precisarão receber suas senhas, antes de serem gravadas, pois ambas serão criptografadas utilizando o algoritmo AES. A senha da chave pública poderá ser uma constante do sistema, pois não há necessidade de ocultá-la (é pública!). Já a senha da chave secreta não deverá ser armazenada em parte alguma, pois somente a senha correta irá decifrar esta chave. Para cadastrar as senhas das chaves, continue digitando no código do botão btCriar:

// Cadastra senhas para as chaves. A pública pode ficar sem senha.
lbRSA1.PrivateKey.Passphrase := edtSenha.Text;
lbRSA1.PublicKey.Passphrase := SenhaPublica;

SenhaPublica é a constante do sistema com a senha da chave pública. Agora, é necessário gravar a chave secreta em um arquivo, para entregar ao usuário. Para gravar a chave secreta, digite o código abaixo, ainda no btCriar:

// Armazena a chave secreta em arquivo
ChaveSecreta := ExtractFilePath(Application.ExeName) + edtNome.Text + '.sec';
lbRSA1.PrivateKey.StoreToFile(ChaveSecreta);
ShowMessage('Chave secreta gravada no arquivo: ' + ChaveSecreta);

isto fará com que a chave secreta seja criptografada e gravada em um arquivo no mesmo diretório do executável, com o nome fornecido para o usuário, mais a extensão ".sec".
Agora, a chave pública precisa ser armazenada no banco de dados, no cadastro do novo usuário. Para tanto, esta chave será gravada em um TMemoryStream, para que seja copiada para o campo BLOB do banco de dados. Prossiga digitando:

// Armazena a chave pública em Stream.
ChavePublica := TMemoryStream.Create;
lbRSA1.PublicKey.StoreToStream(ChavePublica);

e logo em seguida:

// Salva o Stream no Banco de dados
IBTable1.Insert;
IBTable1.FieldByName('NOME').AsString := edtNome.Text;
Chavepublica.Position := 0;
TBlobField(IBTable1.FieldByName('CHAVEPUBLICA')).LoadFromStream(ChavePublica);
IBTable1.Post;
IBTransaction1.CommitRetaining;

Não entrarei em detalhes sobre trabalhos com Stream e sobre conversão de tipos. No código acima, suponho que a tabela IBTable1 já esteja aberta. O "CommitRetaining" mantém a tabela aberta para outro cadastro. Agora existe um cadastro para o usuário, com seu nome e sua chave pública no banco de dados. Para finalizar, digite:

// Concluído
ChavePublica.Free;
ShowMessage('Concluído.');

Pronto. O código do botão btCriar está terminado.
O usuário agora poderá ingressar no sistema, apresentando seu arquivo de chave secreta e digitando a senha. Crie o código de login no botão btLogin.
Pressionando este botão, um dialogbox irá surgir para que o usuário localize seu arquivo de chave. O edtLogin servirá para digitar a senha da chave (evitei reaproveitar edtSenha, para o exemplo ficar mais claro). O sistema irá tentar abrir o arquivo de chave secreta com a senha. Após isto, o programa irá procurar o usuário no banco e carregar sua chave pública. Tendo sucesso em todos estes passos, ele irá confirmar se as chaves são complementares, gerando uma frase ou número qualquer, criptografando com a chave pública e tentando decifrar com a chave secreta. Se obtiver êxito, então as chaves são complementares e válidas.

No botão btLogin, crie as seguintes variáveis locais:

Var ChavePublica : TMemoryStream;
ChaveSecreta : String;
Nome : String;
Desafio : String;
DesafioCif : String;
Resposta : String;

Inicie o código do botão solicitando o arquivo de chave com o dialogbox:

If Not OpenDialog1.Execute then exit;

agora, carregue a chave secreta fornecida. A senha já deverá ter sido digitada em edtLogin. Continue com o código de btLogin:

// Carrega a chave secreta
lbRSA1.PrivateKey.Passphrase := edtLogin.Text;
try
lbRSA1.PrivateKey.LoadFromFile(OpenDialog1.FileName);
except
ShowMessage('Erro carregando a chave secreta.');
Exit;
end;

Em seguida, localize o usuário no banco de dados. Utilizamos o nome do arquivo de chave (que também é o nome do usuário no cadastro) para localizar o usuário. Neste caso, renomear o arquivo fará com que o usuário não seja encontrado. Ainda digitando no código de btLogin:

// Localiza o usuário no banco de dados
Nome := ExtractFileName(OpenDialog1.FileName);
Nome := Copy(Nome,1,Length(nome)-4); // Retira o ".sec"
If not IBTable1.Locate('NOME',Nome,[]) then
begin
ShowMessage('Usuário não encontrado no banco de dados.');
exit;
end;

Tendo encontrado o usuário, é hora de carregar sua chave pública. Usarei novamente um MemoryStream para conseguir pegar a chave do campo BLOB. Continue no código de btLogin:

// Carrega a chave pública do usuário
ChavePublica := TMemoryStream.Create;
TBlobField(IBTable1.FieldByName('CHAVEPUBLICA')).SaveToStream(Chavepublica);
ChavePublica.Position := 0;
lbRSA1.PublicKey.Passphrase := SenhaPublica;
try
lbRSA1.PublicKey.LoadFromStream(ChavePublica);
except
ShowMessage('Erro desconhecido lendo chave pública.');
ChavePublica.Free;
exit;
end;
ChavePublica.Free;

Perceba que utilizei a senha da chave pública que está na constante "SenhaPublica". Agora o componente RSA está com as duas chaves, mas não sabe se uma é realmente "irmã" da outra. Para confirmar se o par é válido, um desafio de resposta deverá ser feito. Continue digitando no código de btLogin:

// Desafio de resposta - Testa se a chave pública
// é a correspondente da secreta apresentada pelo usuário.
// Esta frase deve ser aleatória!
Desafio := 'ESTE É UM DESAFIO!';
Screen.Cursor := crHourGlass;
DesafioCif := lbRSA1.EncryptString(Desafio);
Resposta := lbRSA1.DecryptString(DesafioCif);
Screen.Cursor := crDefault;
If Desafio <> Resposta then
begin
ShowMessage('Chave pública não corresponde com a secreta.');
exit;
end;

A troca de cursor é necessária, pois a criptografia com RSA é muito lenta. Esta verificação deverá demorar, dependendo do computador. A variável "Desafio" é fixa no exemplo para simplificar, mas deverá ser gerada aleatoriamente (de que vale um desafio se já tem a resposta?). Se o usuário sobreviveu a tudo isso, ele merece entrar no sistema. Finalize o código de btLogin com:

ShowMessage('Login Ok. Usuário Autenticado!');

Para que a senha da chave secreta seja alterada, basta carregá-la normalmente (usando a senha antiga, claro!), alterar a propriedade "PassFrase" de "PrivateKey" e gravá-la de volta no arquivo.
Vale lembrar que, esquecendo a senha da chave secreta, não é mais possível ingressar no sistema. A solução é apagar a chave pública e gerar novamente outro par.
Coisas interessantes ainda podem ser feitas com as chaves, como criptografar mensagens para garantir que somente um determinado usuário as leia, assinar mensagens e arquivos, etc...
Mas isso será assunto de um outro artigo!


Autor: Carlos Magno Abreu
icemagno@hotmail.com
http://www.magnoabreu.kit.net/



Comentários Comentários
   Ordem:  
Comentários pertencem aos seus respectivos autores. Não somos responsáveis pelo seus conteúdos.


por: waldnergp : Out 25, 2004 - 05:46
(Informações sobre o membro | Enviar uma mensagem) http://http://
Não consigo acessar o site para fazer o download dos fontes, mas mesmo assim o artigo é interessante.
  Edição 112

Revista ActiveDelphi

  50 Programas Fontes


  Produtos

Conheça Nossos Produtos

Copyright© 2001-2016 – Active Delphi – Todos os direitos reservados