#!/system/bin/sh
# KernelSU模块签名和安全工具
# 用于模块签名、验证和安全管理

# 导入通用函数库
. /usr/lib/common-functions.sh

# 签名配置
readonly SIGN_KEY_DIR="/data/adb/module_keys"
readonly CERT_DIR="/data/adb/certificates"
readonly TRUSTED_KEYS_DIR="/data/adb/trusted_keys"

# 显示帮助信息
show_help() {
    cat << 'EOF'
KernelSU模块签名和安全工具

用法:
    module-security [选项] [操作] [参数...]

选项:
    -h, --help          显示帮助信息
    -v, --version       显示版本信息
    -q, --quiet         安静模式
    -d, --debug         调试模式
    --key-size SIZE     RSA密钥大小 (默认: 2048)
    --hash-algo ALGO    哈希算法 (默认: sha256)
    --cert-days DAYS    证书有效期天数 (默认: 365)

操作:
    generate-key NAME   生成签名密钥对
    sign MODULE_PATH    签名模块包
    verify MODULE_PATH  验证模块签名
    list-keys           列出所有密钥
    list-certs          列出所有证书
    trust-key KEY_FILE  添加信任的密钥
    revoke-key KEY_ID   撤销密钥
    create-cert KEY     创建证书
    check-integrity     检查系统完整性
    scan-modules        扫描所有模块安全状态

示例:
    module-security generate-key developer
    module-security sign /path/to/module.zip
    module-security verify /path/to/module.zip
    module-security trust-key /path/to/public.key
    module-security scan-modules

EOF
}

# 显示版本信息
show_version() {
    echo "KernelSU模块签名和安全工具 v1.0.0"
    echo "Copyright (C) 2024 RootManage-Module-Model Project"
}

# 检查依赖工具
check_dependencies() {
    local missing_deps=""
    
    # 检查OpenSSL
    if ! command -v openssl >/dev/null 2>&1; then
        missing_deps="$missing_deps openssl"
    fi
    
    # 检查其他必需工具
    for tool in sha256sum base64 xxd; do
        if ! command -v "$tool" >/dev/null 2>&1; then
            missing_deps="$missing_deps $tool"
        fi
    done
    
    if [ -n "$missing_deps" ]; then
        log_error "缺少依赖工具: $missing_deps"
        return 1
    fi
    
    return 0
}

# 初始化安全环境
init_security_env() {
    log_debug "初始化安全环境..."
    
    # 创建必要目录
    for dir in "$SIGN_KEY_DIR" "$CERT_DIR" "$TRUSTED_KEYS_DIR"; do
        if [ ! -d "$dir" ]; then
            mkdir -p "$dir"
            chmod 700 "$dir"
            log_debug "创建目录: $dir"
        fi
    done
    
    return 0
}

# 生成密钥对
generate_key_pair() {
    local key_name="$1"
    local key_size="${2:-2048}"
    
    if [ -z "$key_name" ]; then
        log_error "请指定密钥名称"
        return 1
    fi
    
    local private_key="$SIGN_KEY_DIR/$key_name.private.pem"
    local public_key="$SIGN_KEY_DIR/$key_name.public.pem"
    
    # 检查密钥是否已存在
    if [ -f "$private_key" ] || [ -f "$public_key" ]; then
        log_error "密钥已存在: $key_name"
        return 1
    fi
    
    log_info "生成密钥对: $key_name (RSA $key_size 位)"
    
    # 生成私钥
    if ! openssl genrsa -out "$private_key" "$key_size" 2>/dev/null; then
        log_error "生成私钥失败"
        return 1
    fi
    
    # 生成公钥
    if ! openssl rsa -in "$private_key" -pubout -out "$public_key" 2>/dev/null; then
        log_error "生成公钥失败"
        rm -f "$private_key"
        return 1
    fi
    
    # 设置权限
    chmod 600 "$private_key"
    chmod 644 "$public_key"
    
    # 生成密钥指纹
    local fingerprint=$(openssl rsa -in "$public_key" -pubin -outform DER 2>/dev/null | sha256sum | cut -d' ' -f1)
    
    # 保存密钥信息
    cat > "$SIGN_KEY_DIR/$key_name.info" << EOF
name=$key_name
type=RSA
size=$key_size
created=$(date -u +%Y-%m-%dT%H:%M:%SZ)
fingerprint=$fingerprint
EOF
    
    log_info "密钥对生成完成:"
    log_info "  私钥: $private_key"
    log_info "  公钥: $public_key"
    log_info "  指纹: $fingerprint"
    
    return 0
}

