#!/usr/bin/env python3 """ 密钥生成与插件签名工具 - 生成 Falck 官方密钥对 - 为所有官方插件签名 """ import sys import json import base64 import hashlib import time from pathlib import Path from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.hazmat.backends import default_backend # ========== 配置 ========== PROJECT_ROOT = Path(__file__).parent.parent # 修复:tools 的上级目录 KEY_DIR = PROJECT_ROOT / "data" / "signature-verifier" / "keys" STORE_DIR = PROJECT_ROOT / "store" # 官方作者目录 OFFICIAL_AUTHORS = ["FutureOSS", "Falck"] def generate_keypair(author: str): """生成 4096 位 RSA 密钥对""" print(f"\n{'='*60}") print(f"生成 {author} 的密钥对...") print(f"{'='*60}") private_key = rsa.generate_private_key( public_exponent=65537, key_size=4096, backend=default_backend() ) public_key = private_key.public_key() # 保存私钥 private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ) priv_dir = KEY_DIR / "private" priv_dir.mkdir(parents=True, exist_ok=True) priv_file = priv_dir / f"{author.lower()}_private.pem" priv_file.write_bytes(private_pem) print(f"私钥已保存: {priv_file}") # 保存公钥 public_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) pub_dir = KEY_DIR / "public" pub_dir.mkdir(parents=True, exist_ok=True) pub_file = pub_dir / f"{author}.pem" pub_file.write_bytes(public_pem) print(f"公钥已保存: {pub_file}") # 显示公钥(用于嵌入代码) print(f"\n--- 公钥 PEM (用于嵌入 main.py) ---") print(public_pem.decode()) print(f"--- END ---\n") return private_key, public_key def compute_plugin_hash(plugin_dir: Path) -> str: """计算插件目录的内容哈希""" hasher = hashlib.sha256() files_to_hash = [] for file_path in sorted(plugin_dir.rglob("*")): if file_path.is_file() and file_path.name != "SIGNATURE": rel_path = file_path.relative_to(plugin_dir) files_to_hash.append((str(rel_path), file_path)) for rel_path, file_path in files_to_hash: hasher.update(rel_path.encode("utf-8")) hasher.update(file_path.read_bytes()) return hasher.hexdigest() def sign_plugin(plugin_dir: Path, private_key, signer_name: str, author: str): """为插件生成签名""" plugin_hash = compute_plugin_hash(plugin_dir) # 签名 signed_data = f"{author}:{plugin_hash}".encode("utf-8") signature = private_key.sign( signed_data, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() ) # 写入签名文件 sig_data = { "signature": base64.b64encode(signature).decode(), "signer": signer_name, "algorithm": "RSA-SHA256", "timestamp": time.time(), "plugin_hash": plugin_hash, "author": author } signature_file = plugin_dir / "SIGNATURE" signature_file.write_text(json.dumps(sig_data, indent=2)) print(f" ✓ 已签名: {plugin_dir.name} (哈希: {plugin_hash[:16]}...)") def sign_all_plugins(private_key): """为所有官方插件签名""" for author in OFFICIAL_AUTHORS: author_dir = STORE_DIR / f"@{{{author}}}" if not author_dir.exists(): print(f"\n警告: 作者目录不存在: {author_dir}") continue print(f"\n{'='*60}") print(f"为 @{{{author}}} 的插件签名...") print(f"{'='*60}") count = 0 for plugin_dir in sorted(author_dir.iterdir()): if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): sign_plugin(plugin_dir, private_key, author, author) count += 1 print(f"\n完成: 已签名 {count} 个 @{author} 插件") def main(): print("="*60) print("FutureOSS 插件签名工具") print("="*60) # 检查 cryptography try: from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.hazmat.backends import default_backend except ImportError: print("错误: 未安装 cryptography 库") print("运行: pip install cryptography") sys.exit(1) # 步骤 1: 生成密钥对 print("\n步骤 1: 生成 Falck 官方密钥对...") falck_priv, falck_pub = generate_keypair("Falck") print("\n步骤 1b: 生成 FutureOSS 官方密钥对...") foss_priv, foss_pub = generate_keypair("FutureOSS") # 步骤 2: 为所有官方插件签名(使用对应的密钥) print("\n步骤 2: 为所有官方插件签名...") # Falck 的插件用 Falck 密钥签名 falck_dir = STORE_DIR / "@{Falck}" if falck_dir.exists(): print(f"\n{'='*60}") print("为 @{Falck} 的插件使用 Falck 密钥签名...") print(f"{'='*60}") for plugin_dir in sorted(falck_dir.iterdir()): if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): sign_plugin(plugin_dir, falck_priv, "Falck", "Falck") # FutureOSS 的插件用 FutureOSS 密钥签名 foss_dir = STORE_DIR / "@{FutureOSS}" if foss_dir.exists(): print(f"\n{'='*60}") print("为 @{FutureOSS} 的插件使用 FutureOSS 密钥签名...") print(f"{'='*60}") for plugin_dir in sorted(foss_dir.iterdir()): if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): sign_plugin(plugin_dir, foss_priv, "FutureOSS", "FutureOSS") print("\n" + "="*60) print("全部完成!") print("="*60) print(f"\n密钥位置: {KEY_DIR}") print("请将公钥嵌入 signature-verifier/main.py 的 FALCK_PUBLIC_KEY_PEM 变量") print("并妥善保管私钥,不要提交到版本控制系统!") if __name__ == "__main__": main()