Criptografia no PHP com SHA1, MD5, HASH e CRYPT


Criptografia consiste em converter dados legíveis em dados ilegíveis. Os principais usos de criptografia para desenvolvedores de sites e programadores PHP são: Verificar integridade de arquivos (geralmente arquivos muito grandes que são divididos em várias partes podem ser danificados durante uma transferência) e Verificar autenticidade de dados de usuários em sistemas de login. Neste artigo vou te mostrar como fazer Criptografia no PHP com SHA1, MD5, HASH e CRYPT.

Para facilitar o entendimento, vamos supor que eu queira criar um script de login com PHP e que eu tenho cadastrado o usuário “Anderson” que possui a senha “MinhaSenhaDificil”. Dito isto, sigamos em frente…

Criptografia no PHP com SHA1 e MD5

SHA1 e MD5 são duas funções rapidíssimas que possibilitam criptografar dados. Estas funções são usadas das seguintes formas:

Criptografia com MD5

1
2
3
4
$email = "Anderson";
$senha = "MinhaSenhaDificil";
 
echo md5($senha);
$email = "Anderson";
$senha = "MinhaSenhaDificil";

echo md5($senha);

O código acima vai imprimir o seguinte: “b20691edfae7015d475a2002033ebb26”. Isso significa que a senha MinhaSenhaDificil encriptada com o algorítimo MD5 resulta em “b20691edfae7015d475a2002033ebb26”. Você poderia, por exemplo, no ato do cadastro do usuário, salvar a senha criptografada no banco de dados, o que ajudaria a tornar tal informação mais segura. Por exemplo, se algum hacker descobre uma falha em algum servidor de banco de dados e obtém acesso as tabelas com as senhas e logins, caso a senha esteja criptografada, a priori ele não conseguirá fazer muita coisa com elas.

Salvar senhas sem criptografia em banco de dados sem vulnerabilidades de segurança ainda é arriscado, pois qualquer um que tenha acesso ao teu servidor web poderá ver as senhas dos usuários. Isso inclui os usuários de suporte, técnicos, donos de servidores, etc. Será que dá pra confiar piamente em tanta gente, será que Papai Noel existe? Além disso, mesmo que você conheça e confie plenamente em quem gerencia tua hospedagem web, amanhã ou depois pode ser necessário fazer uma migração para outro servidor web e aí toda a segurança e privacidade estará novamente em xeque.

Criptografia com Sha1

1
2
3
4
$email = "Anderson";
$senha = "MinhaSenhaDificil";
 
echo sha1($senha);
$email = "Anderson";
$senha = "MinhaSenhaDificil";

echo sha1($senha);

O retorno de sha1 foi “2bc97fc527ab7d7e7414d24d6210403fdd533bf4”. A forma de uso aqui é a mesma, ou seja, durante o cadastro você criptografa a senha com a função sha1 e a salva no banco de dados já encriptada. Agora, quando o usuário for efetuar login, você — antes de fazer a comparação — encripta a senha que ele digitou e a compara com a senha já encriptada que foi salva no banco de dados.

Tanto MD5 com SHA1 são funções de encriptação de caminho único, ou seja, só é possível encriptar e não há função para decriptar.

Senhas fracas e a Força Bruta

Força Bruta ou “brute force” é uma forma de tentar descobrir senhas tentando todas as combinações possíveis. Por exemplo, se temos uma senha fácil do tipo “123”, ela seria descoberta facilmente via Força Bruta, onde o hacker iria tentar as combinações 1, depois 2 e assim sucessivamente até encontrar a tua senha. Claro que isso não seria feito manualmente, mas através de scripts ou programas devidamente criados para tal fim.

Aí na internet existem, inclusive, bancos de dados com hash md5 e sha. Através deste sites você poderia descobrir facilmente qual é a senha originária de um dado hash md5 ou sha. Como isso funciona? Simples, os usuários criam scripts que geram combinações de senha, depois convertem-nas para hash md5 ou sha e por fim, salvam a senha e o seu respectivo hash em um banco de dados. A partir daí, uma simples consulta sql por um dado hash poderia trazer-lhe a senha originária.

