refactor: 优化 NBPF 模块 - 缓存导入/合并重复方法/减少I/O
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled

- crypto.py: 8个_imp_*方法改为_ModuleCache类缓存导入
- crypto.py: outer/inner加解密合并为_layer_encrypt/decrypt
- crypto.py: 提取公共摘要计算方法,拆分长方法
- compiler.py: 删除_obfuscate_code中未使用的死代码
- loader.py: 3次ZIP扫描合并为1次缓存读取
- format.py: 更新为使用_ModuleCache
- 合计减少205行代码(1707→1502)
This commit is contained in:
2026-05-17 15:36:45 +08:00
parent 1736bb5801
commit e67d2d8ef6
20 changed files with 324 additions and 527 deletions

View File

@@ -79,8 +79,11 @@ class NBPFLoader:
try:
with zipfile.ZipFile(nbpf_path, 'r') as zf:
# 0. 一次扫描,缓存 NIR 模块数据
nir_modules = self._read_nir_modules(zf)
# 1. 外层验签(先用包内公钥验签,再查信任状态)
signer_pub_key, is_trusted, trusted_name = self._verify_outer_signature(zf)
signer_pub_key, is_trusted, trusted_name = self._verify_outer_signature(zf, nir_modules)
status = "已信任" if is_trusted else "未信任"
Log.info("NBPF", f"外层签名验证通过 (signer: {trusted_name or 'unknown'}, {status})")
@@ -89,7 +92,7 @@ class NBPFLoader:
key1_buf = bytearray(key1)
# 3. 中层验签(传入外层签名者名称,确保内外签名者一致)
rsa_signer = self._verify_inner_signature(zf, meta_inf, trusted_name)
rsa_signer = self._verify_inner_signature(nir_modules, meta_inf, trusted_name)
Log.info("NBPF", f"中层签名验证通过 (signer: {rsa_signer})")
# 4. 中层解密
@@ -102,7 +105,7 @@ class NBPFLoader:
self.crypto._secure_wipe(key2_buf)
# 6. 解密 NIR 数据
nir_data = self._decrypt_nir_data(zf, key2)
nir_data = self._decrypt_nir_data_raw(nir_modules, key2)
# 7. 内层验签
self._verify_module_signatures(nir_data, meta_inf, hmac_key)
@@ -145,9 +148,19 @@ class NBPFLoader:
except Exception as e:
raise NBPFLoadError(f"加载失败: {type(e).__name__}: {e}") from e
@staticmethod
def _read_nir_modules(zf: zipfile.ZipFile) -> dict[str, dict]:
"""一次扫描 ZIP 中所有 NIR 模块,缓存结果"""
modules = {}
for info in zf.infolist():
if info.filename.startswith(NBPFFormatter.NIR_DIR) and not info.filename.endswith("/"):
mod_name = info.filename[len(NBPFFormatter.NIR_DIR):]
modules[mod_name] = json.loads(zf.read(info.filename).decode("utf-8"))
return modules
# ── 外层验签 ──
def _verify_outer_signature(self, zf: zipfile.ZipFile) -> tuple[bytes, bool, str | None]:
def _verify_outer_signature(self, zf: zipfile.ZipFile, nir_modules: dict[str, dict]) -> tuple[bytes, bool, str | None]:
"""外层 Ed25519 签名验证
先用包内公钥验签(不依赖外部信任列表),验签通过后再检查信任状态。
@@ -157,9 +170,6 @@ class NBPFLoader:
Returns:
(signer_pub_key_bytes, is_trusted, trusted_name)
- signer_pub_key_bytes: 签名者 Ed25519 公钥(用于上层判断信任)
- is_trusted: 公钥是否在本地信任列表中
- trusted_name: 信任列表中的名称(不信任时为 None
"""
if NBPFFormatter.SIGNATURE not in zf.namelist():
raise NBPFLoadError("缺少外层签名文件")
@@ -169,29 +179,16 @@ class NBPFLoader:
signature_b64 = zf.read(NBPFFormatter.SIGNATURE).decode().strip()
signer_pub_key = zf.read(NBPFFormatter.SIGNER_PEM)
# 计算包摘要(与 full_encrypt_package 一致
# 计算包摘要(使用缓存的 nir_modules
encryption_data = json.loads(zf.read(NBPFFormatter.ENCRYPTION).decode("utf-8"))
digest = hashlib.sha256()
digest.update(json.dumps(encryption_data["data"]).encode())
digest = NBPCrypto._build_package_digest(encryption_data["data"], nir_modules)
# 按模块名排序,添加模块名和密文
nir_modules = {}
for info in zf.infolist():
if info.filename.startswith(NBPFFormatter.NIR_DIR) and not info.filename.endswith("/"):
mod_name = info.filename[len(NBPFFormatter.NIR_DIR):]
mod_data = json.loads(zf.read(info.filename).decode("utf-8"))
nir_modules[mod_name] = mod_data
for mod_name in sorted(nir_modules.keys()):
digest.update(mod_name.encode())
digest.update(nir_modules[mod_name]["ciphertext"].encode())
# 直接用包内公钥验签(不依赖外部信任列表)
# 直接用包内公钥验签
signature = base64.b64decode(signature_b64)
if not self.crypto.outer_verify(digest.digest(), signature, signer_pub_key):
if not self.crypto.outer_verify(digest, signature, signer_pub_key):
raise NBPFLoadError("外层签名验证失败,包可能被篡改")
# 验签通过后,检查公钥是否在本地信任列表中
# 检查公钥是否在本地信任列表中
is_trusted = False
trusted_name = None
for name, trusted_key in self.trusted_ed25519_keys.items():
@@ -224,7 +221,7 @@ class NBPFLoader:
# ── 中层验签 ──
def _verify_inner_signature(self, zf: zipfile.ZipFile, meta_inf: dict, ed25519_signer: str = None) -> str:
def _verify_inner_signature(self, nir_modules: dict[str, dict], meta_inf: dict, ed25519_signer: str = None) -> str:
"""中层 RSA-4096 签名验证,返回签名者名称
签名计算方式与 full_encrypt_package 一致。
@@ -232,7 +229,7 @@ class NBPFLoader:
否则遍历所有信任的 RSA 密钥。
Args:
zf: 打开的 ZIP 文件
nir_modules: 缓存的 NIR 模块数据
meta_inf: 解密后的 META-INF 数据
ed25519_signer: 外层 Ed25519 签名者名称
@@ -246,20 +243,8 @@ class NBPFLoader:
if not inner_sig_b64:
raise NBPFLoadError("缺少中层签名")
# 计算 NIR 数据摘要(与 full_encrypt_package 一致)
nir_modules = {}
for info in zf.infolist():
if info.filename.startswith(NBPFFormatter.NIR_DIR) and not info.filename.endswith("/"):
mod_name = info.filename[len(NBPFFormatter.NIR_DIR):]
mod_data = json.loads(zf.read(info.filename).decode("utf-8"))
nir_modules[mod_name] = mod_data
nir_digest = hashlib.sha256()
for mod_name in sorted(nir_modules.keys()):
nir_digest.update(mod_name.encode())
nir_digest.update(nir_modules[mod_name]["ciphertext"].encode())
# 查找匹配的 RSA 公钥
# 使用缓存的 nir_modules 计算摘要
nir_digest = NBPCrypto._build_nir_digest(nir_modules)
inner_sig = base64.b64decode(inner_sig_b64)
# 优先使用与外层签名者同名的 RSA 密钥
@@ -267,11 +252,10 @@ class NBPFLoader:
if ed25519_signer and ed25519_signer in self.trusted_rsa_keys:
candidates.append((ed25519_signer, self.trusted_rsa_keys[ed25519_signer]))
else:
# 未指定或未找到同名密钥,遍历全部
candidates = list(self.trusted_rsa_keys.items())
for name, rsa_pub_key in candidates:
if self.crypto.inner_verify(nir_digest.digest(), inner_sig, rsa_pub_key):
if self.crypto.inner_verify(nir_digest, inner_sig, rsa_pub_key):
return name
raise NBPFLoadError("中层签名验证失败,无法匹配任何信任的 RSA 公钥")
@@ -291,21 +275,12 @@ class NBPFLoader:
# ── 解密 NIR 数据 ──
def _decrypt_nir_data(self, zf: zipfile.ZipFile, key2: bytes) -> dict[str, bytes]:
"""解密 NIR 数据,返回 {module_name: nir_bytes}"""
nir_data = {}
for info in zf.infolist():
if not info.filename.startswith(NBPFFormatter.NIR_DIR):
continue
if info.filename.endswith("/"):
continue
module_name = info.filename[len(NBPFFormatter.NIR_DIR):]
enc_info = json.loads(zf.read(info.filename).decode("utf-8"))
mod_data = self.crypto.inner_decrypt(enc_info, key2)
nir_data[module_name] = mod_data
return nir_data
def _decrypt_nir_data_raw(self, nir_modules: dict[str, dict], key2: bytes) -> dict[str, bytes]:
"""解密 NIR 数据,使用缓存的模块数据"""
return {
mod_name: self.crypto.inner_decrypt(enc_info, key2)
for mod_name, enc_info in nir_modules.items()
}
# ── 内层验签 ──