ESP32 – Segurança e proteção da flash

esp segurança destaque

Neste artigo trataremos, de forma fácil e rápida, um assunto muito importante para quem pretende comercializar produtos com o ESP32, a segurança do seu hardware com o código presente na memória flash, a fim de impedir clonagem, furto e etc.

Utilizaremos a ESP-IDF v4.0-dev-76-g96aa08a0f-dirty (Ubuntu) para todos artigos desta série e não será abordado sobre como utilizar a IDF, sendo dever do leitor conhecer o funcionamento. Mais sobre a IDF: https://github.com/espressif/esp-idf

image1
Figura 1 – Protegendo o ESP32.

Explicando em miúdos

Todo código (firmware) transferido ao ESP32 fica salvo, na maioria das versões, na memória flash externa, que diminui ainda mais a segurança, já que alguém pode simplesmente removê-la para leitura em um hardware externo e clonar, em segundos, nosso código que pode ter demorado anos para ser desenvolvido. Mesmo se a flash for embutida, como na versão “PICO”, é possível exportar todo conteúdo da flash com apenas um comando no terminal. Então, se todo conteúdo pode ser facilmente obtido, devemos nos proteger e é isso que a criptografia da flash do ESP32 nos proporciona.

Criptografia da flash

Atenção

  • Não abordaremos todas funções e características da criptografia da flash, sendo necessário que você estude MUITO BEM a documentação oficial, a fim de evitar qualquer dor de cabeça que pode ocorrer conforme a IDF se atualiza. Não somos responsáveis por qualquer uso errado de sua parte.
  • A criptografia da flash limita como e/ou quantas vezes é possível fazer upload de novos códigos. Caso feito incorretamente, você pode perder seu ESP32 e não será mais possível regrava-lo.
  • Abordaremos, por motivos de didática, apenas sobre a criptografia com uma chave pré-gerada, assim, podemos regravar o ESP32 sem qualquer restrição de quantidade.
  • Em ambientes que é necessário a maior segurança disponível, você não deve utilizar uma chave pré-gerada, deixando o próprio ESP32 gerar a sua, sendo individual para cada hardware. Além de também habilitar o Secure boot que não abordaremos aqui.

A criptografia da flash (AES-256) é uma característica presente no ESP32 que criptografa o conteúdo presente na flash. Quando habilitado, leituras físicas sem a chave não são suficientes para recuperar o conteúdo. Sendo assim, nos protegemos de quem tentar exportá-la para clonagem e etc. A chave é gravada em um bloco de eFuse, que pode ser protegido contra leitura e escrita (padrão) e, conhecendo a chave, podemos regravar códigos sem a limitação de quantidade, diferentemente do caso onde o ESP32 gera sua própria chave, onde estamos limitados em até 3 uploads físicos.

Vamos observar alguns itens relevantes sobre a criptografia:

  • Em um upload plaintext, o binário original (cru) é enviado ao microcontrolador.
  • Em um upload criptografado, o binário é enviado ao microcontrolador já criptografado pela IDF.
  • O eFuse “FLASH_CRYPT_CNT” (7-bit) é responsável pela permissão de uploads plaintext, pela contagem de uploads físicos plaintext (até 3x) e pelo controle do bootloader para criptografar o conteúdo da flash. Pode ser protegido contra R/W. Após 3 uploads plaintext, este eFuse chegará em seu máximo e aceitará apenas uploads criptografados.
    • Quando for um número par, o bootloader irá criptografar todo conteúdo da flash, logo, é necessário o upload plaintext.
    • Quando for um número ímpar, o bootloader não irá criptografar o conteúdo da flash, logo, é necessário o upload criptografado.
  • Se a chave não for conhecida (pré-gerada), temos no máximo 3 uploads físicos disponíveis (plaintext), que também nos permite desabilitar a criptografia. Se o “FLASH_CRYPT_CNT” for protegido enquanto ímpar, não será possível novos uploads plaintext.
  • Os binários “Bootloader”, “Partition table”, “OTA DATA”, todas “APP (seu código)” e as partições marcadas com a flag “encrypted” na tabela de partição serão criptografados. Partições que não estiverem marcados com “encrypted” não serão criptografados e poderão ser lidos externamente, tenha atenção ao utilizar APIs para acesso da flash como NVS e SPIFFS.
  • Se o “FLASH_CRYPT_CNT” não for protegido corretamente e/ou ainda houver alguma tentativa para upload plaintext, invasores podem inserir códigos maliciosos e ler o conteúdo de forma descriptografada pelo próprio ESP32 sem conhecimento da chave. Por causa disto, é comum protegê-lo contra escrita, a fim de evitar uploads plaintext.

