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 76 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
96e5ccc
Use 4-way key shares for AES private keys
will-v-pi Jan 14, 2025
7484990
Remove check that ELF segments are between metadata blocks
will-v-pi Jan 15, 2025
2bf08af
Fix overlapping memory ranges issue for encrypted binaries
will-v-pi Jan 15, 2025
c1a83cf
Update share as word-wise
will-v-pi Jan 20, 2025
25b690b
Add enc_bootloader binary
will-v-pi Jan 20, 2025
083c9f2
Apply encrypted-example 6de8084b6eda
will-v-pi Jan 20, 2025
425367b
Fixup no libusb build
will-v-pi Jan 20, 2025
d2b21f0
Remove debug prints, and add USE_USB_DPRAM option
will-v-pi Jan 20, 2025
488707b
Reduce binary size
will-v-pi Jan 20, 2025
d49d559
Remove pico_rand and use boot random instead
will-v-pi Jan 21, 2025
1e89ba6
Update precompiled enc_bootloader.elf
will-v-pi Jan 21, 2025
c927b64
Remove unused use_usb_dpram
will-v-pi Jan 21, 2025
47ed4c9
Re-jig to create more space for the AES code
will-v-pi Jan 21, 2025
9fbb8d3
Integrate new aes.S
will-v-pi Jan 22, 2025
5c6bde6
Use minimal vector table
will-v-pi Jan 22, 2025
90ef224
Pass TBYB and version from encrypted binary metadata to the decryptio…
will-v-pi Jan 22, 2025
8d69fd7
Add --otp-key-page argument
will-v-pi Jan 23, 2025
3976072
Update aes.S
will-v-pi Jan 23, 2025
c8cc3d2
Shrink enc_bootloader.c code further
will-v-pi Jan 29, 2025
1c0393e
Add otp file to enc
will-v-pi Jan 29, 2025
84fa35c
Increase stack size by 0x80 to provide some headroom
will-v-pi Jan 29, 2025
904a6ec
Integrate latest aes.S code
will-v-pi Feb 4, 2025
4fbc259
Use ROSC randomisation instead of CK_JITTER
will-v-pi Feb 7, 2025
c98f8a7
Fix SDK branch for enc_bootloader
will-v-pi Feb 7, 2025
fb691e6
Add comments and slight size reduction
will-v-pi Feb 7, 2025
a10b220
Uncomment chaff assertion
will-v-pi Feb 10, 2025
06c936a
Shrink IV storage size
will-v-pi Feb 10, 2025
aed42f8
Update enc_bootloader.elf with latest
will-v-pi Feb 10, 2025
f89116e
Rejig clock init to prevent overclocking
will-v-pi Feb 10, 2025
5dfcbdb
Update with latest aes.S
will-v-pi Feb 12, 2025
f229303
Seed ROSC random using rstate_lfsr
will-v-pi Feb 12, 2025
e5f4284
Use CK_JITTER to enable/disable ROSC randomisation
will-v-pi Feb 12, 2025
24d39a3
Add IV XOR code, but turn it off with IV0_XOR for now
will-v-pi Feb 19, 2025
b610fe3
Disable calibration using XOSC by default
will-v-pi Feb 20, 2025
93faf40
Update with latest aes.S
will-v-pi Feb 20, 2025
5fed019
Add fast-rosc option
will-v-pi Feb 20, 2025
a3adc0f
clock_configure_mhz no longer used
will-v-pi Feb 24, 2025
bbd73c9
Tidy up indents in CMakeLists.txt
will-v-pi Feb 24, 2025
a89abf9
Remove CK_JITTER from aes.S, as this is now handled in the C code
will-v-pi Feb 24, 2025
e718a3e
Throw error when using AES key share file of incorrect size
will-v-pi Feb 24, 2025
4e74b73
Incorporate latest aes.S code, and add IV salt
will-v-pi Feb 26, 2025
50e58f0
Update enc_bootloader.elf with latest
will-v-pi Feb 26, 2025
d725474
Remove pico-sdk branch handling
will-v-pi Feb 26, 2025
8d8a162
Update aes.S
will-v-pi Feb 26, 2025
b3d0a61
Add USE_MBEDTLS variant
will-v-pi Feb 26, 2025
df715e9
Update with latest aes.S
will-v-pi Mar 4, 2025
6502813
Better fix for #210
will-v-pi Mar 4, 2025
5b3f059
Add --use-mbedtls option to use mbedtls version of the decryption stage
will-v-pi Mar 4, 2025
dfb90d9
Add enc_bootloader_mbedtls to bazel build
will-v-pi Mar 4, 2025
f964090
Fix build without mbedtls
will-v-pi Mar 4, 2025
5e1c4c2
Review fixups
will-v-pi Mar 13, 2025
768d7e7
Reword readme, to reflect word-wise aes file
will-v-pi Mar 13, 2025
f69808b
Add IV salt to regular encrypted binaries too
will-v-pi Mar 20, 2025
964da15
Rename xip_ram_perms.cpp and enc_bootloader.cpp to get_....cpp
will-v-pi Mar 20, 2025
519e998
Use include_directories for lib/include
will-v-pi Mar 20, 2025
f8e4869
Use newer VTABLE related variables
kilograham Mar 22, 2025
e67e62e
Copy last block when signing/encrypting, if it has an image_def
will-v-pi Mar 24, 2025
be23237
Review fixups
will-v-pi Mar 24, 2025
3d449fd
Review fixups
will-v-pi Mar 25, 2025
42b3681
don't include RAM vector table
kilograham Mar 25, 2025
4991e1e
Mention file size in bits & bytes
will-v-pi Mar 31, 2025
3d5450c
Remove OTP key workaround
will-v-pi Mar 31, 2025
12d786a
Remove load_map, hash and signature from chosen ELF blocks
will-v-pi Mar 31, 2025
520e6d6
Clear SRAM in load_map of self-decrypting binary
will-v-pi Mar 31, 2025
8ae85ba
Add ability to generate key share from 256 bit key
will-v-pi Mar 31, 2025
2340549
Remove -t argument when not needed
will-v-pi Mar 31, 2025
d657fb3
Support passing AES key and IV salt as hex strings instead of files
will-v-pi Mar 31, 2025
09e79b0
Improve encrypt docs
will-v-pi Apr 1, 2025
8d5f829
Review fixups
will-v-pi Apr 1, 2025
739ca83
Improve external project inclusion
will-v-pi Apr 2, 2025
c569905
Use named_untyped_file_selection for coprodis as well
will-v-pi Apr 3, 2025
dedba68
Implement FIB workaround by storing inverse of row n in row n+32 of e…
will-v-pi Apr 3, 2025
126752f
Only delete existing load_maps when encrypting
will-v-pi Apr 7, 2025
9283925
Tidy up string_to_hex_array function
will-v-pi Apr 15, 2025
2af35ab
Add permission handling to OTP dump
will-v-pi Apr 7, 2025
f0226e9
Modify bootloader to work with FIB workaround
will-v-pi Apr 16, 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
42 changes: 28 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,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 sign`.
`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 sign`. 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 @@ -678,22 +678,46 @@ 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.

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].

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)
Comment on lines +719 to +720
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that the -t options have been removed, perhaps this help-text ought to mention what file-format some of these parameters are expected to be in?

Signing Configuration
--hash
Hash the encrypted file
Expand All @@ -714,16 +738,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