# 签名模块
sign_module() {
    local module_path="$1"
    local key_name="$2"
    local hash_algo="${3:-sha256}"
    
    if [ ! -f "$module_path" ]; then
        log_error "模块文件不存在: $module_path"
        return 1
    fi
    
    # 如果未指定密钥，尝试使用默认密钥
    if [ -z "$key_name" ]; then
        key_name="default"
        if [ ! -f "$SIGN_KEY_DIR/$key_name.private.pem" ]; then
            log_warn "默认密钥不存在，正在生成..."
            if ! generate_key_pair "$key_name"; then
                return 1
            fi
        fi
    fi
    
    local private_key="$SIGN_KEY_DIR/$key_name.private.pem"
    if [ ! -f "$private_key" ]; then
        log_error "私钥不存在: $key_name"
        return 1
    fi
    
    log_info "签名模块: $module_path"
    
    # 计算模块哈希
    local module_hash
    case "$hash_algo" in
        sha256)
            module_hash=$(sha256sum "$module_path" | cut -d' ' -f1)
            ;;
        sha1)
            module_hash=$(sha1sum "$module_path" | cut -d' ' -f1)
            ;;
        md5)
            module_hash=$(md5sum "$module_path" | cut -d' ' -f1)
            ;;
        *)
            log_error "不支持的哈希算法: $hash_algo"
            return 1
            ;;
    esac
    
    # 创建签名数据
    local sign_data_file="/tmp/sign_data_$$"
    cat > "$sign_data_file" << EOF
module=$(basename "$module_path")
hash_algo=$hash_algo
hash=$module_hash
signed_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
key_name=$key_name
EOF
    
    # 生成签名
    local signature_file="${module_path}.sig"
    if ! openssl dgst -"$hash_algo" -sign "$private_key" -out "$signature_file.raw" "$sign_data_file" 2>/dev/null; then
        log_error "生成签名失败"
        rm -f "$sign_data_file"
        return 1
    fi
    
    # 创建可读的签名文件
    {
        echo "# KernelSU模块签名文件"
        echo "# Module signature file"
        echo ""
        cat "$sign_data_file"
        echo ""
        echo "signature=$(base64 -w 0 < "$signature_file.raw")"
    } > "$signature_file"
    
    # 清理临时文件
    rm -f "$sign_data_file" "$signature_file.raw"
    
    log_info "模块签名完成:"
    log_info "  模块: $module_path"
    log_info "  签名: $signature_file"
    log_info "  哈希: $module_hash"
    
    return 0
}