Claro que estes bancos de dados não possuem todas as combinações possíveis, em sua maioria possuem apenas as hashs de senhas fáceis. Um banco de dados que contesse todas as senhas seria inviável, devido ao tamanho imensurável que o banco de dados iria possuir.

Um deste bancos de dados de hash md5 é o MD5 MY-addr . Este site anuncia que possui em seu banco de dados cerca de “4,700,000,000” hashes MD5. Nada mal para começar, não é mesmo? Para você ter uma ideia, criptei aqui uma senha simples, a saber: “senha123” que gerou o hash “e7d80ffeefa212b7c5c55700e4f7193e”, entrei no site e fiz uma consulta por este hash. Veja o que retornou:

O site, em questão de segundos, revelou-me que a senha originária do hash “e7d80ffeefa212b7c5c55700e4f7193e” é “senha123”. Por conta disso, é preferível utilizar crypt em vez de sha1 ou md5, mas caso queira mesmo continuar utilizando md5, o sugerido é sempre trabalhar com senhas difíceis, que combinem letras maiúsculas e minúsculas, numeros, códigos, etc, e que seja mais comprida de que 8 caracteres.

Criptografia no PHP com HASH e CRYPT

Criptografia com HASH

A função hash permite você criptar algo em diversos algorítimos que estejam disponíveis na tua máquina. Por exemplo, para encriptar algo com MD5 usando Hash, ficaria assim:

1
2
3
4
5
6
7
8
$email = "Anderson";
$senha = "MinhaSenhaDificil";
 
echo md5($senha);
 
echo "<br>";
 
echo hash('md5',$senha);
$email = "Anderson";
$senha = "MinhaSenhaDificil";

echo md5($senha);

echo "<br>";

echo hash('md5',$senha);

Ambas os comandos: md5(senha) e hash(‘md5’,senha) são equivalentes. Na função hash, o primeiro parâmetro define o algorítimo a ser utilizado e o segundo parâmetero é o dado para ser encriptado. Para saber quais algorítimos estão disponíveis para uso no teu computador — ou no servidor web que hospeda teu site — você pode usar a função hash_algos(). Veja como:

1
2
3
echo "<pre>";
print_r(hash_algos());
echo "</pre>";
echo "<pre>";
print_r(hash_algos());
echo "</pre>";

Aqui na minha máquina, por exemplo, os algorítimos disponíveis para utilização na função hash foram:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Array
(
    [0] => md2
    [1] => md4
    [2] => md5
    [3] => sha1
    [4] => sha224
    [5] => sha256
    [6] => sha384
    [7] => sha512
    [8] => ripemd128
    [9] => ripemd160
    [10] => ripemd256
    [11] => ripemd320
    [12] => whirlpool
    [13] => tiger128,3
    [14] => tiger160,3
    [15] => tiger192,3
    [16] => tiger128,4
    [17] => tiger160,4
    [18] => tiger192,4
    [19] => snefru
    [20] => snefru256
    [21] => gost
    [22] => adler32
    [23] => crc32
    [24] => crc32b
    [25] => salsa10
    [26] => salsa20
    [27] => haval128,3
    [28] => haval160,3
    [29] => haval192,3
    [30] => haval224,3
    [31] => haval256,3
    [32] => haval128,4
    [33] => haval160,4
    [34] => haval192,4
    [35] => haval224,4
    [36] => haval256,4
    [37] => haval128,5
    [38] => haval160,5
    [39] => haval192,5
    [40] => haval224,5
    [41] => haval256,5
)
Array
(
    [0] => md2
    [1] => md4
    [2] => md5
    [3] => sha1
    [4] => sha224
    [5] => sha256
    [6] => sha384
    [7] => sha512
    [8] => ripemd128
    [9] => ripemd160
    [10] => ripemd256
    [11] => ripemd320
    [12] => whirlpool
    [13] => tiger128,3
    [14] => tiger160,3
    [15] => tiger192,3
    [16] => tiger128,4
    [17] => tiger160,4
    [18] => tiger192,4
    [19] => snefru
    [20] => snefru256
    [21] => gost
    [22] => adler32
    [23] => crc32
    [24] => crc32b
    [25] => salsa10
    [26] => salsa20
    [27] => haval128,3
    [28] => haval160,3
    [29] => haval192,3
    [30] => haval224,3
    [31] => haval256,3
    [32] => haval128,4
    [33] => haval160,4
    [34] => haval192,4
    [35] => haval224,4
    [36] => haval256,4
    [37] => haval128,5
    [38] => haval160,5
    [39] => haval192,5
    [40] => haval224,5
    [41] => haval256,5
)

