Criptografia com PHP

Criptografia com PHP

Neste artigo vamos falar um pouco sobre criptografia e vamos ver alguns exemplos de implementação utilizando a linguagem PHP. Vamos ver um pouco da história e ver como evolui a forma de proteger informações.

A palavra criptografia tem sua origem no grego "kryptós" que significa escondido e "gráphein" que signfica escrita. O termo se aplica a técnicas para comunicação segura na presença de terceiros, mas também é utilizado para se referir a construção e análise de protocolos que impedem terceiros de lerem mensagens privadas. A criptografia é muito antiga, tendo sido usada no começo para a guerra. Um dos primeiros exemplos ocorrem no Egito em torno de 1900 AC. 

O que você vai ver neste artigo

Exemplos de métodos antigos de criptografia

- Cifra de Substitiução

- Cifra de César

- Cifra de Vigenère

Formas comuns de criptografar com PHP

- MD5

- AES

 

Cifra de substituição

 

Na antiguidade surgiram as primeiras formas de criptografia, a mais simples é a chamada cifra de substituição, onde era utilizada uma palavra chave para servir de referência na substituição das letras da mensagem original. Um exemplo moderno dete tipo de criptografia você pode ver a seguir:

 

class ParChaveValor

{

public $chave;

public $valor;

}

function compare($primeiro, $segundo) {

return strcmp($primeiro->valor, $segundo->valor);

}

function GetMudarIndices($chave)

{

$tamanhoChave = strlen($chave);

$indexes = array();

$chavesOrdenadas = array();

$i;

for ($i = 0; $i < $tamanhoChave; ++$i) {

$pair = new ParChaveValor();

$pair->chave = $i;

$pair->valor = $chave[$i];

$chavesOrdenadas[] = $pair;

}

 

usort($chavesOrdenadas, "compare");

$i = 0;

 

 

for ($i = 0; $i < $tamanhoChave; ++$i)

$indexes[$chavesOrdenadas[$i]->chave] = $i;

return $indexes;

}

function Criptografar($mensagem, $chave, $padChar)

{

$saida = "";

$totalCaracteres = strlen($mensagem);

$tamanhoChave = strlen($chave);

$mensagem = ($totalCaracteres % $tamanhoChave == 0) ? $mensagem : str_pad($mensagem, $totalCaracteres - ($totalCaracteres % $tamanhoChave) + $tamanhoChave, $padChar, STR_PAD_RIGHT);

$totalCaracteres = strlen($mensagem);

$totalColunas = $tamanhoChave;

$totalLinhas = ceil($totalCaracteres / $totalColunas);

$caracteresLinha = array(array());

$caracteresColuna = array(array());

$caracteresColunaOrdenados = array(array());

$linhaAtual = 0; $colunaAtual = 0; $i = 0; $j = 0;

$mudarIndices = GetMudarIndices($chave);

 

for ($i = 0; $i < $totalCaracteres; ++$i)

{

$linhaAtual = $i / $totalColunas;

$colunaAtual = $i % $totalColunas;

$caracteresLinha[$linhaAtual][$colunaAtual] = $mensagem[$i];

}

 

for ($i = 0; $i < $totalLinhas; ++$i)

for ($j = 0; $j < $totalColunas; ++$j)

$caracteresColuna[$j][$i] = $caracteresLinha[$i][$j];

 

for ($i = 0; $i < $totalColunas; ++$i)

for ($j = 0; $j < $totalLinhas; ++$j)

$caracteresColunaOrdenados[$mudarIndices[$i]][$j] = $caracteresColuna[$i][$j];

 

for ($i = 0; $i < $totalCaracteres; ++$i)

{

$linhaAtual = $i / $totalLinhas;

$colunaAtual = $i % $totalLinhas;

$saida .= $caracteresColunaOrdenados[$linhaAtual][$colunaAtual];

}

return $saida;

}

function Descriptografar($mensagem, $chave)