# 验证模块签名
verify_module() {
    local module_path="$1"
    local signature_file="${module_path}.sig"
    
    if [ ! -f "$module_path" ]; then
        log_error "模块文件不存在: $module_path"
        return 1
    fi
    
    if [ ! -f "$signature_file" ]; then
        log_error "签名文件不存在: $signature_file"
        return 1
    fi
    
    log_info "验证模块签名: $module_path"
    
    # 解析签名文件
    local key_name=$(grep "^key_name=" "$signature_file" | cut -d'=' -f2)
    local hash_algo=$(grep "^hash_algo=" "$signature_file" | cut -d'=' -f2)
    local expected_hash=$(grep "^hash=" "$signature_file" | cut -d'=' -f2)
    local signature_b64=$(grep "^signature=" "$signature_file" | cut -d'=' -f2)
    
    if [ -z "$key_name" ] || [ -z "$hash_algo" ] || [ -z "$expected_hash" ] || [ -z "$signature_b64" ]; then
        log_error "签名文件格式错误"
        return 1
    fi
    
    # 检查公钥
    local public_key="$SIGN_KEY_DIR/$key_name.public.pem"
    if [ ! -f "$public_key" ]; then
        # 尝试在信任密钥中查找
        public_key="$TRUSTED_KEYS_DIR/$key_name.public.pem"
        if [ ! -f "$public_key" ]; then
            log_error "找不到公钥: $key_name"
            return 1
        fi
    fi
    
    # 验证模块哈希
    local actual_hash
    case "$hash_algo" in
        sha256)
            actual_hash=$(sha256sum "$module_path" | cut -d' ' -f1)
            ;;
        sha1)
            actual_hash=$(sha1sum "$module_path" | cut -d' ' -f1)
            ;;
        md5)
            actual_hash=$(md5sum "$module_path" | cut -d' ' -f1)
            ;;
        *)
            log_error "不支持的哈希算法: $hash_algo"
            return 1
            ;;
    esac
    
    if [ "$actual_hash" != "$expected_hash" ]; then
        log_error "模块哈希验证失败"
        log_error "  期望: $expected_hash"
        log_error "  实际: $actual_hash"
        return 1
    fi
    
    # 重建签名数据
    local verify_data_file="/tmp/verify_data_$$"
    grep -E "^(module|hash_algo|hash|signed_at|key_name)=" "$signature_file" > "$verify_data_file"
    
    # 解码签名
    local signature_file_raw="/tmp/signature_$$"
    echo "$signature_b64" | base64 -d > "$signature_file_raw"
    
    # 验证签名
    if openssl dgst -"$hash_algo" -verify "$public_key" -signature "$signature_file_raw" "$verify_data_file" >/dev/null 2>&1; then
        log_info "模块签名验证成功"
        log_info "  签名者: $key_name"
        log_info "  哈希算法: $hash_algo"
        log_info "  签名时间: $(grep "^signed_at=" "$signature_file" | cut -d'=' -f2)"
        
        # 清理临时文件
        rm -f "$verify_data_file" "$signature_file_raw"
        return 0
    else
        log_error "模块签名验证失败"
        
        # 清理临时文件
        rm -f "$verify_data_file" "$signature_file_raw"
        return 1
    fi
}