Embora hash permita você trabalhar com encriptação com mais tipos de algorítimos, o fato de um determinado algotírimo não estar disponível em um determinado servidor web, nos leva a dar preferência para a próxima função, a saber “crypt”.

Criptografia com Crypt

Crypt é a função própria do PHP para se trabalhar com criptografia. Esta função permite você encriptar algo nos seguintes algorítimos:

– CRYPT_STD_DES – Suporta uma dificuldade adicional (salgar) de 2 caracteres.

– CRYPT_EXT_DES – Permite uma dificuldade adicional de 9 caracteres, sendo que o primeiro deve ser um underline (_).

– CRYPT_MD5 – Permite dificultar com 12 caracteres, sendo que deve iniciar em: $1$

– CRYPT_BLOWFISH – Permite uma dificuldade adicional de 22 caracteres. Deve iniciar em $2a$ seguido de um número entre 04 e 31 seguido de $ e dos caracteres. O número de dois dígitos define a contagem de iterações que a função deve considerar. Detalhe que a partir do PHP 5.3.7 você deve dar preferência para iniciar os caracteres com “$2y$” ou “$2x$”.

– CRYPT_SHA256 – Permite uma dificuldade adicional de 16 caracteres iniciados com $5$. Se usado “rounds=$” no inicio dos caracateres, N indica o número de loops (iterações) que devem ser executados. O valor padrão é 5000, mas o valor aceito está entre 1000 e 999,999,999

– CRYPT_SHA512 – Permite uma dificuldade adicional de 16 caracteres iniciados com $6$. Do mesmo modo que Sha256, se usado “rounds=$” no inicio dos caracateres, N indica o número de loops (iterações) que devem ser executados. O valor padrão é 5000, mas o valor aceito está entre 1000 e 999,999,999

Diferente da função Hash, crypt, a partir da versão 5.3.0 do PHP, caso o algorítimo escolhido não exista no computador, utiliza uma versão interna do algorítimo, existente no núcleo do PHP.

Veja o código abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$senha = "senha123";
 
echo 'DES Padrao: ' . crypt($senha, 'Ox') . "\n";
echo "<br>";
 
echo 'DES Estendido: ' . crypt($senha, '_5D2s/..s') . "\n";
echo "<br>";
 
echo 'MD5:          ' . crypt($senha, '$1$l.vi.5/ks') . "\n";
echo "<br>";
 
echo 'Blowfish:     ' . crypt($senha, '$2a$07$eisaqu/umaSenhArealbo.') . "\n";
echo "<br>";
 
echo 'SHA-256:      ' . crypt($senha, '$5$rounds=5000$umcod1g.Show5S2Z') . "\n";
echo "<br>";
 
echo 'SHA-512:      ' . crypt($senha, '$6$rounds=5000$umcod/g.Show5S2Z') . "\n";
$senha = "senha123";

echo 'DES Padrao: ' . crypt($senha, 'Ox') . "\n";
echo "<br>";

