diff --git a/cpp_ext/decrypt_ota_file.hpp b/cpp_ext/decrypt_ota_file.hpp new file mode 100644 index 0000000..18ebd0e --- /dev/null +++ b/cpp_ext/decrypt_ota_file.hpp @@ -0,0 +1,98 @@ +namespace netcore{ +static bool read_file_all(const std::string& path, std::vector& out) { + std::ifstream ifs(path, std::ios::binary); + if (!ifs) return false; + ifs.seekg(0, std::ios::end); + std::streampos size = ifs.tellg(); + if (size <= 0) return false; + ifs.seekg(0, std::ios::beg); + out.resize(static_cast(size)); + if (!ifs.read(reinterpret_cast(out.data()), size)) return false; + return true; +} + +static bool write_file_all(const std::string& path, const uint8_t* data, size_t len) { + std::ofstream ofs(path, std::ios::binary | std::ios::trunc); + if (!ofs) return false; + ofs.write(reinterpret_cast(data), static_cast(len)); + return static_cast(ofs); +} + +static bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path) { + std::vector in; + if (!netcore::read_file_all(input_path, in)) { + netcore::log_error(std::string("decrypt_ota_file: read failed: ") + input_path); + return false; + } + + const size_t min_len = kOtaMagicLen + kGcmNonceLen + kGcmTagLen + 1; + if (in.size() < min_len) { + netcore::log_error("decrypt_ota_file: too short"); + return false; + } + if (!std::equal(in.begin(), in.begin() + kOtaMagicLen, reinterpret_cast(kOtaMagic))) { + netcore::log_error("decrypt_ota_file: bad magic"); + return false; + } + + const uint8_t* nonce = in.data() + kOtaMagicLen; + const uint8_t* ct_and_tag = in.data() + kOtaMagicLen + kGcmNonceLen; + const size_t ct_and_tag_len = in.size() - (kOtaMagicLen + kGcmNonceLen); + if (ct_and_tag_len <= kGcmTagLen) { + netcore::log_error("decrypt_ota_file: no ciphertext"); + return false; + } + const size_t ciphertext_len = ct_and_tag_len - kGcmTagLen; + const uint8_t* ciphertext = ct_and_tag; + const uint8_t* tag = ct_and_tag + ciphertext_len; + + std::vector plain(ciphertext_len); + int out_len1 = 0; + int out_len2 = 0; + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + netcore::log_error("decrypt_ota_file: EVP_CIPHER_CTX_new failed"); + return false; + } + + bool ok = false; + auto key = ota_key_bytes(); + + do { + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) { + netcore::log_error("decrypt_ota_file: DecryptInit failed"); + break; + } + if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, static_cast(kGcmNonceLen), nullptr)) { + netcore::log_error("decrypt_ota_file: set ivlen failed"); + break; + } + if (1 != EVP_DecryptInit_ex(ctx, nullptr, nullptr, key.data(), nonce)) { + netcore::log_error("decrypt_ota_file: set key/iv failed"); + break; + } + if (1 != EVP_DecryptUpdate(ctx, plain.data(), &out_len1, ciphertext, static_cast(ciphertext_len))) { + netcore::log_error("decrypt_ota_file: update failed"); + break; + } + if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast(kGcmTagLen), const_cast(tag))) { + netcore::log_error("decrypt_ota_file: set tag failed"); + break; + } + if (1 != EVP_DecryptFinal_ex(ctx, plain.data() + out_len1, &out_len2)) { + netcore::log_error("decrypt_ota_file: final failed (auth tag mismatch?)"); + break; + } + const size_t plain_len = static_cast(out_len1 + out_len2); + if (!netcore::write_file_all(output_zip_path, plain.data(), plain_len)) { + netcore::log_error(std::string("decrypt_ota_file: write failed: ") + output_zip_path); + break; + } + ok = true; + } while (false); + + EVP_CIPHER_CTX_free(ctx); + return ok; +} +} \ No newline at end of file diff --git a/cpp_ext/msg_handler.cpp b/cpp_ext/msg_handler.cpp new file mode 100644 index 0000000..e69de29 diff --git a/cpp_ext/utils.cpp b/cpp_ext/utils.cpp new file mode 100644 index 0000000..e69de29 diff --git a/cpp_ext/utils.hpp b/cpp_ext/utils.hpp new file mode 100644 index 0000000..e69de29