Initial partial encryption attempt
diff --git a/bintool/bintool.cpp b/bintool/bintool.cpp index bba2dfc..48f7fe1 100644 --- a/bintool/bintool.cpp +++ b/bintool/bintool.cpp
@@ -1009,6 +1009,19 @@ } +void encrypt_vector(std::vector<uint8_t> &enc_data, const aes_key_t aes_key, std::vector<uint8_t> &iv_data) { + iv_t iv; + for(auto &e : iv.bytes) { + e = rand(); + } + + iv_data.resize(sizeof(iv.bytes)); + memcpy(iv_data.data(), iv.bytes, sizeof(iv.bytes)); + + aes256_buffer(enc_data.data(), enc_data.size(), enc_data.data(), &aes_key, &iv); +} + + void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, model_t model, std::vector<uint8_t> &iv_data, std::vector<uint8_t> &enc_data) { std::vector<uint8_t> to_enc = get_lm_hash_data(elf, new_block, model);
diff --git a/bintool/bintool.h b/bintool/bintool.h index f8c60ff..79aef87 100644 --- a/bintool/bintool.h +++ b/bintool/bintool.h
@@ -30,6 +30,7 @@ int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, const private_t private_key, model_t model, bool hash_value, bool sign, bool clear_sram = false, bool pin_xip_sram = false); void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, model_t model, std::vector<uint8_t> &iv_data, std::vector<uint8_t> &enc_data); int encrypt(elf_file *elf, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, model_t model, std::vector<uint8_t> iv_salt, bool hash_value, bool sign); + void encrypt_vector(std::vector<uint8_t> &enc_data, const aes_key_t aes_key, std::vector<uint8_t> &iv_data); #endif // Bins
diff --git a/main.cpp b/main.cpp index b11973a..043d1ef 100644 --- a/main.cpp +++ b/main.cpp
@@ -606,6 +606,8 @@ struct { bool embed = false; + bool partial = false; + string partial_name = ".enc_data"; bool otp_key_page_set = false; bool fast_rosc = false; bool use_mbedtls = false; @@ -973,6 +975,11 @@ option("--quiet").set(settings.quiet) % "Don't print any output" + option("--verbose").set(settings.verbose) % "Print verbose output" + option("--embed").set(settings.encrypt.embed) % "Embed bootloader in output file" + + option("--partial").set(settings.encrypt.partial) % "Only encrypt the .encrypted ELF segment" + + ( + option("--partial-name") & + value("section").set(settings.encrypt.partial_name) + ).min(0) % "Set section name to encrypt when using --partial (default .enc_data)" + option("--fast-rosc").set(settings.encrypt.fast_rosc) % "Use ~180MHz ROSC configuration for embedded bootloader" + option("--use-mbedtls").set(settings.encrypt.use_mbedtls) % "Use MbedTLS implementation of embedded bootloader (faster but less secure)" + ( @@ -5372,12 +5379,19 @@ std::vector<uint8_t> iv_salt; iv_salt.resize(16); + if (settings.encrypt.embed && settings.encrypt.partial) { + fail(ERROR_ARGS, "Only one of --embed or --partial is supported"); + } + if (get_file_type() == filetype::elf) { isElf = true; } else if (get_file_type() == filetype::bin) { if (settings.encrypt.embed) { fail(ERROR_ARGS, "Can only embed decrypting bootloader into ELFs"); } + if (settings.encrypt.partial) { + fail(ERROR_ARGS, "Can only partially encrypt ELFs"); + } isBin = true; } else { fail(ERROR_ARGS, "Can only sign ELFs or BINs"); @@ -5547,10 +5561,36 @@ block new_block = place_new_block(elf, first_block, model); elf->editable = true; - // Delete any non-generic load_map entries, as they will be invalid after encryption - remove_non_generic_load_map_entries(&new_block, model); + if (!settings.encrypt.partial) { + // Delete any non-generic load_map entries, as they will be invalid after encryption + remove_non_generic_load_map_entries(&new_block, model); + } - if (settings.encrypt.embed) { + if (settings.encrypt.partial) { + auto enc_section = elf->get_section(settings.encrypt.partial_name); + assert(enc_section); + + std::vector<uint8_t> iv_data; + std::vector<uint8_t> enc_data = elf->content(*enc_section); + + if (enc_data.size() % 16 != 0) { + fail(ERROR_INCOMPATIBLE, + "The section for partial encryption must have a size that is a multiple of 16, but %s has size %d", + settings.encrypt.partial_name.c_str(), enc_data.size() + ); + } + + encrypt_vector(enc_data, aes_key, iv_data); + + elf->content(*enc_section, enc_data); + + // Sign the final thing + sign_guts_elf(elf, private_key, public_key, model); + + auto out = get_file_idx(ios::out|ios::binary, 1); + elf->write(out); + out->close(); + } else if (settings.encrypt.embed) { // Detect generic load maps from the encrypted binary, and populate options to propogate them std::shared_ptr<load_map_item> load_map = new_block.get_item<load_map_item>(); if (load_map != nullptr) {