Files
AVM360/tools/cpu_id.py
2026-04-01 14:11:47 +08:00

409 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# client.py - RK3588板端激活程序永久有效
import os
import sys
import json
import hashlib
import hmac
import requests
import subprocess
import time
import logging
import argparse
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# 配置
CONFIG = {
'SERVER_URL': 'http://129.211.170.245:5000/', # 修改为实际服务器地址
'KEY_FILE': '/etc/device.key', # 密钥文件存储路径
'KEY_BACKUP_FILE': '/etc/device.key.bak', # 密钥备份文件
'CHIP_ID_SOURCES': [
'/sys/devices/soc0/serial_number',
'/sys/devices/platform/ff650000.serial/serial0',
'/proc/cpuinfo'
],
'ACTIVATE_URL': '/activate',
'VERIFY_URL': '/verify',
'ACTIVATE_RETRY_COUNT': 3,
'SECRET_KEY': '69588cc5e1b701942cda09b33de5a95c02471f3aaaf610d80aaf5681f4b166e4' # 必须和服务端一致
}
def get_chip_id():
"""
获取RK3588芯片ID增强版
"""
# 方法1: 从多个系统文件读取
for source in CONFIG['CHIP_ID_SOURCES']:
try:
if os.path.exists(source):
with open(source, 'r') as f:
content = f.read().strip()
# 处理cpuinfo的特殊格式
if source == '/proc/cpuinfo':
for line in content.split('\n'):
if 'Serial' in line:
chip_id = line.split(':')[1].strip()
if chip_id:
logger.info(f"{source}获取芯片ID: {chip_id}")
return chip_id
else:
if content:
logger.info(f"{source}获取芯片ID: {content}")
return content
except Exception as e:
logger.warning(f"读取{source}失败: {e}")
# 方法2: 使用dmidecode命令
try:
result = subprocess.run(
['dmidecode', '-s', 'system-serial-number'],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0 and result.stdout.strip():
chip_id = result.stdout.strip()
logger.info(f"从dmidecode获取芯片ID: {chip_id}")
return chip_id
except Exception as e:
logger.warning(f"执行dmidecode失败: {e}")
# 方法3: 读取MAC地址
try:
import uuid
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
chip_id = f"MAC-{mac}"
logger.warning(f"使用MAC地址生成ID: {chip_id}")
return chip_id
except Exception as e:
logger.error(f"无法获取任何标识: {e}")
return None
def verify_key_signature(chip_id, key_data):
"""
验证密钥签名(永久有效)
"""
try:
# 构建待签名数据
data_to_sign = f"{chip_id}|{key_data['activation_id']}|{key_data['activate_time']}"
# 计算期望的签名
expected_signature = hmac.new(
CONFIG['SECRET_KEY'].encode('utf-8'),
data_to_sign.encode('utf-8'),
hashlib.sha256
).hexdigest()
# 比对签名
if key_data['signature'] != expected_signature:
logger.error("密钥签名验证失败")
return False, "密钥签名无效"
logger.info("密钥签名验证通过")
return True, "签名验证通过"
except Exception as e:
logger.error(f"签名验证异常: {e}")
return False, f"验证异常: {str(e)}"
def save_key_file(key_data):
"""
保存密钥文件到本地(永久有效)
"""
try:
# 确保目录存在
key_dir = os.path.dirname(CONFIG['KEY_FILE'])
if key_dir and not os.path.exists(key_dir):
os.makedirs(key_dir, exist_ok=True)
# 如果已有密钥文件,先备份
if os.path.exists(CONFIG['KEY_FILE']):
import shutil
shutil.copy2(CONFIG['KEY_FILE'], CONFIG['KEY_BACKUP_FILE'])
logger.info(f"已备份旧密钥文件到: {CONFIG['KEY_BACKUP_FILE']}")
# 保存新密钥文件
with open(CONFIG['KEY_FILE'], 'w') as f:
json.dump(key_data, f, indent=2)
# 设置文件权限为只读
os.chmod(CONFIG['KEY_FILE'], 0o600)
logger.info(f"密钥文件已保存: {CONFIG['KEY_FILE']}")
return True
except Exception as e:
logger.error(f"保存密钥文件失败: {e}")
return False
def load_key_file():
"""
加载本地密钥文件
"""
try:
# 尝试加载主密钥文件
if os.path.exists(CONFIG['KEY_FILE']):
with open(CONFIG['KEY_FILE'], 'r') as f:
key_data = json.load(f)
logger.info("密钥文件加载成功")
return key_data
# 尝试加载备份密钥文件
if os.path.exists(CONFIG['KEY_BACKUP_FILE']):
logger.warning("主密钥文件不存在,尝试加载备份")
with open(CONFIG['KEY_BACKUP_FILE'], 'r') as f:
key_data = json.load(f)
logger.info("备份密钥文件加载成功")
return key_data
logger.warning("密钥文件不存在")
return None
except Exception as e:
logger.error(f"加载密钥文件失败: {e}")
return None
def verify_local_key(chip_id):
"""
本地验证密钥(永久有效,无过期检查)
"""
# 加载密钥文件
key_data = load_key_file()
if not key_data:
return False, "密钥文件不存在"
# 验证芯片ID是否匹配
if key_data.get('chip_id') != chip_id:
logger.error(f"芯片ID不匹配: 期望 {key_data.get('chip_id')}, 实际 {chip_id}")
return False, "芯片ID不匹配"
# 验证签名
valid, message = verify_key_signature(chip_id, key_data)
if not valid:
return False, message
# 验证通过
logger.info(f"永久激活验证通过!")
logger.info(f"激活时间: {key_data['activate_time']}")
logger.info(f"激活ID: {key_data['activation_id']}")
return True, "验证通过(永久有效)"
def activate_device(chip_id):
"""
联网激活设备(永久激活)
"""
url = f"{CONFIG['SERVER_URL']}{CONFIG['ACTIVATE_URL']}"
payload = {'chip_id': chip_id}
for attempt in range(CONFIG['ACTIVATE_RETRY_COUNT']):
try:
logger.info(f"正在激活设备 (尝试 {attempt + 1}/{CONFIG['ACTIVATE_RETRY_COUNT']})...")
response = requests.post(
url,
json=payload,
timeout=10,
headers={'Content-Type': 'application/json'}
)
if response.status_code == 200:
data = response.json()
if data.get('code') == 200:
# 保存密钥文件
key_data = data['data']
if save_key_file(key_data):
logger.info("设备永久激活成功!")
return True
else:
logger.error("保存密钥文件失败")
else:
logger.error(f"激活失败: {data.get('message')}")
else:
logger.error(f"HTTP错误: {response.status_code}")
except requests.exceptions.RequestException as e:
logger.error(f"网络错误: {e}")
except Exception as e:
logger.error(f"激活过程中发生错误: {e}")
if attempt < CONFIG['ACTIVATE_RETRY_COUNT'] - 1:
wait_time = 2 ** attempt
logger.info(f"等待 {wait_time} 秒后重试...")
time.sleep(wait_time)
return False
def create_emergency_key(chip_id):
"""
创建应急密钥(当无法联网时使用,需人工授权)
警告:此功能仅用于紧急情况
"""
import secrets
logger.warning("正在创建应急密钥...")
# 生成应急密钥数据
emergency_key = {
'chip_id': chip_id,
'activation_id': f"EMERGENCY-{secrets.token_hex(8)}",
'activate_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'signature': 'EMERGENCY-MODE', # 应急模式签名
'permanent': True,
'emergency': True,
'version': '1.0'
}
# 保存应急密钥
if save_key_file(emergency_key):
logger.warning("应急密钥已创建!请确保这是授权操作!")
return True
return False
def main():
"""
主函数:程序启动验证(永久有效)
"""
parser = argparse.ArgumentParser(description='设备永久激活和验证程序')
parser.add_argument('--force-activate', action='store_true', help='强制重新激活')
parser.add_argument('--check-only', action='store_true', help='仅检查验证状态')
parser.add_argument('--emergency', action='store_true', help='创建应急密钥(仅限授权使用)')
parser.add_argument('--show-info', action='store_true', help='显示激活信息')
args = parser.parse_args()
# 获取芯片ID
chip_id = get_chip_id()
if not chip_id:
logger.error("无法获取芯片ID")
sys.exit(1)
logger.info(f"芯片ID: {chip_id}")
# 应急模式
if args.emergency:
if create_emergency_key(chip_id):
logger.info("应急密钥创建成功")
sys.exit(0)
else:
logger.error("应急密钥创建失败")
sys.exit(1)
# 显示激活信息
if args.show_info:
key_data = load_key_file()
if key_data:
print("\n" + "="*50)
print("设备激活信息")
print("="*50)
print(f"芯片ID: {key_data.get('chip_id')}")
print(f"激活时间: {key_data.get('activate_time')}")
print(f"激活ID: {key_data.get('activation_id')}")
print(f"激活类型: {'永久有效' if key_data.get('permanent') else '临时'}")
if key_data.get('emergency'):
print("警告: 应急模式激活")
print("="*50)
else:
print("设备未激活")
sys.exit(0)
# 检查是否需要激活
need_activate = args.force_activate
if not need_activate:
# 尝试本地验证
valid, message = verify_local_key(chip_id)
if valid:
logger.info(f"✅ 验证成功: {message}")
if not args.check_only:
logger.info("验证通过,启动主程序...")
# 在这里调用你的主程序
# subprocess.run(['python3', 'your_main_program.py'])
sys.exit(0)
else:
logger.warning(f"❌ 本地验证失败: {message}")
need_activate = True
# 需要联网激活
if need_activate:
logger.info("开始联网永久激活...")
if activate_device(chip_id):
# 激活后再次验证
valid, message = verify_local_key(chip_id)
if valid:
logger.info(f"✅ 激活验证成功: {message}")
logger.info("设备已永久激活,无需再次联网!")
if not args.check_only:
logger.info("激活完成,启动主程序...")
# subprocess.run(['python3', 'your_main_program.py'])
sys.exit(0)
else:
logger.error(f"❌ 激活后验证失败: {message}")
sys.exit(1)
else:
logger.error("设备激活失败,请检查网络连接")
sys.exit(1)
def install_service():
"""
安装为系统服务
"""
service_content = """[Unit]
Description=Device Permanent Activation Check Service
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /opt/device_activation/client.py --check-only
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
"""
service_file = '/etc/systemd/system/device-activation.service'
try:
# 复制程序到系统目录
script_dir = '/opt/device_activation'
os.makedirs(script_dir, exist_ok=True)
import shutil
shutil.copy2(__file__, os.path.join(script_dir, 'client.py'))
os.chmod(os.path.join(script_dir, 'client.py'), 0o755)
# 创建服务文件
with open(service_file, 'w') as f:
f.write(service_content)
os.chmod(service_file, 0o644)
logger.info(f"服务文件已创建: {service_file}")
logger.info("请执行以下命令启用服务:")
logger.info("sudo systemctl daemon-reload")
logger.info("sudo systemctl enable device-activation.service")
logger.info("sudo systemctl start device-activation.service")
except Exception as e:
logger.error(f"安装服务失败: {e}")
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'install-service':
install_service()
else:
main()