{

$saida = "";

$tamanhoChave = strlen($chave);

$totalCaracteres = strlen($mensagem);

$totalColunas = ceil($totalCaracteres / $tamanhoChave);

$totalLinhas = $tamanhoChave;

$caracteresLinha = array(array());

$caracteresColuna = array(array());

$caracteresColunaOrdenados = array(array());

$linhaAtual = 0; $colunaAtual = 0; $i = 0; $j = 0;

$mudarIndices = GetMudarIndices($chave);

for ($i = 0; $i < $totalCaracteres; ++$i)

{

$linhaAtual = $i / $totalColunas;

$colunaAtual = $i % $totalColunas;

$caracteresLinha[$linhaAtual][$colunaAtual] = $mensagem[$i];

}

for ($i = 0; $i < $totalLinhas; ++$i)

for ($j = 0; $j < $totalColunas; ++$j)

$caracteresColuna[$j][$i] = $caracteresLinha[$i][$j];

for ($i = 0; $i < $totalColunas; ++$i)

for ($j = 0; $j < $totalLinhas; ++$j)

$caracteresColunaOrdenados[$i][$j] = $caracteresColuna[$i][$mudarIndices[$j]];

for ($i = 0; $i < $totalCaracteres; ++$i)

{

$linhaAtual = $i / $totalLinhas;

$colunaAtual = $i % $totalLinhas;

$saida .= $caracteresColunaOrdenados[$linhaAtual][$colunaAtual];

}

return $saida;

}

$mensagem = "Criptografia de substituição";

$chave = "permanbuco";

$texto_criptografado = Criptografar($mensagem, $chave, "-");

$texto_descriptografado = Descriptografar($texto_criptografado, $chave);

echo $texto_criptografado;

echo " - ";

echo $texto_descriptografado;

 

No exemplo, a palavra "pernambuco" é usada como chave para avançar as letras. Veja o exemplo a seguir:

 

---chave: permanbuco

mensagem: prescindir

 

Depois de aplicada a chave, as letras são reorganizadas em ordem alfabética tomando como base a chave. No exemplo anterior, a letra "b" da chave "pernambuco" que ocupa a sétima posição, passa a ocupar a segunda posição.

 

---chave: abcemmopru

mensagem: cnirsirped

 

Funções utilizadas neste código:

 

CEIL - Arredonda um número para cima. 

STRCMP - Faz a comparação de duas string. Esta função é case sensitive.

STRLEN - Retorna o tamanho de uma string.

STR_PAD - Esta funão preenche uma string até um determinado comprimento.

USORT - Ordena um array pelos valores usando uma função de classificação definida pelo usuário.

 

Cifra de César

 

Um outro exemplo vindo da antiguidade é o codificador de Júlio Cesar. Essa técnica clássica consistia em substituir as letras do alfabeto avançando 3 posições. A seguir veja um exemplo de como implementar isso no PHP.

 

function Cipher($caractere, $chave) {

if (!ctype_alpha($caractere))

return $caractere;

$offset = ord(ctype_upper($caractere) ? "A" : "a");

return chr(fmod(((ord($caractere) + $chave) - $offset), 26) + $offset);

}

function Criptografar($mensagem, $chave){

$saida = "";

$arrayMensagem = str_split($mensagem);

foreach ($arrayMensagem as $caractere)

$saida .= Cipher($caractere, $chave);

return $saida;

}

function Descriptografar($mensagem, $chave) {

return Criptografar($mensagem, 26 - $chave);

}

 

$mensagem = "Cifra de Júlio César";

$texto_criptografado = Criptografar($mensagem, 3);

$texto_descriptografado = Descriptografar($texto_criptografado, 3);

echo $texto_criptografado;

echo " - ";

echo $texto_descriptografado;

 

Este não é um método seguro porque existem 26 possíveis combinações que podem ser testadas para descriptografar a mensagem.

Funções utilizadas neste código:

CTYPE_ALPHA - Verifica se os caracteres da string informada são alfanuméricos.

CTYPE_UPPER - Verifica se os caracteres da string informada são maiúsculos.