echo 'DES Estendido: ' . crypt($senha, '_5D2s/..s') . "\n";
echo "<br>";

echo 'MD5:          ' . crypt($senha, '$1$l.vi.5/ks') . "\n";
echo "<br>";

echo 'Blowfish:     ' . crypt($senha, '$2a$07$eisaqu/umaSenhArealbo.') . "\n";
echo "<br>";

echo 'SHA-256:      ' . crypt($senha, '$5$rounds=5000$umcod1g.Show5S2Z') . "\n";
echo "<br>";

echo 'SHA-512:      ' . crypt($senha, '$6$rounds=5000$umcod/g.Show5S2Z') . "\n";

Este script imprimiu na tela o seguinte:

1
2
3
4
5
6
7
DES Padrao: Ox3Y5Fya7XF5w
DES Estendido: _5D2s/..sDW6cb.k2v6c
MD5: $1$l.vi.5/k$jniCb3UJAftmHGjihtW291
Blowfish: $2a$07$eisaqu/umaSenhArealbo.nz9zoBr8hWs4dQTPO8RNtL8WrB056fG
SHA-256: $5$rounds=5000$umcod1g.Show5S2Z$zwYkD4VvpivMMkevXF9YIRTIYkrkrJ64g1bqbpG/Lu2
SHA-512: $6$rounds=5000$umcod/g.Show5S2Z$vh9cbTzlAjbn7OQPMNUkMRpqrFW3bFG0k4h86FIm.FsRF5hQOk9QYNHcv0Zzi59fpEEG2DJgGMcsKESpeOT3o/
0a81023cfd1b9661c66724eb24b8a10a
DES Padrao: Ox3Y5Fya7XF5w
DES Estendido: _5D2s/..sDW6cb.k2v6c
MD5: $1$l.vi.5/k$jniCb3UJAftmHGjihtW291
Blowfish: $2a$07$eisaqu/umaSenhArealbo.nz9zoBr8hWs4dQTPO8RNtL8WrB056fG
SHA-256: $5$rounds=5000$umcod1g.Show5S2Z$zwYkD4VvpivMMkevXF9YIRTIYkrkrJ64g1bqbpG/Lu2
SHA-512: $6$rounds=5000$umcod/g.Show5S2Z$vh9cbTzlAjbn7OQPMNUkMRpqrFW3bFG0k4h86FIm.FsRF5hQOk9QYNHcv0Zzi59fpEEG2DJgGMcsKESpeOT3o/
0a81023cfd1b9661c66724eb24b8a10a

Notaste que a senha utilizada foi a senha “senha123”? Pois é, porém com os caracteres que apimentaram nossa criptografia e com a função crypt, o retorno foi “$1$l.vi.5/k$jniCb3UJAftmHGjihtW291”. Se você pegar este valor, retornar ao site do MD5 My-Addr e refazer a consulta, notará que ele já não consegue mais identificar que a senha original foi senha123. Isso é meio óbvio, pois quando utilizei a função crypt, passei os caracteres “$1$l.vi.5/ks” para base de encriptação md5, e esse conjunto de caracteres é um conjunto que eu criei aleatoriamente. Por conta disso, jamais copie o conjunto de caracateres que eu utilizei neste exemplo, crie seus próprios, obedecendo sempre o limite exigido por cada tipo de algorítimo, conforme descreví acima.

Conclusão

Um detalhe é que você sempre deve informar os caracteres de dificultação para base de encriptação quando for vericar autenticidade de login, pois se não o PHP poderá usar o algorítimo indesejado. Outro detalhe é que os caracteres de salt devem estar no intervaldo: a até z ou A até Z ou 0 até 9 ou ./. Demais caracteres não são aceitos e podem fazer a função crypt falhar.

Agora, se for para encriptar senha, segundo o site do PHP (php.net), o algorítimo preferível é o Blowfish em detrimento do MD5 e SHA.

Até o próximo artigo aqui no blog

Leave a Reply