Compilando o firmware com Secure Boot e Flash Encryption
Não vou ficar perdendo tempo explicando sobre o Flash Encryption porque eu já expliquei, se quiser entender, leia o tutorial anterior na parte de "Preciso ativar Flash Encryption?".
Nesse procedimento, a ideia é gerar a chave de Flash Encryption no computador, manter uma cópia dela em segurança e criptografar os binários antes de gravar eles usando o ROM Download. Para isso funcionar, a mesma chave também precisa estar gravada e protegida em um bloco eFuse do ESP32-S3. O hardware usa essa chave para descriptografar o conteúdo durante a execução.
Assim como no tutorial anterior, vou usar o ESP-IDF 5.5.1, que é usado pelo Projeto do PicoKeys. Os projetos foram compilados usando o commits abaixo:
### FIDO
Hash: ade770281dd4fd8c627add34ed078f56ec40a07b
tag: nightly-main e nightly-development
### HSM
Hash: 5d6a32c81b2367fb83e5320400f61217d2bd0d2f
tag: nightly-master e nightly-development
A gravação de eFuses é permanente e irreversível. Uma configuração incorreta pode impedir a inicialização da placa, impossibilitar futuras atualizações ou tornar ela inutilizável.
Não me responsabilizo por quaisquer danos, falhas ou perdas decorrentes da execução dos procedimentos descritos neste guia, incluindo problemas causados pela compilação, configuração ou gravação do firmware.
Antes de realizar qualquer procedimento, recomendo a leitura da documentação oficial dos fabricantes e dos projetos envolvidos. Cada usuário é responsável por compreender os riscos e verificar a compatibilidade das instruções com seu dispositivo.
Clonando os projetos e instalando o ESP-IDF 5.5.1
No Ubuntu, instale as dependências indicadas pelo ESP-IDF. Depois faça os clones:
# Crie um diretório novo para esse projeto:
mkdir -p ~/src/picokeys-fe && cd ~/src/picokeys-fe
# Clone o ESP-IDF na versão 5.5.1:
git clone --branch v5.5.1 --recursive https://github.com/espressif/esp-idf.git esp-idf
# Clone o Pico FIDO:
git clone --recursive https://github.com/polhenarejos/pico-fido.git
# Clone o Pico HSM:
git clone --recursive https://github.com/polhenarejos/pico-hsm.git
Agora intale o esp-idf e carregue o ambiente:
# Entre no diretório do projeto esp-idf:
cd esp-idf
# Instalar o esp-idf pra esp32-s3:
unset IDF_PYTHON_ENV_PATH ; ./install.sh esp32s3
# Carregue o ambiente ESP-IDF:
. ./export.sh
# Verifique a versão:
$ idf.py --version
ESP-IDF v5.5.1
# Volte para o diretório base:
cd ~/src/picokeys-fe
Ajustes necessários para HSM e FIDO
Assim como descrito nos outros procedimentos, temos que fazer os ajustes necessários tanto no FIDO quanto no PICO para corrigir os problemas relacionado a segurança da chave e qualquer outro ajuste que seja necessário.
Não vou desmontrar o que precisa ser feito, para não replicar o mesmo processo que já foi tutorial anterior nesse aqui.
Gerando as chaves
Para usar Secure Boot V2, precisamos de uma chave privada RSA-3072. Ela será usada para assinar o bootloader e a aplicação. O ESP32-S3 guarda nos eFuses o digest da chave pública correspondente.
A chave de Flash Encryption é outra chave, ela usa AES-XTS e será usada para criptografar os binários no computador. Essa chave também precisa ser provisionada no ESP32-S3 em um bloco eFuse com a finalidade XTS_AES_128_KEY.
Vamos começar criando os diretórios e restringindo as permissões:
mkdir -p ~/.config/picokeys/signing
mkdir -p ~/.config/picokeys/flash-encryption
chmod 700 ~/.config/picokeys/signing ~/.config/picokeys/flash-encryption
umask 077
Agora gere a chave de assinatura (Secure Boot):
espsecure.py generate_signing_key --version 2 --scheme rsa3072 \
~/.config/picokeys/signing/secure-boot.pem
chmod 600 ~/.config/picokeys/signing/secure-boot.pem
Vamos obter o MAC da placa, esse MAC será apenas um nome, um identificador que poderia ser qualquer coisa. Vou usar ele para facilitar identificar a qual placa pertence essa chave. Habilite o Download Mode (Segure BOOT, pressione e solte RESET e então solte BOOT).
Depois execute o comando abaixo para ver em qual porta ele subiu:
$ ls -l /dev/ttyACM* /dev/ttyUSB*
/dev/ttyACM0
No meu caso foi em /dev/ttyACM0, vou usar esse nome no comando abaixo para gravar o firmware. Se o use foi outro, use o nome que apareceu ai, mas certifique-se de que é o ESP32-S3 correto que você quer gravar. Agora vamos ver o MAC da placa:
$ esptool.py --chip esp32s3 --port /dev/ttyACM0 read_mac
esptool.py v4.12.0
Serial port /dev/ttyACM0
Connecting...
Chip is ESP32-S3 (QFN56) (revision v0.2)
Features: WiFi, BLE, Embedded PSRAM 8MB (AP_3v3)
Crystal is 40MHz
USB mode: USB-Serial/JTAG
MAC: 68:ee:8f:51:e0:38
Uploading stub...
Running stub...
Stub running...
MAC: 68:ee:8f:51:e0:38
Hard resetting via RTS pin...
Agora que temos o MAC, vamos usar ele como ID (68ee8f51e038). O comando abaixo vai gerar uma chave de 256 bits (usada para Flash Encryption):
espsecure.py generate_flash_encryption_key \
~/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin
chmod 600 ~/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin
Troque
68ee8f51e038por um identificador seu. Use uma chave FE diferente para cada dispositivo e mantenha uma cópia de segurança protegida. Se perder essa chave, você não vai mais conseguir usar essa placa.
Para salvar esse arquivo em algum lugar seguro, como um cofre de senhas, podemos fazer assim:
xxd -p -c 256 ~/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin
Você vai ver um hash de 256 bits:
11c860d531eec46bb9b29319a798da103e7c121c7dcbe9aa2b251a5a855daae6
Salve esse código em um lugar seguro. Para restaurar de volta a arquivo binário, podemos fazer assim:
xxd -r -p chave.hex pico-68ee8f51e038-restaurado.bin
O arquivo chave.hex deve conter o hash de 256 bits.
Associando o digest da chave ao firmware PicoKeys
Agora vamos calcular o digest da chave pública para validar a assinatura do firmware:
espsecure.py digest_sbv2_public_key \
--keyfile ~/.config/picokeys/signing/secure-boot.pem \
--output ~/.config/picokeys/signing/public-digest.bin
O comando acima gera um arquivo binário de 32 bytes, depois precisamos converter o conteúdo para o formato hexadecimal:
python3 - ~/.config/picokeys/signing/public-digest.bin <<'PY'
from pathlib import Path
import sys
digest = Path(sys.argv[1]).read_bytes()
if len(digest) != 32:
raise SystemExit(f"Esperados 32 bytes; recebidos {len(digest)}")
for start in range(0, 32, 8):
print(" " + ", ".join(f"0x{b:02x}" for b in digest[start:start+8]) + ",")
PY
Tanto para FIDO quanto para HSM, edite o arquivo:
vim pico-keys-sdk/src/otp/otp_esp32.c
Procure por esp_secure_boot_digest[32] e substitua os 32 bytes pelo resultado do comando anterior, assim como desmontrado no tutorial anterior. Essa alteração informa ao SDK qual digest será usado durante para validar a assinatura do firmware. Ela não assina o firmware e também não grava nada nos eFuses.
Configurando o Secure Boot e a Flash Encryption
No diretório raiz de cada projeto, limpe o build e configure o alvo ESP32-S3:
idf.py fullclean
idf.py set-target esp32s3
idf.py menuconfig
Em Security features, configure:
Enable hardware Secure Boot in bootloader;Select secure boot version (Enable Secure Boot version 2);Sign binaries during build;Secure boot private signing key: caminho da chave RSA privada correspondente ao digest aceito pela placa;Enable flash encryption on boot;Enable usage mode:Release;UART ROM download mode:(Permanently switch to Secure mode (recommended)).
Em Partition Table, altere o offset da tabela de 0x8000 para 0x10000. Salve com s e saia com q. Depois confira se as opções estão corretas:
$ grep -E \
-e '^CONFIG_SECURE_BOOT=' \
-e '^CONFIG_SECURE_BOOT_V2_ENABLED=' \
-e '^CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES=' \
-e '^CONFIG_SECURE_BOOT_SIGNING_KEY=' \
-e '^CONFIG_SECURE_FLASH_ENC_ENABLED=' \
-e '^CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=' \
-e '^CONFIG_SECURE_FLASH_ENCRYPTION_AES128=' \
-e '^CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=' \
-e '^CONFIG_PARTITION_TABLE_OFFSET=' \
sdkconfig
CONFIG_SECURE_BOOT=y
CONFIG_SECURE_BOOT_V2_ENABLED=y
CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES=y
CONFIG_SECURE_BOOT_SIGNING_KEY="/home/bruno/.config/picokeys/signing/secure-boot.pem"
CONFIG_SECURE_FLASH_ENC_ENABLED=y
CONFIG_SECURE_FLASH_ENCRYPTION_AES128=y
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=y
CONFIG_PARTITION_TABLE_OFFSET=0x10000
Edite o arquivo abaixo, seja FIDO ou HSM:
vim pico-keys-sdk/config/esp32/partitions.csv
A tabela padrão já usa factory em 0x20000 e part0 em 0x200000, com tamanho de 1M. Então não precisamos alterar esses valores, o mais importante é adicionar a flag encrypted no final da linha part0, ela deve ficar assim:
part0, 0x40, 0x1, 0x200000, 1M, encrypted
O ESP-IDF criptografa as partições de firmware. Já a partição part0 é de dados, por isso precisamos adicionar a flag encrypted, para que ela seja criptografada.
Este procedimento considera uma placa ESP32-S3 zerada, sem Secure Boot e Flash Encryption ativos. Antes de gravar o firmware, confirme que ele foi assinado com a chave privada que você gerou e que a chave de Flash Encryption usada para criptografar os arquivos é a mesma que será provisionada na placa.
Na primeira inicialização, o firmware pode gravar e proteger eFuses para ativar essas funções. Essa alteração é permanente. Faça um backup protegido das chaves e valide o build e as imagens no computador antes de iniciar a placa com esse firmware.
Gerando e validando o firmware assinado FIDO e HSM
Agora vamos novamente ativar o ambiente ESP-IDF 5.5.1 (só por precaução) e compilar o Pico FIDO:
. ~/src/picokeys-fe/esp-idf/export.sh && export IDF_TARGET=esp32s3
cd ~/src/picokeys-fe/pico-fido
idf.py -DIDF_TARGET=esp32s3 -DVIDPID=Yubikey5 -DENABLE_EDDSA=ON build
Estou usando
-DENABLE_EDDSA=ONpara ativar o suporte a chaves ed25519-sk para ser usado no SSH via FIDO.
Para o Pico HSM:
. ~/src/picokeys-fe/esp-idf/export.sh && export IDF_TARGET=esp32s3
cd ~/src/picokeys-fe/pico-hsm
idf.py -DIDF_TARGET=esp32s3 -DVIDPID=YubiHSM build
Depois do build, precisamos validar as assinaturas do bootloader e da aplicação, igual o procedimento anterior. Para FIDO:
cd ~/src/picokeys-fe/pico-fido
$ idf.py secure-verify-signature \
--version 2 \
--keyfile ~/.config/picokeys/signing/secure-boot.pem \
bootloader/bootloader.bin
Executing action: secure-verify-signature
Running espsecure in directory /home/bruno/src/picokeys-fe/pico-fido/build
Executing "/home/bruno/.espressif/python_env/idf5.5_py3.12_env/bin/python -m espsecure verify_signature --version 2 --keyfile /home/bruno/.config/picokeys/signing/secure-boot.pem bootloader/bootloader.bin"...
espsecure.py v4.12.0
Signature block 0 is valid (RSA).
Signature block 0 verification successful using the supplied key (RSA).
Signature block 1 invalid. Skipping.
Signature block 2 invalid. Skipping.
$ idf.py secure-verify-signature \
--version 2 \
--keyfile ~/.config/picokeys/signing/secure-boot.pem \
pico_fido.bin
Executing action: secure-verify-signature
Running espsecure in directory /home/bruno/src/picokeys-fe/pico-fido/build
Executing "/home/bruno/.espressif/python_env/idf5.5_py3.12_env/bin/python -m espsecure verify_signature --version 2 --keyfile /home/bruno/.config/picokeys/signing/secure-boot.pem pico_fido.bin"...
espsecure.py v4.12.0
Signature block 0 is valid (RSA).
Signature block 0 verification successful using the supplied key (RSA).
Signature block 1 invalid. Skipping.
Signature block 2 invalid. Skipping.
Para HSM:
cd ~/src/picokeys-fe/pico-hsm
idf.py secure-verify-signature \
--version 2 \
--keyfile ~/.config/picokeys/signing/secure-boot.pem \
bootloader/bootloader.bin
Executing action: secure-verify-signature
Running espsecure in directory /home/bruno/src/picokeys-fe/pico-hsm/build
Executing "/home/bruno/.espressif/python_env/idf5.5_py3.12_env/bin/python -m espsecure verify_signature --version 2 --keyfile /home/bruno/.config/picokeys/signing/secure-boot.pem bootloader/bootloader.bin"...
espsecure.py v4.12.0
Signature block 0 is valid (RSA).
Signature block 0 verification successful using the supplied key (RSA).
Signature block 1 invalid. Skipping.
Signature block 2 invalid. Skipping.
idf.py secure-verify-signature \
--version 2 \
--keyfile ~/.config/picokeys/signing/secure-boot.pem \
pico_hsm.bin
Executing action: secure-verify-signature
Running espsecure in directory /home/bruno/src/picokeys-fe/pico-hsm/build
Executing "/home/bruno/.espressif/python_env/idf5.5_py3.12_env/bin/python -m espsecure verify_signature --version 2 --keyfile /home/bruno/.config/picokeys/signing/secure-boot.pem pico_hsm.bin"...
espsecure.py v4.12.0
Signature block 0 is valid (RSA).
Signature block 0 verification successful using the supplied key (RSA).
Signature block 1 invalid. Skipping.
Signature block 2 invalid. Skipping.
Para cada comando, o bloco de assinatura 0 precisa ser válido. Os blocos 1 e 2 podem aparecer como inválidos se não foram usados. Não grave um firmware cuja assinatura não tenha sido validada.
Preparação da placa e da chave FE - Somente Primeiro Firmware
Conecte somente a placa que será usada (essa placa não pode ter secure boot ativo). Depois execute o processo para fazer a placa entrar no Download Mode (Segure BOOT, pressione e solte RESET e então solte BOOT).
Depois execute o comando abaixo para ver em qual porta ele subiu:
$ ls -l /dev/ttyACM* /dev/ttyUSB*
/dev/ttyACM0
No meu caso foi em /dev/ttyACM0, vou usar esse nome no comando abaixo para gravar o firmware. Se o use foi outro, use o nome que apareceu ai, mas certifique-se de que é o ESP32-S3 correto que você quer gravar.
Agora temos que confirmar algumas coisas, comece executando os comandos abaixo:
$ espefuse.py --chip esp32s3 --port "/dev/ttyACM0" summary | grep -E 'ENABLE_SECURITY_DOWNLOAD|DIS_DOWNLOAD_MODE'
DIS_DOWNLOAD_MODE (BLOCK0) Set this bit to disable download mode (boot_mode[3 = False R/W (0b0)
ENABLE_SECURITY_DOWNLOAD (BLOCK0) Set this bit to enable secure UART download mode = False R/W (0b0)
$ esptool.py --chip esp32s3 --port "/dev/ttyACM0" get_security_info | grep -iE 'Secure Boot|Flash Encryption|SPI_BOOT_CRYPT_CNT|BLOCK_KEY1'
BLOCK_KEY1 - USER/EMPTY
Secure Boot: Disabled
Flash Encryption: Disabled
SPI Boot Crypt Count (SPI_BOOT_CRYPT_CNT): 0x0
Esses comandos servem para confirmar alguns dados, como:
- Secure Boot está desabilitado.
- Flash Encryption está desabilitada e
SPI_BOOT_CRYPT_CNTestá em0. - Secure Download Mode está desabilitado.
- O bloco que será usado para FE está vazio e livre.
No procedimento abaixo, BLOCK_KEY1 fica reservado para Flash Ecryption e BLOCK_KEY0 para o digest do Secure Boot. Se os comandos acima não confirmarem que BLOCK_KEY1 está livre, pare e não substitua o bloco por outro sem rever a alocação das chaves.
Agora como requisito da documentação oficial temos que limpar a flash (não vejo porque isso seria necessário, mas vamos seguir a risca) e confira se a chave AES-XTS tem 32 bytes:
$ esptool.py --chip esp32s3 --port "/dev/ttyACM0" erase_flash
esptool.py v4.12.0
Serial port /dev/ttyACM0
Connecting...
Chip is ESP32-S3 (QFN56) (revision v0.2)
Features: WiFi, BLE, Embedded PSRAM 8MB (AP_3v3)
Crystal is 40MHz
USB mode: USB-Serial/JTAG
MAC: 68:ee:8f:51:e0:38
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 4.7 seconds.
Hard resetting via RTS pin...
Agora vamos enviar a chave usada no Flash Encryption para a posição BLOCK_KEY1 da eFuse:
$ espefuse.py --chip esp32s3 \
--port "/dev/ttyACM0" \
burn_key BLOCK_KEY1 "/home/bruno/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin" XTS_AES_128_KEY
espefuse.py v4.12.0
Connecting...
=== Run "burn_key" command ===
Sensitive data will be hidden (see --show-sensitive-info)
Burn keys to blocks:
- BLOCK_KEY1 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??]
Reversing byte order for AES-XTS hardware peripheral
'KEY_PURPOSE_1': 'USER' -> 'XTS_AES_128_KEY'.
Disabling write to 'KEY_PURPOSE_1'.
Disabling read to key block
Disabling write to key block
Check all blocks for burn...
idx, BLOCK_NAME, Conclusion
[00] BLOCK0 is not empty
(written ): 0x0000000000000100000000000000d1f50000000000000000
(to write): 0x000000000000000000000000400000000000000201000200
(coding scheme = NONE)
[05] BLOCK_KEY1 is empty, will burn the new value
.
This is an irreversible operation!
Type 'BURN' (all capitals) to continue.
BURN
BURN BLOCK5 - OK (write block == read block)
BURN BLOCK0 - OK (all write block bits are set)
Reading updated efuses...
Successful
O
burn_keyprotege a chave contra leitura e escrita por padrão.
O procedimento vai pedir para você digitar BURN para continuar o processo, digite e aperte Enter.
Agora vamos conferir o get_security_info novamente, o BLOCK_KEY1 deve ter finalidade XTS_AES_128_KEY e estar protegido contra leitura e escrita.
$ esptool.py --chip esp32s3 --port "/dev/ttyACM0" get_security_info | grep -iE 'Secure Boot|Flash Encryption|SPI_BOOT_CRYPT_CNT|BLOCK_KEY1'
BLOCK_KEY1 - XTS_AES_128_KEY
Secure Boot: Disabled
Flash Encryption: Disabled
SPI Boot Crypt Count (SPI_BOOT_CRYPT_CNT): 0x0
Gravando o primeiro firmware na placa
Vamos juntar os arquivos em um único binário:
### FIDO:
cd ~/src/picokeys-fe/pico-fido && mkdir -p release && cd build
esptool.py --chip ESP32-S3 merge_bin \
-o ../release/pico_fido_esp32-s3.bin \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 bootloader/bootloader.bin \
0x10000 partition_table/partition-table.bin \
0x20000 pico_fido.bin && cd ..
### HSM:
cd ~/src/picokeys-fe/pico-hsm && mkdir -p release && cd build
esptool.py --chip ESP32-S3 merge_bin \
-o ../release/pico_hsm_esp32-s3.bin \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 bootloader/bootloader.bin \
0x10000 partition_table/partition-table.bin \
0x20000 pico_hsm.bin && cd ..
No layout acima, os endereços usados são:
| Arquivo | Endereço |
|---|---|
| Bootloader | 0x0 |
| Tabela de partições | 0x10000 |
Aplicação/Firmware (factory) | 0x20000 |
Dados (part0), se houver conteúdo | 0x200000 |
Agora vamos gravar na placa:
# FIDO:
esptool.py --chip ESP32-S3 -p "/dev/ttyACM0" write_flash \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 release/pico_fido_esp32-s3.bin
# HSM:
esptool.py --chip ESP32-S3 -p "/dev/ttyACM0" write_flash \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 release/pico_hsm_esp32-s3.bin
O write_flash é usado com os binários assinados, mas quando a placa ainda não possui Flash Eencryption ativa. Como nós configuramos Flash Encryption on boot e já colocamos a chave no eFuse, é o bootloader quem vai fazer a criptografia na primeira inicialização do firmware na placa.
Nas próximas gravações, depois que a Flash Encryption estiver ativa, vamos usar o encrypt_flash_data para criptografar o novo firmware no computador com a chave Flash Encryption da placa. Depois, vamos gravar o arquivo criptografado com o write_flash, usando o mesmo endereço definido na criptografia.
Desconecte e reconecte a placa e entre em modo de download, depois execute o comando abaixo:
$ esptool.py --chip ESP32-S3 --port /dev/ttyACM0 --no-stub get_security_info
esptool.py v4.12.0
Serial port /dev/ttyACM0
Connecting...
Chip is ESP32-S3 in Secure Download Mode
Enabling default SPI flash mode...
Security Information:
=====================
Flags: 0x000006f5 (0b11011110101)
Key Purposes: (9, 4, 0, 0, 0, 0, 12)
BLOCK_KEY0 - SECURE_BOOT_DIGEST0
BLOCK_KEY1 - XTS_AES_128_KEY
BLOCK_KEY2 - USER/EMPTY
BLOCK_KEY3 - USER/EMPTY
BLOCK_KEY4 - USER/EMPTY
BLOCK_KEY5 - USER/EMPTY
Chip ID: 9
API Version: 0
Secure Boot: Enabled
Secure Boot Key Revocation Status:
Secure Boot Key1 is Revoked
Secure Boot Key2 is Revoked
Flash Encryption: Enabled
SPI Boot Crypt Count (SPI_BOOT_CRYPT_CNT): 0x7
Dcache in UART download mode: Disabled
Icache in UART download mode: Disabled
JTAG: Permanently Disabled
Hard resetting via RTS pin...
A linha BLOCK_KEY0 - SECURE_BOOT_DIGEST0 mostra que o digest da chave pública do Secure Boot foi gravado no BLOCK_KEY0. As mensagens Secure Boot Key1 is Revoked e Secure Boot Key2 is Revoked mostram que os slots 1 e 2 foram revogados. Assim, o slot 0 continua autorizado para validar as assinaturas.
Também podemos observar que o Flash Encryption está ativo. O valor SPI_BOOT_CRYPT_CNT: 0x7 confirma que a Flash Encryption foi ativada, e BLOCK_KEY1 - XTS_AES_128_KEY mostra que a chave FE está no bloco esperado. A placa também está em Secure Download Mode. Nesse modo, o download fica restrito aos comandos básicos de gravação. As caches de dados e instruções estão desativadas durante o download, e o JTAG foi permanentemente desabilitado.
Gravando novos firmwares criptografados - segunda gravação ou posteriores
Este procedimento é para a segunda gravação ou posteriores, depois que o primeiro firmware já ativou a Flash Encryption. Depois de compilar o firmware, vamos juntar os binários em um úncio arquivo:
### FIDO:
cd ~/src/picokeys-fe/pico-fido && mkdir -p release && cd build
esptool.py --chip ESP32-S3 merge_bin \
-o ../release/pico_fido_esp32-s3.bin \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 bootloader/bootloader.bin \
0x10000 partition_table/partition-table.bin \
0x20000 pico_fido.bin && cd ..
### HSM:
cd ~/src/picokeys-fe/pico-hsm && mkdir -p release && cd build
esptool.py --chip ESP32-S3 merge_bin \
-o ../release/pico_hsm_esp32-s3.bin \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 bootloader/bootloader.bin \
0x10000 partition_table/partition-table.bin \
0x20000 pico_hsm.bin && cd ..
Agora vamos criptografar o firmware:
# FIDO:
espsecure.py encrypt_flash_data --aes_xts \
--keyfile "/home/bruno/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin" \
--address 0x0 \
--output release/pico_fido_esp32-s3.enc.bin \
release/pico_fido_esp32-s3.bin
# HSM:
espsecure.py encrypt_flash_data --aes_xts \
--keyfile "/home/bruno/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin" \
--address 0x0 \
--output release/pico_hsm_esp32-s3.enc.bin \
release/pico_hsm_esp32-s3.bin
Antes de gravar, vamos fazer um teste para validar que a criptografia deu certo:
espsecure.py decrypt_flash_data --aes_xts \
--keyfile "/home/bruno/.config/picokeys/flash-encryption/pico-68ee8f51e038.bin" \
--address 0x0 \
--output /tmp/pico_hsm.dec.bin \
release/pico_hsm_esp32-s3.enc.bin
# Compare a diferença entre o firmware original (criptografado) e o firmware recem descriptografado (se nao retornar nada, está tudo certo):
cmp release/pico_hsm_esp32-s3.bin /tmp/pico_hsm.dec.bin
Para gravar precisamos usar o parâmetro --force, se não usar, isso acontece:
$ esptool.py --chip ESP32-S3 -p "/dev/ttyACM0" --no-stub write_flash \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 release/pico_hsm_esp32-s3.enc.bin
esptool.py v4.12.0
Serial port /dev/ttyACM0
Connecting...
Chip is ESP32-S3 in Secure Download Mode
Enabling default SPI flash mode...
Configuring flash size...
WARNING: In case of failure, please set a specific --flash_size.
A fatal error occurred: WARNING: Detected flash encryption and secure download mode enabled.
Flashing plaintext binary may brick your device! Use --force to override the warning.
Esse aviso é esperado do esptool, já que ele encontrou uma placa com Flash Encryption e Secure Download Mode habilitados. Quando ele encontra esses recursos ativos, não tem como ele verificar se o arquivo foi criptografado e se foi da forma correta, por isso precisamos usar o --force.
Como nós validamos a criptografia, podemos seguir:
# FIDO:
esptool.py --chip ESP32-S3 -p "/dev/ttyACM0" --no-stub write_flash --force \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 release/pico_fido_esp32-s3.enc.bin
# HSM:
esptool.py --chip ESP32-S3 -p "/dev/ttyACM0" --no-stub write_flash --force \
--flash_mode dio --flash_freq 80m --flash_size keep \
0x0 release/pico_hsm_esp32-s3.enc.bin
Fontes
https://docs.espressif.com/projects/esp-idf/en/v5.5/esp32s3/security/flash-encryption.html
https://docs.espressif.com/projects/esp-idf/en/v5.5/esp32s3/security/secure-boot-v2.html