Skip to content

Add support for creating self-decrypting binaries, and use 4-way AES key shares instead of just the AES key #207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 78 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
bc12015
Use 4-way key shares for AES private keys
will-v-pi Jan 14, 2025
78f27fb
Remove check that ELF segments are between metadata blocks
will-v-pi Jan 15, 2025
d1088ff
Fix overlapping memory ranges issue for encrypted binaries
will-v-pi Jan 15, 2025
a65daa7
Update share as word-wise
will-v-pi Jan 20, 2025
4eac457
Add enc_bootloader binary
will-v-pi Jan 20, 2025
76baca1
Apply encrypted-example 6de8084b6eda
will-v-pi Jan 20, 2025
cc6fbab
Fixup no libusb build
will-v-pi Jan 20, 2025
0d81600
Remove debug prints, and add USE_USB_DPRAM option
will-v-pi Jan 20, 2025
d0dd100
Reduce binary size
will-v-pi Jan 20, 2025
5596923
Remove pico_rand and use boot random instead
will-v-pi Jan 21, 2025
0dc6c62
Update precompiled enc_bootloader.elf
will-v-pi Jan 21, 2025
83de3e3
Remove unused use_usb_dpram
will-v-pi Jan 21, 2025
a605be7
Re-jig to create more space for the AES code
will-v-pi Jan 21, 2025
cff9a9e
Integrate new aes.S
will-v-pi Jan 22, 2025
d04d513
Use minimal vector table
will-v-pi Jan 22, 2025
d2c8419
Pass TBYB and version from encrypted binary metadata to the decryptio…
will-v-pi Jan 22, 2025
af31a00
Add --otp-key-page argument
will-v-pi Jan 23, 2025
6e62875
Update aes.S
will-v-pi Jan 23, 2025
4ef6450
Shrink enc_bootloader.c code further
will-v-pi Jan 29, 2025
e17112d
Add otp file to enc
will-v-pi Jan 29, 2025
82d6116
Increase stack size by 0x80 to provide some headroom
will-v-pi Jan 29, 2025
9cf530f
Integrate latest aes.S code
will-v-pi Feb 4, 2025
1640e86
Use ROSC randomisation instead of CK_JITTER
will-v-pi Feb 7, 2025
b1b0015
Fix SDK branch for enc_bootloader
will-v-pi Feb 7, 2025
3251f22
Add comments and slight size reduction
will-v-pi Feb 7, 2025
4819b55
Uncomment chaff assertion
will-v-pi Feb 10, 2025
922c3e3
Shrink IV storage size
will-v-pi Feb 10, 2025
4eab13e
Update enc_bootloader.elf with latest
will-v-pi Feb 10, 2025
e86b6c5
Rejig clock init to prevent overclocking
will-v-pi Feb 10, 2025
7d8db46
Update with latest aes.S
will-v-pi Feb 12, 2025
2766a7d
Seed ROSC random using rstate_lfsr
will-v-pi Feb 12, 2025
9f01c2c
Use CK_JITTER to enable/disable ROSC randomisation
will-v-pi Feb 12, 2025
baf011f
Add IV XOR code, but turn it off with IV0_XOR for now
will-v-pi Feb 19, 2025
aa6a0ba
Disable calibration using XOSC by default
will-v-pi Feb 20, 2025
8781004
Update with latest aes.S
will-v-pi Feb 20, 2025
d7aa177
Add fast-rosc option
will-v-pi Feb 20, 2025
c8b03fd
clock_configure_mhz no longer used
will-v-pi Feb 24, 2025
854e147
Tidy up indents in CMakeLists.txt
will-v-pi Feb 24, 2025
8af552d
Remove CK_JITTER from aes.S, as this is now handled in the C code
will-v-pi Feb 24, 2025
e20a3a5
Throw error when using AES key share file of incorrect size
will-v-pi Feb 24, 2025
bd403b4
Incorporate latest aes.S code, and add IV salt
will-v-pi Feb 26, 2025
aef73b1
Update enc_bootloader.elf with latest
will-v-pi Feb 26, 2025
abb4e63
Remove pico-sdk branch handling
will-v-pi Feb 26, 2025
e96ff1c
Update aes.S
will-v-pi Feb 26, 2025
c29bad5
Add USE_MBEDTLS variant
will-v-pi Feb 26, 2025
7080fdf
Update with latest aes.S
will-v-pi Mar 4, 2025
8e9eaba
Better fix for #210
will-v-pi Mar 4, 2025
eef5d24
Add --use-mbedtls option to use mbedtls version of the decryption stage
will-v-pi Mar 4, 2025
15f059c
Add enc_bootloader_mbedtls to bazel build
will-v-pi Mar 4, 2025
8c4a66c
Fix build without mbedtls
will-v-pi Mar 4, 2025
bbbd032
Review fixups
will-v-pi Mar 13, 2025
fce50e1
Reword readme, to reflect word-wise aes file
will-v-pi Mar 13, 2025
cd21a1e
Add IV salt to regular encrypted binaries too
will-v-pi Mar 20, 2025
fd7e89b
Rename xip_ram_perms.cpp and enc_bootloader.cpp to get_....cpp
will-v-pi Mar 20, 2025
d26ccd0
Use include_directories for lib/include
will-v-pi Mar 20, 2025
5030525
Use newer VTABLE related variables
kilograham Mar 22, 2025
d838946
Copy last block when signing/encrypting, if it has an image_def
will-v-pi Mar 24, 2025
e0db243
Review fixups
will-v-pi Mar 24, 2025
3fdc556
Review fixups
will-v-pi Mar 25, 2025
64fe3d4
don't include RAM vector table
kilograham Mar 25, 2025
091cf6f
Mention file size in bits & bytes
will-v-pi Mar 31, 2025
04d8819
Remove OTP key workaround
will-v-pi Mar 31, 2025
90ddbc4
Remove load_map, hash and signature from chosen ELF blocks
will-v-pi Mar 31, 2025
e370a20
Clear SRAM in load_map of self-decrypting binary
will-v-pi Mar 31, 2025
33419cf
Add ability to generate key share from 256 bit key
will-v-pi Mar 31, 2025
b35d9a9
Remove -t argument when not needed
will-v-pi Mar 31, 2025
4adbf75
Support passing AES key and IV salt as hex strings instead of files
will-v-pi Mar 31, 2025
cbfab7c
Improve encrypt docs
will-v-pi Apr 1, 2025
eb5c981
Review fixups
will-v-pi Apr 1, 2025
ba3bf03
Improve external project inclusion
will-v-pi Apr 2, 2025
954120f
Use named_untyped_file_selection for coprodis as well
will-v-pi Apr 3, 2025
1ff20e0
Implement FIB workaround by storing inverse of row n in row n+32 of e…
will-v-pi Apr 3, 2025
d6c5171
Only delete existing load_maps when encrypting
will-v-pi Apr 7, 2025
61bf7c3
Tidy up string_to_hex_array function
will-v-pi Apr 15, 2025
f018f89
Add permission handling to OTP dump
will-v-pi Apr 7, 2025
6743582
Modify bootloader to work with FIB workaround
will-v-pi Apr 16, 2025
f9bf5e7
Review fixups
will-v-pi Apr 24, 2025
861a153
Mention mbedtls is "faster but less secure" in help text
will-v-pi Apr 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ picotool_binary_data_header(
out = "xip_ram_perms_elf.h",
)