# 列出密钥
list_keys() {
    log_info "已生成的密钥:"
    
    if [ ! -d "$SIGN_KEY_DIR" ] || [ -z "$(ls -A "$SIGN_KEY_DIR" 2>/dev/null)" ]; then
        log_info "  无密钥"
        return 0
    fi
    
    printf "%-20s %-8s %-8s %-20s %s\n" "名称" "类型" "大小" "创建时间" "指纹"
    echo "--------------------------------------------------------------------------------"
    
    for info_file in "$SIGN_KEY_DIR"/*.info; do
        if [ -f "$info_file" ]; then
            local name=$(grep "^name=" "$info_file" | cut -d'=' -f2)
            local type=$(grep "^type=" "$info_file" | cut -d'=' -f2)
            local size=$(grep "^size=" "$info_file" | cut -d'=' -f2)
            local created=$(grep "^created=" "$info_file" | cut -d'=' -f2)
            local fingerprint=$(grep "^fingerprint=" "$info_file" | cut -d'=' -f2)
            
            printf "%-20s %-8s %-8s %-20s %s\n" \
                "$name" "$type" "$size" "${created:-未知}" "${fingerprint:0:16}..."
        fi
    done
}

# 信任密钥
trust_key() {
    local key_file="$1"
    local key_name="$2"
    
    if [ ! -f "$key_file" ]; then
        log_error "密钥文件不存在: $key_file"
        return 1
    fi
    
    # 如果未指定名称，从文件名推导
    if [ -z "$key_name" ]; then
        key_name=$(basename "$key_file" .pem)
        key_name=$(basename "$key_name" .pub)
        key_name=$(basename "$key_name" .public)
    fi
    
    local trusted_key="$TRUSTED_KEYS_DIR/$key_name.public.pem"
    
    # 验证密钥格式
    if ! openssl rsa -in "$key_file" -pubin -noout 2>/dev/null; then
        log_error "无效的公钥格式"
        return 1
    fi
    
    # 复制密钥
    cp "$key_file" "$trusted_key"
    chmod 644 "$trusted_key"
    
    # 生成指纹
    local fingerprint=$(openssl rsa -in "$trusted_key" -pubin -outform DER 2>/dev/null | sha256sum | cut -d' ' -f1)
    
    # 保存信任信息
    cat > "$TRUSTED_KEYS_DIR/$key_name.info" << EOF
name=$key_name
type=RSA
trusted_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
fingerprint=$fingerprint
source=$key_file
EOF
    
    log_info "密钥已添加到信任列表:"
    log_info "  名称: $key_name"
    log_info "  指纹: $fingerprint"
    
    return 0
}

# 扫描模块安全状态
scan_modules() {
    local modules_dir="/data/adb/modules"
    local total_count=0
    local signed_count=0
    local unsigned_count=0
    local invalid_count=0
    
    if [ ! -d "$modules_dir" ]; then
        log_info "模块目录不存在"
        return 0
    fi
    
    log_info "扫描模块安全状态..."
    printf "%-20s %-15s %-15s %s\n" "模块ID" "签名状态" "版本" "路径"
    echo "--------------------------------------------------------------------------------"
    
    for module_dir in "$modules_dir"/*; do
        if [ -d "$module_dir" ]; then
            local module_id=$(basename "$module_dir")
            local module_prop="$module_dir/module.prop"
            local module_zip="$module_dir.zip"
            local version="未知"
            local status="未签名"
            
            total_count=$((total_count + 1))
            
            # 获取版本信息
            if [ -f "$module_prop" ]; then
                version=$(grep "^version=" "$module_prop" | cut -d'=' -f2)
            fi
            
            # 检查签名状态
            if [ -f "$module_zip" ]; then
                if [ -f "$module_zip.sig" ]; then
                    if verify_module "$module_zip" >/dev/null 2>&1; then
                        status="已签名"
                        signed_count=$((signed_count + 1))
                    else
                        status="签名无效"
                        invalid_count=$((invalid_count + 1))
                    fi
                else
                    unsigned_count=$((unsigned_count + 1))
                fi
            else
                unsigned_count=$((unsigned_count + 1))
            fi
            
            printf "%-20s %-15s %-15s %s\n" \
                "$module_id" "$status" "$version" "$module_dir"
        fi
    done
    
    echo ""
    log_info "扫描结果统计:"
    log_info "  总数量: $total_count"
    log_info "  已签名: $signed_count"
    log_info "  未签名: $unsigned_count"
    log_info "  签名无效: $invalid_count"
    
    return 0
}

# 主函数
main() {
    local operation=""
    local key_size=2048
    local hash_algo="sha256"
    local cert_days=365
    
    # 解析参数
    while [ $# -gt 0 ]; do
        case "$1" in
            -h|--help)
                show_help
                exit 0
                ;;
            -v|--version)
                show_version
                exit 0
                ;;
            -q|--quiet)
                QUIET=true
                ;;
            -d|--debug)
                DEBUG=true
                ;;
            --key-size)
                key_size="$2"
                shift
                ;;
            --hash-algo)
                hash_algo="$2"
                shift
                ;;
            --cert-days)
                cert_days="$2"
                shift
                ;;
            generate-key|sign|verify|list-keys|list-certs|trust-key|revoke-key|create-cert|check-integrity|scan-modules)
                operation="$1"
                shift
                break
                ;;
            *)
                log_error "无效的选项: $1"
                exit 1
                ;;
        esac
        shift
    done
    
    # 检查依赖
    if ! check_dependencies; then
        exit 1
    fi
    
    # 初始化环境
    if ! init_security_env; then
        exit 1
    fi
    
    # 执行操作
    case "$operation" in
        generate-key)
            generate_key_pair "$1" "$key_size"
            ;;
        sign)
            sign_module "$1" "$2" "$hash_algo"
            ;;
        verify)
            verify_module "$1"
            ;;
        list-keys)
            list_keys
            ;;
        trust-key)
            trust_key "$1" "$2"
            ;;
        scan-modules)
            scan_modules
            ;;
        "")
            log_error "请指定操作"
            show_help
            exit 1
            ;;
        *)
            log_error "无效的操作: $operation"
            exit 1
            ;;
    esac
}

# 检查参数并运行主函数
if [ $# -eq 0 ]; then
    show_help
    exit 0
fi

main "$@"