Cientes dos detalhes básicos (há dezenas de detalhes extras na documentação oficial que você deve ler antes de efetuar os testes abaixo), vamos testar a criptografia da flash e ver se realmente funciona! Lembrando que utilizaremos a IDF no Ubuntu e quase todos comandos podem mudar de acordo com seu computador, projeto, endereços e muitas outras coisas. Os comandos utilizados aqui podem não servir para você, logo, terá que alterá-los de acordo com seu projeto, caminho de arquivos e etc. Este artigo é apenas uma demonstração e deve ser tomado como base, não seguido ao pé da letra. Os scripts utilizados estão na pasta da IDF, “esp-idf/components/esptool_py/esptool/”, tome bastante atenção ao uso dos caminhos dos arquivos e scripts, pois você pode estar tentando rodar o comando no local errado. Também tenha atenção na porta utilizada, seu ESP32 pode estar em uma porta diferente da nossa.

Primeiramente, vamos testar um código simples apenas para verificar sobre o que foi citado acima, sobre a leitura (clonagem) da memória flash sem proteção. Você pode ignorar essa parte.

Quando fazemos um upload padrão para placa, o computador utiliza um script python (esptool.py) com o comando “make flash”, que basicamente compila e faz upload (plaintext). Com o código enviado, vamos fazer uma leitura (sumário) dos eFuses para comparação após ativar a criptografia:

Sabendo que este ESP32 não está protegido, podemos exportar o conteúdo da flash e usar para clonagem, engenharia reversa ou o que der na cabeça! Vamos ver se achamos a palavra usada no ESP_LOGI(), “Embarcados…”, ao ler o conteúdo da memória:

Utilizando o comando “hexdump” para ler o arquivo gerado, conseguimos achar a palavra utilizada no código sem criptografia:

image2 6
Figura 2 – Memória do ESP32 clonada antes da criptografia.

Agora que a clonagem foi demonstrada com apenas um comando no terminal, indicando que seu produto sem proteção está totalmente vulnerável nas mãos de alguém, vamos nos proteger ativando a criptografia.

  1. Criando a chave

Utilizaremos o próprio script da IDF para criar uma chave (256b), mas você pode utilizar qualquer método ou chave que desejar. O comando exportará a chave no arquivo “key.bin”, que você deve deixar uma cópia dentro da pasta do seu projeto, ficando algo similar com o nosso:

image4 3
Figura 3 – Pasta do projeto com chave.
  1. Gravando a chave pré-gerada no eFuse

O comando acima gravou nossa chave no eFuse e automaticamente protegeu contra R/W, o que impede de qualquer um conseguir lê-la ou alterá-la. Apesar deste comando escrever no terminal a chave gravada, ao tentar ler a chave diretamente do eFuse (sumário) como feito anteriormente, é retornado:

Agora com uma chave conhecida no eFuse, temos a possibilidade de uploads ilimitados (criptografados), o que é muito interessante na fase de desenvolvimento.

  1. Ativando a criptografia da flash

Agora com a chave gravada, basta ativar a criptografia da flash no “menuconfig” em “Security features”.

image5 3
Figura 4 – Ativando a criptografia da flash.

Atenção, se você não gravou a chave pré-gerada, ao dar o upload de um novo código com a criptografia ativada, o próprio ESP32 irá gerar uma chave que nem você, nós ou a Espressif poderá ler, lhe restando 3 uploads (plaintext) e/ou tentativas para desativar a criptografia, tome cuidado! Atualizações OTA são ilimitadas mesmo sem conhecimento da chave.

Após ativar a criptografia, vamos refazer o upload do código utilizado anteriormente de forma padrão, como utilizado antes (upload plaintext). Nesse primeiro boot, o bootloader irá criptografar todo conteúdo da memória e reiniciará, esse processo pode demorar um pouco então aguarde. Após o ESP32 reiniciar, indicando que a criptografia foi ativada, vamos fazer uma nova leitura da flash para ver se encontramos a palavra “Embarcados…” novamente.

image3 5
Figura 5 – Memória do ESP32 clonada após criptografia.

Além da palavra “Embarcados…” não ser encontrada, nenhum texto legível foi visto, o que anteriormente era facilmente visto (Strings utilizadas pela própria IDF). O mesmo endereço que encontramos a palavra anteriormente, agora, não passa de um texto corrompido para quem tentar ler sem a chave!

Se olharmos o sumário dos eFuses novamente, podemos ver que o “FLASH_CRYPT_CNT” foi de 0 para 1, indicando que agora só aceita uploads criptografados, logo, se utilizarmos o upload padrão (plaintext), o ESP irá ficar em boot-loop com a seguinte mensagem:

O “FLASH_CRYPT_CNT” não é protegido contra escrita por padrão, logo, alguém ainda pode desativar a criptografia, fazer upload (plaintext) e ler sua flash de forma descriptografada, logo, devemos proteger este eFuse contra escrita ENQUANTO estiver em um número ímpar ou utilizar o Secure boot.

  1. Protegendo o eFuse

