Tutorial Básico de Criptografia

Artigos, manuais, conselhos e dicas sobre programação em AutoHotkey

Moderator: Gio

Post Reply
User avatar
Gio
Posts: 1247
Joined: 30 Sep 2013, 10:54
Location: Brazil

Tutorial Básico de Criptografia

Post by Gio » 09 Nov 2021, 11:34

Tutorial Básico de Criptografia

Bom dia!

Decidi fazer este tutorial porque tenho visto muitas perguntas relacionadas à segurança, licenças, senha, logins e etc. Se você quer criar uma rotina dessas, é importante que conheça pelo menos alguns rudimentos de criptografia, com vistas à dar mais segurança às suas rotinas. A criptografia vai ajudar você nessa tarefa, e dependendo do intuito do seu programa, pode se tornar realmente necessária.

Vamos aprender?

1. O que é criptografia

De forma resumida e sem definir propriamente o termo, criptografia é o meio através do qual podemos transmitir mensagens de um remetente a um destinatário sem que um terceiro com acesso a ela possa entender seu conteúdo.

Senhas são um ótimo exemplo: Para adquirir acesso a um programa-alvo de forma segura, o usuário precisa digitar uma senha válida em uma tela. Mas internamente, o programa-alvo só pode saber se a senha está correta comparando-a com algum registro que estiver armazenado em algum lugar, tal como um arquivo. Neste caso, o que podemos fazer para que um terceiro não tenha acesso à senha mesmo que tenha acesso ao arquivo com os dados da senha?

:arrow: Simples! Fazemos isso com criptografia.

2. Como criar uma rotina básica de criptografia

Vamos nos concentrar no caso-problema relatado no item 1 do tutorial. Suponhamos, para simplificar o nosso entendimento, que a senha de acesso a um programa-alvo seja simplesmente o número 5. Isso significa que o usuário acessará o programa digitando o número 5 na tela da senha.

Ocorre que, para viabilizar essa rotina, precisamos salvar as informações necessárias para que o programa também possa saber a senha em algum lugar. Além disso, escolhemos por simplicidade que será um arquivo chamado. No entanto, é aqui que se inicia o nosso problema: se salvarmos o número 5 diretamente no arquivo, qualquer pessoa que tiver acesso ao arquivo poderá facilmente saber qual a senha que dá acesso ao programa.

Como fazemos então para que, mesmo que alguém tenha acesso e possa ler o conteúdo do arquivo, esse alguém NÃO consiga saber a senha e ter acesso ao programa?

:arrow: Simples: ao invés de escrevermos o número 5 neste arquivo de dados de senhas, vamos escrever "8" no arquivo.

Talvez você esteja se perguntando: Como assim escrever 8 :crazy: ? A senha não é 5?

Mas veja que é aqui que está o pulo do gato: Podemos facilmente fazer com que o programa entenda que o 8 é um número criptografado que na verdade significa 5. Para isso, precisamos apenas criar um algoritmo que transforma "8" em "5" dentro do programa. Para nossa sorte, esse algoritmo é muito simples: basta "deduzir 3". Logo, quando o programa ler o arquivo de dados de senhas, ele vai ler um 8, mas depois vai aplicar internamente o algoritmo "deduzir 3" e então encontrará "5", que é justamente o número que deve ser comparado ao que o usuário digitou para tentar acessar o programa.

Ou seja, se um bisbilhoteiro pode até tentar abrir o arquivo, e vai até conseguir ler o que estiver lá, porém será o número "8". Se ele tentar escrever esse "8" na tela de acesso, ele NÃO vai ganhar acesso ao programa, pois o algoritmo NÃO roda sobre o número inserido no campo de senha (roda apenas sobre o número escrito no arquivo).

Ainda não entendeu? Pense assim: o arquivo tem um 8 escrito, e o usuário tentou digitar 8 na senha. Porém, o programa pegou o 8 do arquivo (somente ele) e transformou internamente em um 5 antes da comparação. Como o 8 digitado no campo de senha NÃO é igual ao 5 encontrado internamente pelo programa, o acesso NÃO será concedido. Já se o usuário digitar corretamente a senha "5", o programa da mesma forma vai pegar o 8 escrito no arquivo, vai aplicar o algoritmo "deduzir 3" neste valor, e vai encontrar também 5, resultando que a senha inserida será, neste caso sim, igual ao número encontrado internamente pelo programa.

Viu como é simples? Pense bem: com essa sistemática tudo funciona corretamente, ainda que o arquivo NÃO contenha a senha real escrita.

