修改了4g分片下载,改了版本号约定 最后数字是模型版本号
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // 支持 std::vector, std::map 等
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <array>
|
||||
#include <openssl/evp.h>
|
||||
#include <algorithm>
|
||||
#include <openssl/evp.h>
|
||||
#include "native_logger.hpp"
|
||||
|
||||
namespace netcore{
|
||||
@@ -18,11 +15,11 @@ namespace netcore{
|
||||
constexpr size_t kOtaMagicLen = 7;
|
||||
constexpr size_t kGcmNonceLen = 12;
|
||||
constexpr size_t kGcmTagLen = 16;
|
||||
constexpr size_t kHeaderLen = kOtaMagicLen + kGcmNonceLen;
|
||||
// 分块解密,避免整包读入导致 RAM 峰值约为「文件大小×2」(小内存设备易 OOM)
|
||||
constexpr size_t kDecryptChunk = 65536;
|
||||
|
||||
// 固定 32-byte AES-256-GCM key(提高被直接查看的成本;不是绝对安全)
|
||||
// 注意:需要与打包端传入的 --aead-key-hex 保持一致。
|
||||
static std::array<uint8_t, 32> ota_key_bytes() {
|
||||
// 简单拆分混淆:key = a XOR b
|
||||
static const std::array<uint8_t, 32> a = {
|
||||
0x92,0x99,0x4d,0x06,0x6f,0xb6,0xa6,0x3d,0x85,0x08,0xbe,0x73,0x5e,0x73,0x4d,0x8a,
|
||||
0x53,0x88,0xe6,0x99,0xfc,0x10,0x29,0xb9,0x16,0x9b,0xe7,0x0c,0x65,0x21,0x1c,0xce
|
||||
@@ -36,56 +33,45 @@ namespace netcore{
|
||||
return k;
|
||||
}
|
||||
|
||||
static bool read_file_all(const std::string& path, std::vector<uint8_t>& 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_t>(size));
|
||||
if (!ifs.read(reinterpret_cast<char*>(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<const char*>(data), static_cast<std::streamsize>(len));
|
||||
return static_cast<bool>(ofs);
|
||||
}
|
||||
|
||||
bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path) {
|
||||
std::vector<uint8_t> in;
|
||||
if (!netcore::read_file_all(input_path, in)) {
|
||||
netcore::log_error(std::string("decrypt_ota_file: read failed: ") + input_path);
|
||||
std::ifstream ifs(input_path, std::ios::binary);
|
||||
if (!ifs) {
|
||||
netcore::log_error(std::string("decrypt_ota_file: open in failed: ") + input_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t min_len = kOtaMagicLen + kGcmNonceLen + kGcmTagLen + 1;
|
||||
if (in.size() < min_len) {
|
||||
ifs.seekg(0, std::ios::end);
|
||||
const std::streampos szp = ifs.tellg();
|
||||
if (szp <= 0) {
|
||||
netcore::log_error("decrypt_ota_file: empty input");
|
||||
return false;
|
||||
}
|
||||
const uint64_t file_size = static_cast<uint64_t>(szp);
|
||||
const size_t min_len = kHeaderLen + kGcmTagLen + 1;
|
||||
if (file_size < min_len) {
|
||||
netcore::log_error("decrypt_ota_file: too short");
|
||||
return false;
|
||||
}
|
||||
if (!std::equal(in.begin(), in.begin() + kOtaMagicLen, reinterpret_cast<const uint8_t*>(kOtaMagic))) {
|
||||
const uint64_t ciphertext_len = file_size - kHeaderLen - kGcmTagLen;
|
||||
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
std::array<uint8_t, kHeaderLen> header{};
|
||||
ifs.read(reinterpret_cast<char*>(header.data()), static_cast<std::streamsize>(kHeaderLen));
|
||||
if (ifs.gcount() != static_cast<std::streamsize>(kHeaderLen)) {
|
||||
netcore::log_error("decrypt_ota_file: read header failed");
|
||||
return false;
|
||||
}
|
||||
if (!std::equal(header.begin(), header.begin() + kOtaMagicLen,
|
||||
reinterpret_cast<const uint8_t*>(kOtaMagic))) {
|
||||
netcore::log_error("decrypt_ota_file: bad magic");
|
||||
return false;
|
||||
}
|
||||
const uint8_t* nonce = header.data() + kOtaMagicLen;
|
||||
|
||||
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");
|
||||
std::ofstream ofs(output_zip_path, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs) {
|
||||
netcore::log_error(std::string("decrypt_ota_file: open out failed: ") + output_zip_path);
|
||||
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<uint8_t> plain(ciphertext_len);
|
||||
int out_len1 = 0;
|
||||
int out_len2 = 0;
|
||||
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx) {
|
||||
@@ -95,6 +81,8 @@ namespace netcore{
|
||||
|
||||
bool ok = false;
|
||||
auto key = ota_key_bytes();
|
||||
std::vector<uint8_t> chunk_in(kDecryptChunk);
|
||||
std::vector<uint8_t> chunk_out(kDecryptChunk + EVP_MAX_BLOCK_LENGTH);
|
||||
|
||||
do {
|
||||
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
|
||||
@@ -109,27 +97,59 @@ namespace netcore{
|
||||
netcore::log_error("decrypt_ota_file: set key/iv failed");
|
||||
break;
|
||||
}
|
||||
if (1 != EVP_DecryptUpdate(ctx, plain.data(), &out_len1, ciphertext, static_cast<int>(ciphertext_len))) {
|
||||
netcore::log_error("decrypt_ota_file: update failed");
|
||||
|
||||
uint64_t remaining = ciphertext_len;
|
||||
while (remaining > 0) {
|
||||
const size_t n = static_cast<size_t>(std::min<uint64_t>(remaining, kDecryptChunk));
|
||||
ifs.read(reinterpret_cast<char*>(chunk_in.data()), static_cast<std::streamsize>(n));
|
||||
if (ifs.gcount() != static_cast<std::streamsize>(n)) {
|
||||
netcore::log_error("decrypt_ota_file: read ciphertext chunk failed");
|
||||
goto cleanup_ctx;
|
||||
}
|
||||
int outl = 0;
|
||||
if (1 != EVP_DecryptUpdate(ctx, chunk_out.data(), &outl,
|
||||
chunk_in.data(), static_cast<int>(n))) {
|
||||
netcore::log_error("decrypt_ota_file: update failed");
|
||||
goto cleanup_ctx;
|
||||
}
|
||||
if (outl > 0) {
|
||||
ofs.write(reinterpret_cast<const char*>(chunk_out.data()), outl);
|
||||
if (!ofs) {
|
||||
netcore::log_error("decrypt_ota_file: write plaintext failed");
|
||||
goto cleanup_ctx;
|
||||
}
|
||||
}
|
||||
remaining -= n;
|
||||
}
|
||||
|
||||
std::array<uint8_t, kGcmTagLen> tag{};
|
||||
ifs.read(reinterpret_cast<char*>(tag.data()), static_cast<std::streamsize>(kGcmTagLen));
|
||||
if (ifs.gcount() != static_cast<std::streamsize>(kGcmTagLen)) {
|
||||
netcore::log_error("decrypt_ota_file: read tag failed");
|
||||
break;
|
||||
}
|
||||
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(kGcmTagLen), const_cast<uint8_t*>(tag))) {
|
||||
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(kGcmTagLen), tag.data())) {
|
||||
netcore::log_error("decrypt_ota_file: set tag failed");
|
||||
break;
|
||||
}
|
||||
if (1 != EVP_DecryptFinal_ex(ctx, plain.data() + out_len1, &out_len2)) {
|
||||
|
||||
int outl2 = 0;
|
||||
if (1 != EVP_DecryptFinal_ex(ctx, chunk_out.data(), &outl2)) {
|
||||
netcore::log_error("decrypt_ota_file: final failed (auth tag mismatch?)");
|
||||
break;
|
||||
}
|
||||
const size_t plain_len = static_cast<size_t>(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;
|
||||
if (outl2 > 0) {
|
||||
ofs.write(reinterpret_cast<const char*>(chunk_out.data()), outl2);
|
||||
if (!ofs) {
|
||||
netcore::log_error("decrypt_ota_file: write final failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
} while (false);
|
||||
|
||||
cleanup_ctx:
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
} // namespace netcore
|
||||
|
||||
Reference in New Issue
Block a user