Continuando a série “Segurança da Informação“, neste artigo será mostrada a criptografia AES, uma criptografia de blocos que é geralmente mais segura e confiável que RC4. A criptografia Advanced Encryption Standard (AES) é talvez a criptografia simétrica mais utilizada no mundo, sendo altamente confiável e compatível com os mais diversos sistemas operacionais e relacionados.
As criptografias simétricas de blocos, como AES, contam com diversos métodos de operação criados ao longo do tempo, para melhorar ou obter diferentes resultados. Veja alguns deles:
ECB (Electronic CodeBook)
Modo mais simples de criptografia. A mensagem (plaintext) é dividida em blocos, os quais são criptografados separadamente. Blocos iguais de plaintext geram o mesmo output (ciphertext). É o único método que não usa IV (vetor de inicialização).
Vetor de inicialização (IV)
O vetor de inicialização pode ser entendido como um “bloco falso”, utilizado no início do processo de cifragem, gerando aleatoriedade no sistema. Exceto ECB, todos fazem o uso do IV.
CBC (Cypher Block Chaining)
Para cada bloco de plaintext é realizada a operação XOR junto com o bloco cifrado anterior antes dele ser criptografado. Com isso os blocos futuros são dependentes dos blocos anteriores. Com IV aleatório em cada cifragem, é possível manter a aleatoriedade do ciphertext mesmo com um plaintext igual.
CFB (Cipher FeedBack)
Similar ao CBC, permite que a cifra de bloco vire uma espécie de cifra de fluxo, se parecendo com o RC4. Este modo é interessante quando a transmissão de dados pela rede é fraca e você faz a criptografia de pequenos dados.
CTR (Counter)
Transforma a cifra de bloco em cifra de fluxo (similar a CFB), entretanto é adicionado um contador para gerar aleatoriedade no sistema de criptografia. O método mais simples é apenas um incrementador.
Na prática
Vamos novamente utilizar o ESP32 para executar essas criptografias. A biblioteca MbedTLS permite os modos ECB, CBC, CFB e CTR. Faremos como no material anterior, criptografando uma mensagem e descriptografando a mensagem encriptada para verificar os resultados.
Obs: Estamos usando chaves fixas e simples apenas para demonstração e didática. Você deve usar chaves e IV’s aleatórios a fim de garantir a segurança dessas informações.
ECB
#include <mbedtls\aes.h>
mbedtls_aes_context aes;
unsigned char key[] = "1234567890123456";
String bla = "Embarcados";
unsigned char out[16];
unsigned char inp[16];
void setup()
{
Serial.begin(115200);
int size = sizeof(bla);
for (int i = 0; i < size; i++)
{
inp[i] = bla[i];
}
for (int i = size; i < 16; i++)
{
inp[i] = 0;
}
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc(&aes, key, 128);
}
void loop()
{
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, inp, out);
Serial.printf("\nChipertext: ");
for (int i = 0; i < 16; i++)
{
Serial.print(out[i], HEX);
Serial.print(" ");
}
delay(5000);
}
Chave: “1234567890123456”
Plaintext: “Embarcados”
O ciphertext retornado para nosso plaintext em ECB é sempre igual, já que é usado o mesmo plaintext. Você deve ter atenção ao usar comandos estáticos em seu sistema, que irá sempre gerar um ciphertext igual.
CBC
#include <mbedtls\aes.h>
mbedtls_aes_context aes;
unsigned char key[] = "1234567890123456";
unsigned char iv[] = "1234567890123456";
String bla = "Embarcados";
unsigned char out[16];
unsigned char inp[16];
void setup()
{
Serial.begin(115200);
int size = sizeof(bla);
for (int i = 0; i < size; i++)
{
inp[i] = bla[i];
}
for (int i = size; i < 16; i++)
{
inp[i] = 0;
}
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc(&aes, key, 128);
}
void loop()
{
Serial.print("\n\nIV: ");
for (int i = 0; i < 16; i++)
{
Serial.print(iv[i], HEX);
Serial.print(" ");
}
mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, 16, iv, inp, out);
Serial.printf("\nChipertext: ");
for (int i = 0; i < 16; i++)
{
Serial.print(out[i], HEX);
Serial.print(" ");
}
delay(5000);
}
Chave: “1234567890123456”
IV (inicial): “1234567890123456”
Plaintext: “Embarcados”
Veja que para o mesmo plaintext, houve diversas saídas (ciphertext). Isso acontece pois o próprio sistema do MbedTLS atualiza o nosso vetor de inicialização. Perceba que o IV é igual aos dados da última criptografia (ciphertext). Se você precisa do IV fixo, terá que salvar em alguma variável auxiliar. Agora, vamos analisar a primeira e a segunda cifragem com a ferramenta externa:
Lembrando: o IV deve ser colocado em Hexadecimal.
Utilizamos o ciphertext com o IV e chave corretos, veja que o plaintext está certo.
Agora, vamos incrementar a chave e o IV, respectivamente, e ver o que acontece com o plaintext:
Fizemos o incremento do último número da nossa chave e IV, e veja que interessante. A alteração mínima da chave foi o suficiente para deixar o plaintext inesperado, porém o mesmo não ocorreu com a alteração do IV, que gerou apenas um incremento no local alterado.
Para finalizar, vamos analisar a próxima cifra que alterou automaticamente o IV, deixando o ciphertext diferente:
Chegamos à conclusão que a alteração completa ou de boa parte do IV gera um plaintext inesperado. Perceba que na figura 12 usamos o IV que foi definido inicialmente e mesmo assim a mensagem retornada não está correta. O MbedTLS fez alteração do IV com o ciphertext da última encriptação e, ao usar esse novo IV, o plaintext foi gerado corretamente (Figura 13).
A premissa de sigilo de dados é amplamente utilizada, entretanto precisamos mais que apenas sigilo para garantir um dado seguro, como, por exemplo, assinaturas digitais. Devemos implementar a segurança necessária para o projeto de acordo com sua utilização e nunca se esquecer que em algum momento alguém pode “bisbilhotar” seus dados e gerar terríveis danos. Ficará como lição de casa a implementação de certificados e assinaturas digitais. Bons estudos!
