CHR - Retorna um caractere de acordo com o valor ASCII informado.

FMOD - Calcula o módulo flutuante de uma divisão

ORD - Retorna o valor ASCII de um caractere.

 

Cifra de Vigenère

 

Em tempos mais recentes, durante a época da Renascença, o italiano Giovan Battista Bellaso em 1553 fez uma melhoria neste tipo de criptografia de substiuição, utilizando valores de deslocamento diferentes para cada letra. Esta melhoria foi atribuída incorretamente ao 

francês Blaise de Vigenère no século XIX, e leva o seu nome desde então. Esta cifra consiste em atribuir valores númericos para cada letra da chave da mensagem e este número é utilizado para fazer o deslocamento da letra da mensagem. A crifra de Vigenère pode ser implementada da seguinte forma no PHP.

 

function Mod($a, $b)

{

return ($a % $b + $b) % $b;

}

function Cipher($mensagem, $chave, $encipher)

{

$tamanhoChave = strlen($chave);

for ($i = 0; $i < $tamanhoChave; ++$i)

if (!ctype_alpha($chave[$i]))

return ""; // Erro

$saida = "";

$ContagemCaractereNaoAlfa = 0;

$tamanhoMensagem = strlen($mensagem);

for ($i = 0; $i < $tamanhoMensagem; ++$i)

{

if (ctype_alpha($mensagem[$i]))

{

$caractereMaiusculo = ctype_upper($mensagem[$i]);

$offset = ord($caractereMaiusculo ? "A" : "a");

$chaveIndex = ($i - $ContagemCaractereNaoAlfa) % $tamanhoChave;

$k = ord($caractereMaiusculo ? strtoupper($chave[$chaveIndex]) : strtolower($chave[$chaveIndex])) - $offset;

$k = $encipher ? $k : -$k;

$ch = chr((Mod(((ord($mensagem[$i]) + $k) - $offset), 26)) + $offset);

$saida .= $ch;

}

else

{

$saida .= $mensagem[$i];

++$ContagemCaractereNaoAlfa;

}

}

return $saida;

}

function Criptografar($mensagem, $chave)

{

return Cipher($mensagem, $chave, true);

}

function Descriptografar($mensagem, $chave)

{

return Cipher($mensagem, $chave, false);

}

$mensagem = "Cifra de Vigenère";

$texto_criptografado = Criptografar($mensagem, "cipher");

$texto_descriptografado = Descriptografar($texto_criptografado, "cipher");

echo $texto_criptografado;

echo " - ";

echo $texto_descriptografado;

 

A referência para a quantidade de letras a ser avançada na mensagem foi a palavra "cipher". A quantidade de caracteres a avançar para cada letra da mensagem é  2, 8, 15, 7, 4, e 17. Para ficar mais claro, veja a explicação a seguir:

 

---chave: cipher

mensagem: pipoca

Sabemos que ao utilizar a palavra "cipher" como chave, devemos avançar a quantidade de caracteres da mensagem na seguinte ordem: 2, 8, 15, 7, 4, e 17. Aplicando esta regra, a mensagem codificada ficaria da seguinte forma:

---chave: cipher

mensagem: rqevgr

Agora que vimos alguns exemplos históricos, vamos ver exemplos mais práticos de dois tipos de criptografia comuns utilizados no PHP, que são o MD5 e o AES.

Funções utilizadas neste código:

CHR - Retorna um caractere de acordo com o valor ASCII informado.

CTYPE_UPPER - Verifica se os caracteres da string informada são maiúsculos.

ORD - Retorna o valor ASCII de um caractere.

STRLEN - Retorna o tamanho de uma string.

STRTOUPPER - Converte uma string em caracteres maiúsculos.

 

Criptografia MD5

 

MD5 é a abreviação de Message-Digest algorithm 5 e foi criado em 1991 por Ronald Rivest. Esta é uma forma bem conhecida de criptografia. Ela pega uma mensagem de qualquer tamanho e produz um hash de 128 bits, retornando um hash hexadecimal de 32 caracteres. Ao contrário dos exemplos anteriores que vimos neste artigo, ele não pode ser revertido, por isso é chamado de um método de criptografia unidirecional. 

