Skip to main content

aster/codesign/
signing.rs

1//! 签名和验证功能
2
3use sha2::{Digest, Sha256, Sha384, Sha512};
4
5use super::keys::get_key;
6use super::types::*;
7
8/// 计算内容哈希
9pub fn hash_content(content: &str, algorithm: HashAlgorithm) -> String {
10    match algorithm {
11        HashAlgorithm::Sha256 => {
12            let mut hasher = Sha256::new();
13            hasher.update(content.as_bytes());
14            hex::encode(hasher.finalize())
15        }
16        HashAlgorithm::Sha384 => {
17            let mut hasher = Sha384::new();
18            hasher.update(content.as_bytes());
19            hex::encode(hasher.finalize())
20        }
21        HashAlgorithm::Sha512 => {
22            let mut hasher = Sha512::new();
23            hasher.update(content.as_bytes());
24            hex::encode(hasher.finalize())
25        }
26    }
27}
28
29/// 使用私钥签名内容
30///
31/// 注意:当前实现使用 HMAC-SHA256 作为简化签名
32/// 如需完整的 Ed25519 签名,需要添加 ring 或 ed25519-dalek 依赖
33pub fn sign_content(content: &str, key: &SigningKey) -> Option<CodeSignature> {
34    let private_key = key.private_key.as_ref()?;
35
36    let hash = hash_content(content, HashAlgorithm::Sha256);
37
38    // 使用 HMAC-like 签名(简化实现)
39    use sha2::{Digest, Sha256};
40    let mut hasher = Sha256::new();
41    hasher.update(hash.as_bytes());
42    hasher.update(private_key.as_bytes());
43    let signature = hex::encode(hasher.finalize());
44
45    Some(CodeSignature {
46        hash,
47        algorithm: HashAlgorithm::Sha256,
48        timestamp: chrono::Utc::now().timestamp_millis(),
49        signed_by: Some(key.id.clone()),
50        signature: Some(signature),
51    })
52}
53
54/// 验证签名
55pub fn verify_signature(content: &str, signature: &CodeSignature) -> bool {
56    let (sig, key) = match (&signature.signature, &signature.signed_by) {
57        (Some(sig), Some(signer)) => {
58            let key = match get_key(signer) {
59                Some(k) => k,
60                None => return false,
61            };
62            (sig.clone(), key)
63        }
64        _ => return false,
65    };
66
67    // 验证哈希
68    let hash = hash_content(content, signature.algorithm);
69    if hash != signature.hash {
70        return false;
71    }
72
73    // 验证签名(HMAC-like)
74    let private_key = match &key.private_key {
75        Some(pk) => pk,
76        None => return false,
77    };
78
79    use sha2::{Digest, Sha256};
80    let mut hasher = Sha256::new();
81    hasher.update(hash.as_bytes());
82    hasher.update(private_key.as_bytes());
83    let expected_sig = hex::encode(hasher.finalize());
84
85    sig == expected_sig
86}
87
88/// 签名文件
89pub fn sign_file(file_path: &str, key_id: Option<&str>) -> Option<SignedFile> {
90    use std::path::Path;
91
92    let absolute_path = Path::new(file_path)
93        .canonicalize()
94        .map(|p| p.to_string_lossy().to_string())
95        .unwrap_or_else(|_| file_path.to_string());
96
97    let content = std::fs::read_to_string(&absolute_path).ok()?;
98
99    // 获取签名密钥
100    let key = if let Some(id) = key_id {
101        get_key(id)
102    } else {
103        super::keys::get_signing_key()
104    };
105
106    let signature = if let Some(k) = key {
107        sign_content(&content, &k)?
108    } else {
109        // 仅哈希签名
110        CodeSignature {
111            hash: hash_content(&content, HashAlgorithm::Sha256),
112            algorithm: HashAlgorithm::Sha256,
113            timestamp: chrono::Utc::now().timestamp_millis(),
114            signed_by: None,
115            signature: None,
116        }
117    };
118
119    // 缓存签名
120    super::storage::cache_signature(&absolute_path, signature.clone());
121    super::storage::save_signatures();
122
123    Some(SignedFile {
124        path: absolute_path,
125        content,
126        signature,
127    })
128}
129
130/// 验证文件签名
131pub fn verify_file(file_path: &str) -> VerifyResult {
132    use std::path::Path;
133
134    let absolute_path = Path::new(file_path)
135        .canonicalize()
136        .map(|p| p.to_string_lossy().to_string())
137        .unwrap_or_else(|_| file_path.to_string());
138
139    let content = match std::fs::read_to_string(&absolute_path) {
140        Ok(c) => c,
141        Err(_) => return VerifyResult::err("File not found"),
142    };
143
144    // 获取签名
145    let signature = match super::storage::get_cached_signature(&absolute_path) {
146        Some(s) => s,
147        None => return VerifyResult::err("No signature found"),
148    };
149
150    // 验证哈希
151    let current_hash = hash_content(&content, signature.algorithm);
152    if current_hash != signature.hash {
153        return VerifyResult::err_with_sig("File has been modified", signature);
154    }
155
156    // 验证加密签名
157    if signature.signature.is_some() && !verify_signature(&content, &signature) {
158        return VerifyResult::err_with_sig("Cryptographic signature invalid", signature);
159    }
160
161    VerifyResult::ok(signature)
162}