:arrow: Neste caso apresentado, podemos dizer que o "8" seria a senha "criptografada", que pode ser escrita sem problemas no arquivo, e o 5 seria a senha "descriptografada", que só existe internamente no programa após se aplicar o algoritmo interno "deduzir 3" sobre o conteúdo do arquivo. O programa cuidará de garantir internamente que a senha descriptografada não seja acessível diretamente no arquivo, pois ele é quem possui em seu código o algoritmo para "deduzir 3" naquilo que estiver no arquivo. Sem saber que o algoritmo é este, um terceiro jamais poderá usar a informação "8" para acessar o programa, pois o programa só será acessível se ele escrever 5 na tela, que é o resultado da aplicação do algoritmo sobre o número 8 escrito no arquivo. Ademais, veja que com o mesmo algoritmo podemos criar várias senhas para vários usuários diferentes,

Dessa forma, o próprio algoritmo "deduzir 3" se torna uma espécie de senha interna do programa, que trabalhará em conjunto com a senha do usuário para permitir ou negar o acesso ao programa.

:arrow: Exemplo prático: vamos criar um código bem simples onde a senha seja 5, mas vamos garantir que esse número não esteja escrito em canto nenhum:

Code: Select all

SENHA_LIDA := 8

InputBox, VALOR_DIGITADO, Senha de acesso, Insira a senha de acesso ao programa para continuar

IF (VALOR_DIGITADO = SENHA_LIDA - 3)
{
	msgbox % "parabéns! Você conseguiu o acesso. :D"
}
else
{
	msgbox % "Desculpe, mas a senha informada está incorreta! :("
}
Reload

:arrow: No código acima, veja que o programa não tem o número 5 escrito em seu código. Dessa forma, podemos inferir que também não seria necessário escrever o número 5 em um arquivo de senhas para que a rotina de acesso funcione: poderíamos escrever 8 e depois usar um FileRead para popular a variável SENHA_LIDA. Dessa forma, não faria diferença alguma se um curioso decidisse ler o conteúdo do arquivo de senhas, pois isso não é o bastante para que ele saiba a senha correta.

É claro que uma senha de 1 dígito não é segura de nenhuma forma, mas o exemplo serve para entendermos o conceito. A seguir vamos aplicá-lo a uma senha que seja um pouco mais segura: uma senha que contenha letras, por exemplo.

3. Como criar uma rotina básica de criptografia com LETRAS?

Se você entendeu corretamente o item 2 deste tutorial, pode ter se perguntado: "ok, agora entendo como criar uma senha numérica criptografada, mas como faria isso com uma senha que envolva letras? não posso deduzir 3 de uma letra!"

Bom, você está correto, não é possível deduzir 3 de uma letra. Mas é possível deduzir 3 de um valor numérico correspondente a uma letra. Para fazer isso, tudo que temos que fazer é atribuir valores numéricos diferentes para letras diferentes.

Imagine o seguinte: ainda que a letra "a" não possua um valor matemático, podemos perfeitamente definir que ela possua um valor específico em nosso programa. Dessa forma, podemos definir que "a" seria 1, "b" seria 2, "c" seria 3, "d" seria 4, "e" seria 5, e assim sucessivamente. Tendo isso em mente, vamos reconstruir o programa-exemplo do item 2 para que a senha seja a letra "e" e não 5. Ademais, vamos salvar a letra "h" no lugar do 8 em nosso arquivo de senhas. Veja como não é tão difícil fazer:

Code: Select all

a := 1
b := 2
c := 3
d := 4
e := 5
f := 6
g := 7
h := 8

SENHA_LIDA := "h"
VALOR_DA_SENHA_LIDA := %SENHA_LIDA% ; Podemos usar uma dereferenciação-dupla para recuperar o valor 8 a partir da letra "h", uma vez que definimos acima que a variável de nome "h" possui o valor 8.

InputBox, VALOR_DIGITADO, Senha de acesso, Insira a senha de acesso ao programa para continuar

NUMERO_DO_VALOR_DIGITADO := %VALOR_DIGITADO% ; A mesma coisa fazemos aqui.

IF (NUMERO_DO_VALOR_DIGITADO = VALOR_DA_SENHA_LIDA - 3)
{
	msgbox % "parabéns! Você conseguiu o acesso. :D"
}
else
{
	msgbox % "Desculpe, mas a senha informada está incorreta! :("
}
Reload

:arrow: Veja no código acima que a senha passou a ser a letra "e" e não mais o número 5. Como bônus, não adianta o usuário digitar 5 na tela: ou ele digita "e" ou o acesso não será concedido pelo programa.

Por fim, veja que não é necessário que as letras tenham um valor iniciado em 1, e nem que sejam na mesma ordem do alfabeto: basta que tenham valores diferentes para que o programa funcione. Mas neste caso, precisaríamos, é claro, definir muito bem qual caractere colocar no arquivo de senhas, uma vez que o algoritmo atual requer que o caractere do arquivo seja maior que a senha real em exatamente 3 (pois a chave interna ainda é "deduzir 3").

