ÍNDICE DE CONTEÚDO
- Segurança da informação para IoT
- Segurança da Informação – Criptografia AES
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
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 |
#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
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 46 47 48 49 50 51 52 |
#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!