From c4a5de48086a44b341b77caf59992712c1c466b0 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 22 Jan 2025 17:51:47 +0000 Subject: [PATCH 1/8] Add pico_create_decrypting_binary function For now, this function embeds the decrypting bootloader, but probably better to integrate (or replace) existing pico_encrypt_binary function --- tools/CMakeLists.txt | 52 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5273840a5..2cb0a93e7 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -41,6 +41,12 @@ define_property(TARGET BRIEF_DOCS "AES key for encrypting" FULL_DOCS "AES key for encrypting" ) +define_property(TARGET + PROPERTY PICOTOOL_EMBED_DECRYPTION + INHERITED + BRIEF_DOCS "Embed decryption stage into encrypted binary" + FULL_DOCS "Embed decryption stage into encrypted binary" +) define_property(TARGET PROPERTY PICOTOOL_ENC_SIGFILE INHERITED @@ -424,7 +430,7 @@ endfunction() # \brief_nodesc\ Encrypt the taget binary # # Encrypt the target binary with the given AES key (should be a binary -# file containing 32 bytes of a random key), and sign the encrypted binary. +# file containing 128 bytes of a random key), and sign the encrypted binary. # # This sets the target properties PICOTOOL_AESFILE to AESFILE, # and PICOTOOL_ENC_SIGFILE to SIGFILE if present, else PICOTOOL_SIGFILE. @@ -455,6 +461,37 @@ function(pico_encrypt_binary TARGET AESFILE) endif() endfunction() +# pico_create_decrypting_binary(TARGET AESFILE [SIGFILE]) +# Encrypt the target binary with the given AES key (should be a binary +# file containing 128 bytes of a random key), add a decryption stage to +# decrypt the binary at runtime, and then sign the encrypted binary. +# This sets PICOTOOL_AESFILE to AESFILE, PICOTOOL_EMBED_DECRYPTION to TRUE, +# and PICOTOOL_ENC_SIGFILE to SIGFILE if present, else PICOTOOL_SIGFILE. +function(pico_create_decrypting_binary TARGET AESFILE) + picotool_check_configurable(${TARGET}) + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_AESFILE ${AESFILE} + PICOTOOL_EMBED_DECRYPTION TRUE + ) + if (ARGC EQUAL 3) + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_ENC_SIGFILE ${ARGV2} + ) + else() + get_target_property(enc_sig_file ${TARGET} PICOTOOL_ENC_SIGFILE) + if (NOT enc_sig_file) + get_target_property(sig_file ${TARGET} PICOTOOL_SIGFILE) + if (NOT sig_file) + message(FATAL_ERROR "Signature file not set for ${TARGET}") + else() + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_ENC_SIGFILE ${sig_file} + ) + endif() + endif() + endif() +endfunction() + # pico_add_uf2_output(TARGET) # \brief_nodesc\ Add a UF2 output using picotool # @@ -595,9 +632,20 @@ function(picotool_postprocess_binary TARGET) endif() # Encryption if (picotool_aesfile) + get_target_property(picotool_embed_decryption ${TARGET} PICOTOOL_EMBED_DECRYPTION) + if (picotool_embed_decryption) + list(APPEND picotool_encrypt_args "--embed") + endif() + add_custom_command(TARGET ${TARGET} POST_BUILD DEPENDS ${picotool_enc_sigfile} ${picotool_aesfile} - COMMAND picotool encrypt --quiet --hash --sign $ $ ${picotool_aesfile} ${picotool_enc_sigfile} + COMMAND picotool + ARGS encrypt + --quiet --hash --sign + ${picotool_encrypt_args} + $ $ + ${picotool_aesfile} ${picotool_enc_sigfile} + COMMAND_EXPAND_LISTS VERBATIM) if (ARGC EQUAL 2) set(${ARGV1} TRUE PARENT_SCOPE) From f2d02caf1e07979ef1806d6c05eb0a4da48f2d29 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 23 Jan 2025 11:58:30 +0000 Subject: [PATCH 2/8] Add EMBED and OTP_KEY_PAGE arguments to pico_encrypt_binary function --- tools/CMakeLists.txt | 65 ++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2cb0a93e7..4ddfa44bb 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -47,6 +47,12 @@ define_property(TARGET BRIEF_DOCS "Embed decryption stage into encrypted binary" FULL_DOCS "Embed decryption stage into encrypted binary" ) +define_property(TARGET + PROPERTY PICOTOOL_OTP_KEY_PAGE + INHERITED + BRIEF_DOCS "OTP page storing the AES key" + FULL_DOCS "OTP page storing the AES key" +) define_property(TARGET PROPERTY PICOTOOL_ENC_SIGFILE INHERITED @@ -426,7 +432,7 @@ function(pico_embed_pt_in_binary TARGET PTFILE) ) endfunction() -# pico_encrypt_binary(TARGET AESFILE [SIGFILE]) +# pico_encrypt_binary(TARGET AESFILE [SIGFILE ] [EMBED] [OTP_KEY_PAGE ]) # \brief_nodesc\ Encrypt the taget binary # # Encrypt the target binary with the given AES key (should be a binary @@ -435,47 +441,41 @@ endfunction() # This sets the target properties PICOTOOL_AESFILE to AESFILE, # and PICOTOOL_ENC_SIGFILE to SIGFILE if present, else PICOTOOL_SIGFILE. # +# Optionally, use EMBED to embed a decryption stage into the encrypted binary. +# This sets the target property PICOTOOL_EMBED_DECRYPTION to TRUE. +# +# Optionally, use OTP_KEY_PAGE to specify the OTP page storing the AES key. +# This sets the target property PICOTOOL_OTP_KEY_PAGE to OTP_KEY_PAGE. +# # \param\ AESFILE The AES key file to use # \param\ SIGFILE The PEM signature file to use +# \param\ EMBED Embed a decryption stage into the encrypted binary +# \param\ OTP_KEY_PAGE The OTP page storing the AES key function(pico_encrypt_binary TARGET AESFILE) + set(options EMBED) + set(oneValueArgs OTP_KEY_PAGE SIGFILE) + # set(multiValueArgs ) + cmake_parse_arguments(PARSE_ARGV 2 ENC "${options}" "${oneValueArgs}" "${multiValueArgs}") picotool_check_configurable(${TARGET}) set_target_properties(${TARGET} PROPERTIES PICOTOOL_AESFILE ${AESFILE} ) - if (ARGC EQUAL 3) + + if (ENC_EMBED) set_target_properties(${TARGET} PROPERTIES - PICOTOOL_ENC_SIGFILE ${ARGV2} + PICOTOOL_EMBED_DECRYPTION TRUE ) - else() - get_target_property(enc_sig_file ${TARGET} PICOTOOL_ENC_SIGFILE) - if (NOT enc_sig_file) - get_target_property(sig_file ${TARGET} PICOTOOL_SIGFILE) - if (NOT sig_file) - message(FATAL_ERROR "Signature file not set for ${TARGET}") - else() - set_target_properties(${TARGET} PROPERTIES - PICOTOOL_ENC_SIGFILE ${sig_file} - ) - endif() - endif() endif() -endfunction() -# pico_create_decrypting_binary(TARGET AESFILE [SIGFILE]) -# Encrypt the target binary with the given AES key (should be a binary -# file containing 128 bytes of a random key), add a decryption stage to -# decrypt the binary at runtime, and then sign the encrypted binary. -# This sets PICOTOOL_AESFILE to AESFILE, PICOTOOL_EMBED_DECRYPTION to TRUE, -# and PICOTOOL_ENC_SIGFILE to SIGFILE if present, else PICOTOOL_SIGFILE. -function(pico_create_decrypting_binary TARGET AESFILE) - picotool_check_configurable(${TARGET}) - set_target_properties(${TARGET} PROPERTIES - PICOTOOL_AESFILE ${AESFILE} - PICOTOOL_EMBED_DECRYPTION TRUE - ) - if (ARGC EQUAL 3) + if (ENC_OTP_KEY_PAGE) set_target_properties(${TARGET} PROPERTIES - PICOTOOL_ENC_SIGFILE ${ARGV2} + PICOTOOL_OTP_KEY_PAGE ${ENC_OTP_KEY_PAGE} + ) + endif() + + if (ENC_SIGFILE) + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_ENC_SIGFILE ${ENC_SIGFILE} ) else() get_target_property(enc_sig_file ${TARGET} PICOTOOL_ENC_SIGFILE) @@ -637,6 +637,11 @@ function(picotool_postprocess_binary TARGET) list(APPEND picotool_encrypt_args "--embed") endif() + get_target_property(otp_key_page ${TARGET} PICOTOOL_OTP_KEY_PAGE) + if (otp_key_page) + list(APPEND picotool_encrypt_args "--otp-key-page" ${otp_key_page}) + endif() + add_custom_command(TARGET ${TARGET} POST_BUILD DEPENDS ${picotool_enc_sigfile} ${picotool_aesfile} COMMAND picotool From 332dd64a9dddd2c6a03db881c11dcd39f9ec6d98 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 5 Feb 2025 16:00:17 +0000 Subject: [PATCH 3/8] Support passing otp_file to picotool encrypt --- tools/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 4ddfa44bb..637014613 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -649,7 +649,7 @@ function(picotool_postprocess_binary TARGET) --quiet --hash --sign ${picotool_encrypt_args} $ $ - ${picotool_aesfile} ${picotool_enc_sigfile} + ${picotool_aesfile} ${picotool_enc_sigfile} ${otp_file} COMMAND_EXPAND_LISTS VERBATIM) if (ARGC EQUAL 2) From 230593293b813e056e2074b87c5f2761c68a81cd Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 26 Feb 2025 12:36:08 +0000 Subject: [PATCH 4/8] Add IV salt to pico_encrypt_binary --- tools/CMakeLists.txt | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 637014613..b9495e935 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -41,6 +41,12 @@ define_property(TARGET BRIEF_DOCS "AES key for encrypting" FULL_DOCS "AES key for encrypting" ) +define_property(TARGET + PROPERTY PICOTOOL_IVFILE + INHERITED + BRIEF_DOCS "IV OTP salt for encrypting" + FULL_DOCS "IV OTP salt for encrypting" +) define_property(TARGET PROPERTY PICOTOOL_EMBED_DECRYPTION INHERITED @@ -432,14 +438,17 @@ function(pico_embed_pt_in_binary TARGET PTFILE) ) endfunction() -# pico_encrypt_binary(TARGET AESFILE [SIGFILE ] [EMBED] [OTP_KEY_PAGE ]) +# pico_encrypt_binary(TARGET AESFILE IVFILE [SIGFILE ] [EMBED] [OTP_KEY_PAGE ]) # \brief_nodesc\ Encrypt the taget binary # # Encrypt the target binary with the given AES key (should be a binary # file containing 128 bytes of a random key), and sign the encrypted binary. # -# This sets the target properties PICOTOOL_AESFILE to AESFILE, -# and PICOTOOL_ENC_SIGFILE to SIGFILE if present, else PICOTOOL_SIGFILE. +# Salts the public IV with the provided IVFILE (should be a binary file +# containing 16 bytes of a random IV), to give the IV used by the encryption. +# +# This sets the target properties PICOTOOL_AESFILE to AESFILE, PICOTOOL_IVFILE to IVFILE, and +# PICOTOOL_ENC_SIGFILE to SIGFILE if specified, else PICOTOOL_SIGFILE. # # Optionally, use EMBED to embed a decryption stage into the encrypted binary. # This sets the target property PICOTOOL_EMBED_DECRYPTION to TRUE. @@ -451,15 +460,18 @@ endfunction() # \param\ SIGFILE The PEM signature file to use # \param\ EMBED Embed a decryption stage into the encrypted binary # \param\ OTP_KEY_PAGE The OTP page storing the AES key -function(pico_encrypt_binary TARGET AESFILE) +function(pico_encrypt_binary TARGET AESFILE IVFILE) set(options EMBED) set(oneValueArgs OTP_KEY_PAGE SIGFILE) # set(multiValueArgs ) - cmake_parse_arguments(PARSE_ARGV 2 ENC "${options}" "${oneValueArgs}" "${multiValueArgs}") + cmake_parse_arguments(PARSE_ARGV 3 ENC "${options}" "${oneValueArgs}" "${multiValueArgs}") picotool_check_configurable(${TARGET}) set_target_properties(${TARGET} PROPERTIES PICOTOOL_AESFILE ${AESFILE} ) + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_IVFILE ${IVFILE} + ) if (ENC_EMBED) set_target_properties(${TARGET} PROPERTIES @@ -592,6 +604,10 @@ function(picotool_postprocess_binary TARGET) if (picotool_aesfile) pico_add_link_depend(${TARGET} ${picotool_aesfile}) endif() + get_target_property(picotool_ivfile ${TARGET} PICOTOOL_IVFILE) + if (picotool_ivfile) + pico_add_link_depend(${TARGET} ${picotool_ivfile}) + endif() get_target_property(picotool_enc_sigfile ${TARGET} PICOTOOL_ENC_SIGFILE) if (picotool_enc_sigfile) pico_add_link_depend(${TARGET} ${picotool_enc_sigfile}) @@ -631,7 +647,7 @@ function(picotool_postprocess_binary TARGET) VERBATIM) endif() # Encryption - if (picotool_aesfile) + if (picotool_aesfile AND picotool_ivfile) get_target_property(picotool_embed_decryption ${TARGET} PICOTOOL_EMBED_DECRYPTION) if (picotool_embed_decryption) list(APPEND picotool_encrypt_args "--embed") @@ -643,13 +659,13 @@ function(picotool_postprocess_binary TARGET) endif() add_custom_command(TARGET ${TARGET} POST_BUILD - DEPENDS ${picotool_enc_sigfile} ${picotool_aesfile} + DEPENDS ${picotool_enc_sigfile} ${picotool_aesfile} ${picotool_ivfile} COMMAND picotool ARGS encrypt --quiet --hash --sign ${picotool_encrypt_args} $ $ - ${picotool_aesfile} ${picotool_enc_sigfile} ${otp_file} + ${picotool_aesfile} ${picotool_ivfile} ${picotool_enc_sigfile} ${otp_file} COMMAND_EXPAND_LISTS VERBATIM) if (ARGC EQUAL 2) From 80f98679b177da9ed2cee31d3d8f9cb8e60df56e Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 4 Mar 2025 15:51:35 +0000 Subject: [PATCH 5/8] Add MBEDTLS option to use mbedtls decryption stage --- tools/CMakeLists.txt | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b9495e935..d8b1f77f8 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -53,6 +53,12 @@ define_property(TARGET BRIEF_DOCS "Embed decryption stage into encrypted binary" FULL_DOCS "Embed decryption stage into encrypted binary" ) +define_property(TARGET + PROPERTY PICOTOOL_USE_MBEDTLS_DECRYPTION + INHERITED + BRIEF_DOCS "Use MbedTLS based decryption stage - this is faster, but not secure against power snooping" + FULL_DOCS "Use MbedTLS based decryption stage - this is faster, but not secure against power snooping" +) define_property(TARGET PROPERTY PICOTOOL_OTP_KEY_PAGE INHERITED @@ -438,7 +444,7 @@ function(pico_embed_pt_in_binary TARGET PTFILE) ) endfunction() -# pico_encrypt_binary(TARGET AESFILE IVFILE [SIGFILE ] [EMBED] [OTP_KEY_PAGE ]) +# pico_encrypt_binary(TARGET AESFILE IVFILE [SIGFILE ] [EMBED] [MBEDTLS] [OTP_KEY_PAGE ]) # \brief_nodesc\ Encrypt the taget binary # # Encrypt the target binary with the given AES key (should be a binary @@ -453,15 +459,21 @@ endfunction() # Optionally, use EMBED to embed a decryption stage into the encrypted binary. # This sets the target property PICOTOOL_EMBED_DECRYPTION to TRUE. # +# Optionally, use MBEDTLS to to use the MbedTLS based decryption stage - this +# is faster, but less secure. +# This sets the target property PICOTOOL_USE_MBEDTLS_DECRYPTION to TRUE. +# # Optionally, use OTP_KEY_PAGE to specify the OTP page storing the AES key. # This sets the target property PICOTOOL_OTP_KEY_PAGE to OTP_KEY_PAGE. # # \param\ AESFILE The AES key file to use +# \param\ IVFILE The IV file to use # \param\ SIGFILE The PEM signature file to use # \param\ EMBED Embed a decryption stage into the encrypted binary +# \param\ MBEDTLS Use MbedTLS based decryption stage (faster, but less secure) # \param\ OTP_KEY_PAGE The OTP page storing the AES key function(pico_encrypt_binary TARGET AESFILE IVFILE) - set(options EMBED) + set(options EMBED MBEDTLS) set(oneValueArgs OTP_KEY_PAGE SIGFILE) # set(multiValueArgs ) cmake_parse_arguments(PARSE_ARGV 3 ENC "${options}" "${oneValueArgs}" "${multiValueArgs}") @@ -479,6 +491,12 @@ function(pico_encrypt_binary TARGET AESFILE IVFILE) ) endif() + if (ENC_MBEDTLS) + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_USE_MBEDTLS_DECRYPTION TRUE + ) + endif() + if (ENC_OTP_KEY_PAGE) set_target_properties(${TARGET} PROPERTIES PICOTOOL_OTP_KEY_PAGE ${ENC_OTP_KEY_PAGE} @@ -653,6 +671,11 @@ function(picotool_postprocess_binary TARGET) list(APPEND picotool_encrypt_args "--embed") endif() + get_target_property(picotool_mbedtls_decryption ${TARGET} PICOTOOL_USE_MBEDTLS_DECRYPTION) + if (picotool_mbedtls_decryption) + list(APPEND picotool_encrypt_args "--use-mbedtls") + endif() + get_target_property(otp_key_page ${TARGET} PICOTOOL_OTP_KEY_PAGE) if (otp_key_page) list(APPEND picotool_encrypt_args "--otp-key-page" ${otp_key_page}) From c0c034a88457c00bb2010975c8a8f95955b88608 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 26 Mar 2025 16:16:43 +0000 Subject: [PATCH 6/8] Improve docs for pico_encrypt_binary Add newlines for readability, and explain why MbedTLS version is insecure --- tools/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index d8b1f77f8..ace1168cd 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -460,7 +460,8 @@ endfunction() # This sets the target property PICOTOOL_EMBED_DECRYPTION to TRUE. # # Optionally, use MBEDTLS to to use the MbedTLS based decryption stage - this -# is faster, but less secure. +# is faster, but offers no security against power or timing sniffing attacks, +# and takes up more code size. # This sets the target property PICOTOOL_USE_MBEDTLS_DECRYPTION to TRUE. # # Optionally, use OTP_KEY_PAGE to specify the OTP page storing the AES key. From fdc61ca2fb8a9b0e0fa73c4d93c06f3d928efff3 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 28 Apr 2025 16:47:21 +0100 Subject: [PATCH 7/8] Key can be 128 byte key share or 32 byte key --- tools/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ace1168cd..89f5e3839 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -448,7 +448,8 @@ endfunction() # \brief_nodesc\ Encrypt the taget binary # # Encrypt the target binary with the given AES key (should be a binary -# file containing 128 bytes of a random key), and sign the encrypted binary. +# file containing 128 bytes of a random key share, or 32 bytes of a random key), +# and sign the encrypted binary. # # Salts the public IV with the provided IVFILE (should be a binary file # containing 16 bytes of a random IV), to give the IV used by the encryption. From 230dd3edfbb61b3dc45c3e249ed0320831896e09 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 19 May 2025 17:20:16 +0100 Subject: [PATCH 8/8] Always package encrypted binaries with embedded decryption stages The embedded decryption stage only works if the binary is written to Flash and then loaded to SRAM by the bootrom --- tools/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 89f5e3839..85358571e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -491,6 +491,14 @@ function(pico_encrypt_binary TARGET AESFILE IVFILE) set_target_properties(${TARGET} PROPERTIES PICOTOOL_EMBED_DECRYPTION TRUE ) + + # Embedded decryption stage only works with packaged binaries + get_target_property(uf2_package_addr ${TARGET} PICOTOOL_UF2_PACKAGE_ADDR) + if (NOT uf2_package_addr) + set_target_properties(${TARGET} PROPERTIES + PICOTOOL_UF2_PACKAGE_ADDR 0x10000000 + ) + endif() endif() if (ENC_MBEDTLS)