Vamos proteger o eFuse “FLASH_CRYPT_CNT” contra escritas para impossibilitar qualquer tipo de upload sem conhecimento da chave, isso automaticamente permite que suas placas estejam protegidas de uploads não permitidos, forçando seu hardware a aceitar apenas códigos que tenham sidos criptografados com a chave. Apesar desta proteção funcionar com o mesmo intuito do Secure boot (impossibilitar uploads não permitidos), há alguns casos em que manter o Secure boot ativado pode ser melhor, entretanto, na maioria dos casos, protegendo o eFuse já não precisamos do Secure boot (pesquise melhor sobre isso se for usar em ambientes agressivos onde a segurança deve prevalecer).

Antes de proteger a escrita, devemos certificar-se que ele está em algum número ímpar através do sumário, que nos retornou “FLASH_CRYPT_CNT Flash encryption mode counter = 1 R/W (0x1)”

A partir de agora, é impossível desabilitar a criptografia ou enviar códigos que não estejam criptografados pela chave presente no ESP32.

Ok, se o upload padrão não funciona mais, o que faremos? Criptografamos antes de enviar! Apesar de ser utilizado AES-256, a Espressif usa métodos diferentes de funcionamento (detalhes na documentação oficial), logo, precisamos criptografar pelo próprio script da IDF

  1. Criptografando os binários

O upload agora deve ser feito “manualmente”, sendo necessário criptografar e enviar os binários criptografados. Essa parte depende muito de projeto para projeto, principalmente nos caminhos de arquivos e endereço da memória, tome muita atenção.

5.1 Crie uma pasta “enc” dentro do seu projeto, ela irá guardar os binários criptografados pelo script.

5.2 Com o terminal aberto na pasta do seu projeto, use o comando “make all” para descobrir o que e onde os arquivos são gravados.

Podemos ver que nesse nosso projeto, onde utilizamos OTA e uma tabela de partições (custom), é feito o upload de 4 binários nos seus respectivos endereços.

ota_data_initial.bin: 0x363000.

bootloader.bin: 0x1000.

esp32.bin (o código em si): 0x10000.

partitions.bin: 0x8000.

Iremos criptografá-los individualmente e posteriormente, efetuar o upload. Não se esqueça que os caminhos dos arquivos devem ser alterados para o seu projeto.

5.3 Com o terminal aberto na pasta de scripts, use os comandos abaixo e não se esqueça de tomar muita atenção com os endereços de memória e caminho dos binários.

5.4 Faça o upload dos binários criptografados pelo comando: 

Após o upload criptografado, o ESP32 iniciará normalmente como se nada tivesse acontecido. Esse método apesar de ser manual, pode ser automatizado por um script (bash), basta colocá-los num arquivo e executar no terminal.

Agora que a proteção do ESP32 esta ativada, podemos ficar mais relaxados na questão sobre alguém clonar nosso firmware, já que não será possível sem a chave gravada. Você deve ler toda documentação oficial e também pode ser interessante utilizar o Secure boot sem criptografia da flash, análise seu projeto e mãos na massa!

Referências

https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

[wpseo_breadcrumb]
Comentários:
Notificações
Notificar
guest
6 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Willian Henrique
23/05/2020 12:32

Parabêns pelo artigo, realmente muito bom e útil. Uma coisa que estou tentando é gerar o binário criptografado para entregar para outra pessoa, é possível? Nestes exemplos o binário sempre fica descriptografado, abraços,

Willian Henrique

R
R
27/02/2020 17:31

Muito legal, mas e para o caso de verificar o conteúdo da Flash automaticamente? Tem algum exemplo de CRC self-test? Para certificar de que não ocorreu corrompimento do firmware em algum momento, chips STM32 tem um módulo de hardware CRC, o ESP32 tem esta funcionalidade?

José Morais
José Morais
Reply to  R
27/02/2020 18:52

Sim, sua pergunta me parece estar mais ligada com atualizações remotas (OTA), mas de qualquer maneira, o arquivo binário enviado ao ESP32 tem “Magic Byte” e também vários bytes de CRC. O “hardware boot”, responsável por selecionar qual partição sera “bootada”, já faz a verificação se a partição esta OK ou corrompida.

Fernando Ginez da Silva
Fernando Ginez da Silva
04/12/2019 14:45

Parabéns pelo artigo! Muito útil.
Vale apenas acompanhar o desenrolar da vulnerabilidade de segurança que encontraram no chip. Veja o CVE (https://nvd.nist.gov/vuln/detail/CVE-2019-17391) e o artigo do descobridor da falha (https://limitedresults.com/2019/11/pwn-the-esp32-forever-flash-encryption-and-sec-boot-keys-extraction/).
Abs!

Alexandre Fernandes dos Anjos
Membro
26/09/2019 18:02

Ótimo artigo José, muito didático e detalhado…

Talvez você goste:

Séries

Menu
Privacy Settings saved!
Configurações de Privacidade

Entenda quais dados e informações usamos para ter melhor entrega de conteúdo personalizado para você.

These cookies are necessary for the website to function and cannot be switched off in our systems.

Para usar este site, usamos os seguintes cookies tecnicamente exigidos

  • wordpress_test_cookie
  • wordpress_logged_in_
  • wordpress_sec

Decline all Services
Accept all Services