4. Usando a tabela ASCII para facilitar criptografia de senhas com letras.

Agora que você já entendeu como criptografamos letras através da definição de valores diferentes para letras diferentes, vale a pena dizer que não precisamos definir nós mesmos os valores de cada letra: podemos usar a tablea ASCII.

A tablea ASCII é uma tabela que define valores numéricos diferentes para caracteres diferentes. Como ela é muito utilizada na programação, e possui funções embutidas para conversão entre caracteres e seus valores numéricos, pode ser útil utilizá-la no nosso programa.

Nessa tabela, a letra "a" minúscula, por exemplo, possui o valor de 97. Já a letra "b" possui o valor 98. Para encontrar o valor numérico de uma letra, podemos utilizar a função embutida Asc(), tal como o exemplo a seguir: msgbox % Asc("a").

Também é possível encontrar a letra através do seu valor, e para isso usaremos a função embutida Chr(), tal como neste exemplo: msgbox % chr(97)

Mas qual a vantagem de usar a tablea ASCII? Uma delas é que podemos facilmente usar essas funções e outros conhecimentos de programação para converter muitas letras em números correspondentes.

Exemplo: recuperando em loop os valores de cada letra de uma "palavra" com 7 letras:

Code: Select all

palavra_exemplo := "abcdefg"
Loop, parse, palavra_exemplo
{
	msgbox % asc(A_LoopField)
}

5. Quebrando algoritmos de criptografia

Agora que você já entendeu como funciona um algoritmo básico de criptografia convém falarmos sobre a segurança desses algoritmos. Embora na teoria seja impossível inferir que a senha é "5" quando o conteúdo do arquivo é "8", saiba que o ser humano é bastante "criativo" em encontrar falhas nesses algoritmos. Essa criatividade pode levar alguém a tentar quebrar sua criptografia, seja através de deduções sobre o funcionamento do programa, ou através de ataques pautados em analises estatísticas ou mesmo através de força bruta mesmo.

Um exemplo de ataque do tipo "força bruta" seria o usuário tentar todos os números do 1 até o 10000, por exemplo. Nesse caso ele conseguiria quebrar a senha em apenas 5 tentativas. Se o programa permitir muitas tentativas em pouco tempo, isso ficaria ainda mais fácil.

Já um exemplo de ataque de "deduções" seria alguém perceber que a senha criptografada tem apenas 1 dígito e por isso decidir tentar as senhas de 0 até 9, só para ver. Essa dedução simples também permitiria que o atacante quebrasse a senha em pouco tempo, uma vez que ela é findou sendo verdadeira e com ela não se perderia tempo com números maiores que 10. Outro exemplo de ataque de dedução seria se fosse possível criar vários usuários no programa, com várias senhas diferentes. Comparando as novas senhas criadas com os novos conteúdo do arquivo de senhas, seria possível perceber que todas as senhas geram conteúdos maiores que elas em 3. Dessa forma, seria possível deduzir que o algoritmo interno do programa deduz 3 do conteúdo do arquivo, e portanto que o valor 8 significaria a senha "5". Uma pessoa com alguma ideia do que está fazendo não teria problemas em deduzir esta senha dessa forma.

Finalmente, um exemplo de ataque estatístico seria tentar usar primeiro as senhas mais comuns (sim, muita gente usa 123456 como senha), ou, caso usemos um algoritmo específico conhecido (como SHA-256), tentar usar métodos matemáticos estatísticos que reduzem a quantidade de tentativas para quebrar uma senha, e a partir daí usar a força bruta.

Portanto, antes de finalizar uma rotina de senha com criptografia, convém que analise se ela não está fraca demais. Se você tiver algum receio de que a sua criptografia possa ser "quebrada" (nome que damos para a ação de recuperar o "5" a partir do "8"), você sempre pode tentar melhorar ela. Mas mantenha este pensamento em mente: não adianta criar um muro de 100 metros se o custo dele for 20x maior que um muro de 5 metros, pois o ladrão sempre pode abrir um buraco ou cair de paraquedas. Faça uma segurança apropriada, não gaste todo seu tempo fazendo segurança inútil.


6. Criando algoritmos melhores

Se você entendeu tudo até aqui, deve ter percebido o potencial da criptografia para a segurança dos dados. Mas deve também ter percebido que os algoritmos dos exemplos são MUITO básicos: eles não devem ser utilizados exatamente dessa forma, pois a segurança será muito baixa.