# TODO: Make it possible to build the prebuilt from source.
picotool_binary_data_header(
name = "enc_bootloader_elf",
src = "//enc_bootloader:enc_bootloader_prebuilt",
out = "enc_bootloader_elf.h",
)

# TODO: Make it possible to build the prebuilt from source.
picotool_binary_data_header(
name = "enc_bootloader_mbedtls_elf",
src = "//enc_bootloader:enc_bootloader_mbedtls_prebuilt",
out = "enc_bootloader_mbedtls_elf.h",
)

# TODO: Make it possible to build the prebuilt from source.
picotool_binary_data_header(
name = "flash_id_bin",
Expand All @@ -26,9 +40,9 @@ picotool_binary_data_header(

cc_library(
name = "xip_ram_perms",
srcs = ["xip_ram_perms.cpp"],
srcs = ["get_xip_ram_perms.cpp"],
hdrs = [
"xip_ram_perms.h",
"get_xip_ram_perms.h",
"xip_ram_perms_elf.h",
],
deps = [
Expand All @@ -37,6 +51,20 @@ cc_library(
],
)

cc_library(
name = "enc_bootloader",
srcs = ["get_enc_bootloader.cpp"],
hdrs = [
"get_enc_bootloader.h",
"enc_bootloader_elf.h",
"enc_bootloader_mbedtls_elf.h",
],
deps = [
"//bazel:data_locs",
"//lib/whereami",
],
)

filegroup(
name = "data_locs_header",
srcs = ["data_locs.h"],
Expand All @@ -61,7 +89,8 @@ cc_binary(
"otp.cpp",
"otp.h",
"rp2350.rom.h",
"xip_ram_perms.cpp",
"get_xip_ram_perms.cpp",
"get_enc_bootloader.cpp",
] + select({
# MSVC can't handle long strings, so use this manually generated
# header instead.
Expand Down Expand Up @@ -97,6 +126,7 @@ cc_binary(
}),
deps = [
":xip_ram_perms",
":enc_bootloader",
"//bazel:data_locs",
"//bintool",
"//elf",
Expand Down
120 changes: 90 additions & 30 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ endif()

# todo better install paths for this
set(DATA_LOCS "./" "${CMAKE_INSTALL_PREFIX}/${INSTALL_DATADIR}/")
message(${DATA_LOCS})
string(REGEX REPLACE ";" "\",\"" DATA_LOCS_VEC "${DATA_LOCS}")
configure_file(data_locs.template.cpp ${CMAKE_CURRENT_BINARY_DIR}/data_locs.cpp)

Expand All @@ -57,11 +56,53 @@ endif()

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)

# To configure mbedtls, without modifying mbedtls CMake files
set(MBEDTLS_CONFIG_FILE "mbedtls_config.h")
include_directories(${CMAKE_SOURCE_DIR}/lib/include)

add_subdirectory(lib)

if (NOT DEFINED USE_PRECOMPILED)
set(USE_PRECOMPILED true)
endif()

# compile enc_bootloader.elf
ExternalProject_Add(enc_bootloader
PREFIX enc_bootloader
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/enc_bootloader
BINARY_DIR ${CMAKE_BINARY_DIR}/enc_bootloader
CMAKE_ARGS
"-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}"
"-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}"
"-DUSE_PRECOMPILED:BOOL=${USE_PRECOMPILED}"
"-DUSE_MBEDTLS=0"
"-DPICO_DEBUG_INFO_IN_RELEASE=OFF"
BUILD_ALWAYS 1 # todo remove this
INSTALL_COMMAND ""
)

set(ENC_BOOTLOADER_ELF ${CMAKE_BINARY_DIR}/enc_bootloader/enc_bootloader.elf)

if (TARGET mbedtls)
ExternalProject_Add(enc_bootloader_mbedtls
PREFIX enc_bootloader_mbedtls
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/enc_bootloader
BINARY_DIR ${CMAKE_BINARY_DIR}/enc_bootloader_mbedtls
CMAKE_ARGS
"-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}"
"-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}"
"-DUSE_PRECOMPILED:BOOL=${USE_PRECOMPILED}"
"-DUSE_MBEDTLS=1"
"-DPICO_DEBUG_INFO_IN_RELEASE=OFF"
BUILD_ALWAYS 1 # todo remove this
INSTALL_COMMAND ""
)

set(ENC_BOOTLOADER_MBEDTLS_ELF ${CMAKE_BINARY_DIR}/enc_bootloader_mbedtls/enc_bootloader.elf)
endif()

if (NOT PICOTOOL_NO_LIBUSB)
# compile xip_ram_perms.elf
if (NOT DEFINED USE_PRECOMPILED)
set(USE_PRECOMPILED true)
endif()
ExternalProject_Add(xip_ram_perms
PREFIX xip_ram_perms
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/xip_ram_perms
Expand All @@ -76,14 +117,6 @@ if (NOT PICOTOOL_NO_LIBUSB)
)

set(XIP_RAM_PERMS_ELF ${CMAKE_BINARY_DIR}/xip_ram_perms/xip_ram_perms.elf)
add_executable(xip_ram_perms_elf IMPORTED)
add_dependencies(xip_ram_perms_elf xip_ram_perms)
set_property(TARGET xip_ram_perms_elf PROPERTY IMPORTED_LOCATION ${XIP_RAM_PERMS_ELF})
# copy xip_ram_perms.elf into build directory
add_custom_command(TARGET xip_ram_perms
COMMAND ${CMAKE_COMMAND} -E copy ${XIP_RAM_PERMS_ELF} ${CMAKE_BINARY_DIR}/xip_ram_perms.elf
DEPENDS xip_ram_perms
)

# compile flash_id
ExternalProject_Add(flash_id
Expand All @@ -100,14 +133,6 @@ if (NOT PICOTOOL_NO_LIBUSB)
)

set(FLASH_ID_BIN ${CMAKE_BINARY_DIR}/picoboot_flash_id/flash_id.bin)
add_executable(flash_id_bin IMPORTED)
add_dependencies(flash_id_bin flash_id)
set_property(TARGET flash_id_bin PROPERTY IMPORTED_LOCATION ${FLASH_ID_BIN})
# copy flash_id.bin into build directory
add_custom_command(TARGET flash_id
COMMAND ${CMAKE_COMMAND} -E copy ${FLASH_ID_BIN} ${CMAKE_BINARY_DIR}/flash_id.bin
DEPENDS flash_id
)

# We want to generate headers from WELCOME.HTM etc.
ExternalProject_Add(otp_header_parser
Expand Down Expand Up @@ -169,7 +194,16 @@ if (NOT PICOTOOL_NO_LIBUSB)
endif()
endif()

add_custom_target(binary_data DEPENDS
if (TARGET mbedtls)
add_custom_target(embedded_data_no_libusb DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/enc_bootloader_elf.h
${CMAKE_CURRENT_BINARY_DIR}/enc_bootloader_mbedtls_elf.h)
else()
add_custom_target(embedded_data_no_libusb DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/enc_bootloader_elf.h)
endif()

add_custom_target(embedded_data DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h
${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h
${CMAKE_CURRENT_BINARY_DIR}/flash_id_bin.h)
Expand All @@ -188,6 +222,22 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h
DEPENDS xip_ram_perms
COMMENT "Configuring xip_ram_perms_elf.h"
VERBATIM)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/enc_bootloader_elf.h
COMMAND ${CMAKE_COMMAND}
-D BINARY_FILE=${ENC_BOOTLOADER_ELF}
-D OUTPUT_NAME=enc_bootloader_elf
-P ${CMAKE_CURRENT_LIST_DIR}/cmake/binh.cmake
DEPENDS enc_bootloader
COMMENT "Configuring enc_bootloader_elf.h"
VERBATIM)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/enc_bootloader_mbedtls_elf.h
COMMAND ${CMAKE_COMMAND}
-D BINARY_FILE=${ENC_BOOTLOADER_MBEDTLS_ELF}
-D OUTPUT_NAME=enc_bootloader_mbedtls_elf
-P ${CMAKE_CURRENT_LIST_DIR}/cmake/binh.cmake
DEPENDS enc_bootloader_mbedtls
COMMENT "Configuring enc_bootloader_mbedtls_elf.h"
VERBATIM)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_id_bin.h
COMMAND ${CMAKE_COMMAND}
-D BINARY_FILE=${FLASH_ID_BIN}
Expand All @@ -203,13 +253,6 @@ add_subdirectory(picoboot_connection)
add_subdirectory(elf)
add_subdirectory(elf2uf2)

# To configure mbedtls
# todo make the configuration better
set(MBEDTLS_CONFIG_FILE "mbedtls_config.h")
add_compile_options(-I${CMAKE_SOURCE_DIR}/lib/include)

add_subdirectory(lib)

add_subdirectory(bintool)

if (NOT PICOTOOL_NO_LIBUSB)
Expand All @@ -233,11 +276,13 @@ target_include_directories(regs_headers INTERFACE ${PICO_SDK_PATH}/src/rp2350/ha
# Main picotool executable
add_executable(picotool
data_locs.cpp
get_enc_bootloader.cpp
${OTP_EXE}
main.cpp)
add_dependencies(picotool embedded_data_no_libusb)
if (NOT PICOTOOL_NO_LIBUSB)
target_sources(picotool PRIVATE xip_ram_perms.cpp)
add_dependencies(picotool generate_otp_header xip_ram_perms_elf binary_data)
target_sources(picotool PRIVATE get_xip_ram_perms.cpp)
add_dependencies(picotool generate_otp_header embedded_data)
endif()
set(PROJECT_VERSION 2.1.2-develop)
set(PICOTOOL_VERSION 2.1.2-develop)
Expand Down Expand Up @@ -328,6 +373,21 @@ install(FILES
DESTINATION ${INSTALL_CONFIGDIR}
)

#Install enc_bootloader.elf
install(FILES
${ENC_BOOTLOADER_ELF}
DESTINATION ${INSTALL_DATADIR}
)

if (TARGET mbedtls)
#Install enc_bootloader_mbedtls.elf
install(FILES
${ENC_BOOTLOADER_MBEDTLS_ELF}
DESTINATION ${INSTALL_DATADIR}
RENAME enc_bootloader_mbedtls.elf
)
endif()

if (NOT PICOTOOL_NO_LIBUSB)
if (NOT PICOTOOL_CODE_OTP)
#Install the otp json
Expand Down
44 changes: 30 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ OPTIONS:

## encrypt

`encrypt` allows you to encrypt and sign a binary for use on the RP2350. By default, it will sign the encrypted binary, but that can be configured similarly to `picotool seal`.
`encrypt` allows you to encrypt and sign a binary for use on the RP2350. By default, it will sign the encrypted binary, but that can be configured similarly to `picotool seal`. You can either provide your own bootloader to decrypt the binary (see pico-examples/bootloaders/encrypted), or embed a decrypting bootloader into the binary with the `--embed` argument, to create a self-decrypting binary.

The encrypted binary will have the following structure:

Expand All @@ -586,22 +586,48 @@ The encrypted binary will have the following structure:
- Padding to ensure the encrypted length is a multiple of 4 words
- Signature metadata block

The AES key must be provided as a .bin file of the 256 bit AES key to be used for encryption.
The AES key can either be provided as a 1024-bit (128 byte) 4-way key share or as a 256-bit (32 byte) AES key. In the latter case, a key share will be generated for you, as the decryption code needs a 4-way key share in OTP rather than a plain key.

The 4-way key share should be generated by creating a random .bin file of length 128 bytes and the AES key will be derived from that. With the words stored in the file as A[0], B[0], C[0], D[0], A[1], B[1], etc., C[7], D[7], word i of the key X is X[i] = A[i] ^ B[i] ^ C[i] ^ D[i].

Alternatively an AES key can be provided directly, as either a 32 byte .bin file or as a string of 64 hexadecimal characters (eg 0x0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210). Picotool will generate a random key share for that key, by generating 3 random shares (A, B & C) and calculating a 4th share (D) to match the provided key (X), with each word i of the 4th share calculated as D[i] = X[i] ^ A[i] ^ B[i] ^ C[i].

When using a .bin file, picotool will use the file size to determine if a 128 byte key share or a 32 byte key has been provided - any other file size will throw an error.

The encryption/decryption code also salts the IV (initialisation vector) so it's not stored in plaintext in the binary. This requires a per-device IV salt in OTP, which should be a 128-bit (16 byte) random value - this can be provided as either a 16 byte .bin file, or a string of 32 hexadecimal characters, similar to the AES key. This per-device salt will be XORed with the IV stored in the binary, to give the IV used by the decryption code.

```text
$ picotool help encrypt
ENCRYPT:
Encrypt the program.

SYNOPSIS:
picotool encrypt [--quiet] [--verbose] [--hash] [--sign] <infile> [-t <type>] [-o <offset>] <outfile> [-t <type>] <aes_key> [-t <type>]
[<signing_key>] [-t <type>]
picotool encrypt [--quiet] [--verbose] [--embed] [--fast-rosc] [--use-mbedtls] [--otp-key-page <page>] [--hash] [--sign] <infile>
[-t <type>] [-o <offset>] <outfile> [-t <type>] <aes_key> <iv_otp> <signing_key> <otp>

OPTIONS:
--quiet
Don't print any output
--verbose
Print verbose output
--embed
Embed bootloader in output file
--fast-rosc
Use ~180MHz ROSC configuration for embedded bootloader
--use-mbedtls
Use MbedTLS implementation of embedded bootloader
--otp-key-page
Specify the OTP page storing the AES key (IV salt is stored on the next page)
<page>
OTP page (default 30)
<aes_key>
AES Key Share or AES Key
<iv_otp>
IV OTP Salt
<signing_key>
Signing Key file
<otp>
File to save OTP to (will edit existing file if it exists)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that in main.cpp this has been updated to "JSON file to save OTP to (will edit existing file if it exists)", so I guess you might want to use #220 here? 😀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I think I'll merge #220 into develop, then merge develop into here again and run it

Signing Configuration
--hash
Hash the encrypted file
Expand All @@ -622,16 +648,6 @@ OPTIONS:
The file name
-t <type>
Specify file type (uf2 | elf | bin) explicitly, ignoring file extension
AES Key
<aes_key>
The file name
-t <type>
Specify file type (bin) explicitly, ignoring file extension
Signing Key file
<signing_key>
The file name
-t <type>
Specify file type (pem) explicitly, ignoring file extension
```

## partition
Expand Down
Loading
Loading