A sua implementação no PHP é muito simples:

 

$mensagem = "Mensagem secreta";

$hash = hash("md5", $message);

echo $hash;

 

A função hash recebe dois argumentos, o primeiro é o algoritmo de criptografia que será utilizado, e o segundo é a mensagem que desejamos criptografar.

Uma outra forma mais simples de fazer isso:

 

$mensagem = "Mensagem secreta";

$hash = md5($message);

echo $hash;

 

Apesar de popular, não é considerado um método seguro, porque podem ocorrer colisões, ou seja, mensagens diferentes que geram o mesmo hash. Apesar de não ser recomendado para armazenar senhas, pode ser utiilzado para outras coisas onde a segurança não é tão importante, com por exemplo hash de arquivos.

Um outro método mais seguro é o AES

 

Criptografia AES

 

AES é a abreviação de Advanced Encryption Standard.  Este é um algortimo que usa uma chave simetrica, é um método de criptografia rápido e seguro. Para implementar essa criptografia utilizamos as funções openssl_encrypt e openssl_decrypt. Veja a seguir um exemplo:

 

$string = "Esta é uma mensagem criptografada";

$algoritmo = "AES-256-CBC";

$chave = "BLOGBINS";

$iv = "h5bko7vkh1dybvrv";

$mensagem = openssl_encrypt($string, $algoritmo, $chave, OPENSSL_RAW_DATA, $iv);

$mensagem_string = base64_encode($mensagem);

echo "Senha original:" . $string;

echo "<br>";

echo "Senha criptografada:" . $mensagem_string;

echo "<hr>";

$mensagem = openssl_decrypt(base64_decode($mensagem_string), $algoritmo, $chave, OPENSSL_RAW_DATA, $iv);

echo "Senha descriptografada:" . $mensagem; 

echo "<hr>";

 

Perceha que as funções openssl_encrypt e openssl_decrypt recebem a mesma quantidade de argumentos. O primeiro argumento é a string que desejamos criptografar. O segundo argumento é o algoritmo de criptografia a ser utilizado, as opções disponíveis podem ser listadas utilizando o método openssl_get_cipher_methods. O terceiro parâmetro é a palavra chave utilizada para criptografar ou descriptografar a mensagem.  O quarto parâmetro, onde informamos OPENSSL_RAW_DATA, força o retorno do resultado em sua forma original, que é raw data. Finalmente, o último parâmetro é o chamado vetor de inicialização, ela consiste de uma string randômica que é utilizada para garantir que a criptografia é única, evitando colisões.

Quando retornamos os dados como RAW data será necessário utiilzar o base64_encoded para transformar a resposta numa string. Se você não quiser fazer o base64 encoded/decoded, pode passar NULL para o quarto parâmetro, o resultado final será o mesmo.

 

$string = "Esta é uma mensagem criptografada";

$algoritmo = "AES-256-CBC";

$chave = "BLOGBINS";

$iv = "h5bko7vkh1dybvrv";

$mensagem = openssl_encrypt($string, $algoritmo, $chave, NULL, $iv);

echo "Senha original:" . $string;

echo "<br>";

echo "Senha criptografada:" . $mensagem;

echo "<hr>";

$mensagem = openssl_decrypt($mensagem, $algoritmo, $chave,NULL, $iv);

echo "Senha descriptografada:" . $mensagem; 

echo "<hr>";

 

 

Outros conteudos que podem ser de seu interesse

Calculando distâncias com PHP
04/06/2023PHP

Calculando distâncias com PHP

Veja como calcular a distância entre duas coordenadas com PHP

Saiba mais...
Calculando juros simples e compostos com PHP
20/12/2020PHP

Calculando juros simples e compostos com PHP

Aprenda como trabalhar com juros simples e compostos utilizando PHP

Saiba mais...

Conteúdo sobre banco de dados sem complicação!