Mas como faríamos para elevar a segurança dos nossos algoritmos e criar rotinas mais seguras?

Simples: Você pode pesquisar ou elaborar um algoritmo mais complexo, usando dentre outras as seguintes características:

1. O conteúdo do arquivo não precisa ter o mesmo tamanho da senha: imagine que ao invés de deduzir 3, você vai adicionar 458734. Nesse caso, a o conteúdo salvo no arquivo para a senha 5 não seria 8, mas sim 458739. Descobrir que a senha é 5 a partir de 458739 não é tão fácil quanto descobrir isso a partir de 8, pois senhas longas (e algoritmos longos) (costumam) precisar de mais trabalho para serem quebradas.
2. Exija que o usuário cadastre senhas mais longas: se a senha do usuário for 237512 ao invés de 5, então o conteúdo do arquivo considerando o adicionar de 458734 passaria a ser 696246. Ou seja, seria um número muito diferente daquele que é apresentado no arquivo de senha, e isso pode ajudar um pouco na segurança. Também é interessante que a senha seja uma combinação de letras e números (se você não exigir isso no formulário de cadastro, um hacker experiente saberá que há grandes chances de a senha escolhida pelo usuário ser somente numérica, permitindo que ele use essa estatística juntamente com a força bruta para tentar quebrar mais fácil a sua senha)
3. Use um algoritmo mais complexo: o algoritmo dentro do programa não precisa ser algo tão simples como "deduzir 3". Pode ser algo bem mais trabalhado que isso, algo que seja bem mais difícil deduzir. Um exemplo seria fazer vários passos: multiplicado por 30, deduzir 8, elevar ao quadrado, diminuir 3, multiplicar por 2, adicionar 1, etc... Neste caso, convém apenas destacar que talvez você chegue a um algoritmo com múltiplas senhas válidas, mas dentre muitas possibilidades, isso não deve ser problemático. Só tome cuidado com fórmulas simplificáveis (multiplica por 20 e em seguida dividir por 10 equivale a multiplicar por 2). Mas dependendo de como você monta os passos, pode ser bem difícil entender uma senha a partir de muitas outras testadas.
4. Lembre-se sempre que um dos pontos chaves da segurança é o sigilo: não deixe nenhuma informação no programa que possa levar o atacante a descobrir qual método de criptografia você utilizou.
5. Na dúvida, procure pesquisar sobre algoritmos fortes que podem ser replicados no seu programa. Matemáticos costumam estudar relações entre números e elaborar teses sobre essas relações. Ao usar um algoritmo reconhecidamente forte, você diminui a chance de seu algoritmo parecer forte, mas ser na verdade frágil através de uma ótica matemática que você desconhece.

7. Outros usos da criptografia

Muito embora a criptografia seja comumente relacionada a rotinas de senhas, saiba que você pode utilizá-la para outras rotinas. Um exemplo são rotinas de obfuscação: essas rotinas servem para que você possa mostrar, por exemplo, um código funcional, mas ao mesmo tempo, dificultar a leitura de parte dele. Outro exemplo são rotinas de comunicação entre servidores e clients: as vezes, a conversa em si, apesar de não conter senhas, deve ser protegida de bisbilhoteiras. Pode-se conseguir isso com criptografia (o whatsapp, por exemplo, possui criptografia de ponta-a-ponta em suas mensagens). Outro exemplo de uso da criptografia é em arquivos de programas com formato proprietário: se você não quer que alguém desenvolva um programa que pode trabalhar com os arquivos do seu programa, você pode criptografá-los. Isso pode ser útil por exemplo no desenvolvimento de jogos onde o desenvolvedor, por qualquer razão que seja, não quer ver mods de seus jogos por aí.

8. Outras criptografias (e conclusão)

O ramo da criptografia não se restringe às ideias que tratamos aqui. Existem tópicos não abordados neste tutorial básico que você pode explorar se precisar, tais como a criptografia com chaves públicas e privadas (que é útil para assinaturas digitais e etc). Use este tutorial apenas como um pontapé para seu aprendizado: não use como se aqui houvessem as informações para criar criptografias fortes. Mas lembre-se que tudo na programação é uma troca entre facilidade de implementação e ganho de controle: algoritmos simples podem prover uma segurança básica que manterá a maioria dos usuários médios afastados sem que seja necessário muito trabalho da sua parte. Algoritmos mais complexos podem manter até mesmo hackers experientes distantes do seu programa, mas não há nada que impeça alguém em absoluto de conseguir quebrar sua senha. É importante balancear bem o volume de trabalho com o resultado necessário.

Espero ter ajudado, se ainda tiver alguma dúvida sobre este tópico, basta postar abaixo :thumbup:

Post Reply

Return to “Tutoriais”