1use std::collections::HashMap;
9use std::fs;
10use std::path::Path;
11
12use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
13use ring::aead;
14use serde::{Deserialize, Serialize};
15use sha2::{Digest, Sha256};
16use torsh_core::error::{Result, TorshError};
17
18use crate::package::Package;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct PackageSignature {
23 pub algorithm: SignatureAlgorithm,
25 pub signature: Vec<u8>,
27 pub public_key: Vec<u8>,
29 pub timestamp: chrono::DateTime<chrono::Utc>,
31 pub metadata: HashMap<String, String>,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub enum SignatureAlgorithm {
38 Ed25519,
40 Rsa,
42 Ecdsa,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
48pub enum EncryptionAlgorithm {
49 Aes256Gcm,
51 ChaCha20Poly1305,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct EncryptedPackage {
58 pub algorithm: EncryptionAlgorithm,
60 pub encrypted_data: Vec<u8>,
62 pub nonce: Vec<u8>,
64 pub aad: Option<Vec<u8>>,
66 pub key_metadata: HashMap<String, String>,
68 pub timestamp: chrono::DateTime<chrono::Utc>,
70}
71
72pub struct PackageSigner {
74 signing_key: Option<SigningKey>,
75 verifying_keys: Vec<VerifyingKey>,
76 algorithm: SignatureAlgorithm,
77}
78
79pub struct PackageEncryptor {
81 algorithm: EncryptionAlgorithm,
82}
83
84#[derive(Debug, thiserror::Error)]
86pub enum SecurityError {
87 #[error("Signature verification failed: {0}")]
89 InvalidSignature(String),
90 #[error("Encryption error: {0}")]
92 EncryptionError(String),
93 #[error("Key error: {0}")]
95 KeyError(String),
96}
97
98impl PackageSigner {
99 pub fn new() -> Self {
101 use ring::rand::{SecureRandom, SystemRandom};
103 let rng = SystemRandom::new();
104 let mut secret_bytes = [0u8; 32];
105 rng.fill(&mut secret_bytes)
106 .expect("Failed to generate random key");
107
108 let signing_key = SigningKey::from_bytes(&secret_bytes);
109
110 Self {
111 signing_key: Some(signing_key),
112 verifying_keys: Vec::new(),
113 algorithm: SignatureAlgorithm::Ed25519,
114 }
115 }
116
117 pub fn from_signing_key(signing_key: SigningKey) -> Self {
119 Self {
120 signing_key: Some(signing_key),
121 verifying_keys: Vec::new(),
122 algorithm: SignatureAlgorithm::Ed25519,
123 }
124 }
125
126 pub fn verifier_only() -> Self {
128 Self {
129 signing_key: None,
130 verifying_keys: Vec::new(),
131 algorithm: SignatureAlgorithm::Ed25519,
132 }
133 }
134
135 pub fn add_trusted_key(&mut self, public_key: &[u8]) -> Result<()> {
137 let verifying_key =
138 VerifyingKey::from_bytes(public_key.try_into().map_err(|_| {
139 TorshError::InvalidArgument("Invalid public key length".to_string())
140 })?)
141 .map_err(|e| TorshError::InvalidArgument(format!("Invalid public key: {}", e)))?;
142
143 self.verifying_keys.push(verifying_key);
144 Ok(())
145 }
146
147 pub fn public_key(&self) -> Option<Vec<u8>> {
149 self.signing_key
150 .as_ref()
151 .map(|sk| sk.verifying_key().to_bytes().to_vec())
152 }
153
154 pub fn export_signing_key(&self) -> Option<Vec<u8>> {
156 self.signing_key.as_ref().map(|sk| sk.to_bytes().to_vec())
157 }
158
159 pub fn sign_package(&self, package: &Package) -> Result<PackageSignature> {
161 let signing_key = self
162 .signing_key
163 .as_ref()
164 .ok_or_else(|| TorshError::InvalidArgument("No signing key available".to_string()))?;
165
166 let package_data = self.package_digest(package)?;
168
169 let signature = signing_key.sign(&package_data);
171
172 let mut metadata = HashMap::new();
173 metadata.insert("package_name".to_string(), package.name().to_string());
174 metadata.insert(
175 "package_version".to_string(),
176 package.get_version().to_string(),
177 );
178
179 Ok(PackageSignature {
180 algorithm: self.algorithm,
181 signature: signature.to_bytes().to_vec(),
182 public_key: signing_key.verifying_key().to_bytes().to_vec(),
183 timestamp: chrono::Utc::now(),
184 metadata,
185 })
186 }
187
188 pub fn verify_package(&self, package: &Package, signature: &PackageSignature) -> Result<bool> {
190 if signature.algorithm != self.algorithm {
191 return Err(TorshError::InvalidArgument(format!(
192 "Unsupported signature algorithm: {:?}",
193 signature.algorithm
194 )));
195 }
196
197 let verifying_key =
199 VerifyingKey::from_bytes(signature.public_key.as_slice().try_into().map_err(|_| {
200 TorshError::InvalidArgument("Invalid public key length".to_string())
201 })?)
202 .map_err(|e| TorshError::InvalidArgument(format!("Invalid public key: {}", e)))?;
203
204 if !self.verifying_keys.is_empty()
206 && !self
207 .verifying_keys
208 .iter()
209 .any(|k| k.to_bytes() == verifying_key.to_bytes())
210 {
211 return Ok(false);
212 }
213
214 let package_data = self.package_digest(package)?;
216
217 let sig =
219 Signature::from_bytes(signature.signature.as_slice().try_into().map_err(|_| {
220 TorshError::InvalidArgument("Invalid signature length".to_string())
221 })?);
222
223 match verifying_key.verify(&package_data, &sig) {
225 Ok(()) => Ok(true),
226 Err(_) => Ok(false),
227 }
228 }
229
230 fn package_digest(&self, package: &Package) -> Result<Vec<u8>> {
232 let mut hasher = Sha256::new();
234
235 hasher.update(package.name().as_bytes());
237 hasher.update(package.get_version().as_bytes());
238
239 let mut resource_names: Vec<_> = package.resources().keys().collect();
241 resource_names.sort();
242
243 for name in resource_names {
244 if let Some(resource) = package.resources().get(name) {
245 hasher.update(name.as_bytes());
246 hasher.update(&resource.data);
247 }
248 }
249
250 Ok(hasher.finalize().to_vec())
251 }
252
253 pub fn save_signature<P: AsRef<Path>>(signature: &PackageSignature, path: P) -> Result<()> {
255 let serialized = oxicode::serde::encode_to_vec(signature, oxicode::config::standard())
256 .map_err(|e| TorshError::SerializationError(e.to_string()))?;
257
258 fs::write(path, serialized).map_err(|e| TorshError::IoError(e.to_string()))?;
259 Ok(())
260 }
261
262 pub fn load_signature<P: AsRef<Path>>(path: P) -> Result<PackageSignature> {
264 let data = fs::read(path).map_err(|e| TorshError::IoError(e.to_string()))?;
265
266 let (signature, _) = oxicode::serde::decode_from_slice(&data, oxicode::config::standard())
267 .map_err(|e| TorshError::SerializationError(e.to_string()))?;
268
269 Ok(signature)
270 }
271}
272
273impl Default for PackageSigner {
274 fn default() -> Self {
275 Self::new()
276 }
277}
278
279impl PackageEncryptor {
280 pub fn new(algorithm: EncryptionAlgorithm) -> Self {
282 Self { algorithm }
283 }
284
285 pub fn encrypt_package_with_password(
287 &self,
288 package: &Package,
289 password: &str,
290 ) -> Result<EncryptedPackage> {
291 let package_data = oxicode::serde::encode_to_vec(package, oxicode::config::standard())
293 .map_err(|e| TorshError::SerializationError(e.to_string()))?;
294
295 let salt = self.generate_salt();
297 let key = self.derive_key_from_password(password, &salt)?;
298
299 let (encrypted_data, nonce) = self.encrypt_data(&package_data, &key)?;
301
302 let mut key_metadata = HashMap::new();
303 key_metadata.insert("kdf".to_string(), "pbkdf2".to_string());
304 key_metadata.insert("salt".to_string(), hex::encode(&salt));
305 key_metadata.insert("iterations".to_string(), "100000".to_string());
306
307 Ok(EncryptedPackage {
308 algorithm: self.algorithm,
309 encrypted_data,
310 nonce,
311 aad: None,
312 key_metadata,
313 timestamp: chrono::Utc::now(),
314 })
315 }
316
317 pub fn decrypt_package_with_password(
319 &self,
320 encrypted: &EncryptedPackage,
321 password: &str,
322 ) -> Result<Package> {
323 let salt_hex = encrypted
325 .key_metadata
326 .get("salt")
327 .ok_or_else(|| TorshError::InvalidArgument("Missing salt in metadata".to_string()))?;
328
329 let salt = hex::decode(salt_hex)
330 .map_err(|e| TorshError::InvalidArgument(format!("Invalid salt: {}", e)))?;
331
332 let key = self.derive_key_from_password(password, &salt)?;
334
335 let decrypted_data =
337 self.decrypt_data(&encrypted.encrypted_data, &encrypted.nonce, &key)?;
338
339 let (package, _) =
341 oxicode::serde::decode_from_slice(&decrypted_data, oxicode::config::standard())
342 .map_err(|e| TorshError::SerializationError(e.to_string()))?;
343
344 Ok(package)
345 }
346
347 fn encrypt_data(&self, data: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
349 match self.algorithm {
350 EncryptionAlgorithm::Aes256Gcm => self.encrypt_aes_gcm(data, key),
351 EncryptionAlgorithm::ChaCha20Poly1305 => self.encrypt_chacha20(data, key),
352 }
353 }
354
355 fn decrypt_data(&self, encrypted: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec<u8>> {
357 match self.algorithm {
358 EncryptionAlgorithm::Aes256Gcm => self.decrypt_aes_gcm(encrypted, nonce, key),
359 EncryptionAlgorithm::ChaCha20Poly1305 => self.decrypt_chacha20(encrypted, nonce, key),
360 }
361 }
362
363 fn encrypt_aes_gcm(&self, data: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
365 let unbound_key = aead::UnboundKey::new(&aead::AES_256_GCM, key)
366 .map_err(|_| TorshError::InvalidArgument("Invalid key for AES-256-GCM".to_string()))?;
367
368 let nonce_bytes = self.generate_nonce(aead::NONCE_LEN);
369 let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_bytes)
370 .map_err(|_| TorshError::InvalidArgument("Invalid nonce".to_string()))?;
371
372 let sealing_key = aead::LessSafeKey::new(unbound_key);
373
374 let mut in_out = data.to_vec();
375 sealing_key
376 .seal_in_place_append_tag(nonce, aead::Aad::empty(), &mut in_out)
377 .map_err(|_| TorshError::InvalidArgument("Encryption failed".to_string()))?;
378
379 Ok((in_out, nonce_bytes))
380 }
381
382 fn decrypt_aes_gcm(&self, encrypted: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec<u8>> {
384 let unbound_key = aead::UnboundKey::new(&aead::AES_256_GCM, key)
385 .map_err(|_| TorshError::InvalidArgument("Invalid key for AES-256-GCM".to_string()))?;
386
387 let nonce = aead::Nonce::try_assume_unique_for_key(nonce)
388 .map_err(|_| TorshError::InvalidArgument("Invalid nonce".to_string()))?;
389
390 let opening_key = aead::LessSafeKey::new(unbound_key);
391
392 let mut in_out = encrypted.to_vec();
393 let decrypted = opening_key
394 .open_in_place(nonce, aead::Aad::empty(), &mut in_out)
395 .map_err(|_| TorshError::InvalidArgument("Decryption failed".to_string()))?;
396
397 Ok(decrypted.to_vec())
398 }
399
400 fn encrypt_chacha20(&self, data: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
402 let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, key).map_err(|_| {
403 TorshError::InvalidArgument("Invalid key for ChaCha20-Poly1305".to_string())
404 })?;
405
406 let nonce_bytes = self.generate_nonce(aead::NONCE_LEN);
407 let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_bytes)
408 .map_err(|_| TorshError::InvalidArgument("Invalid nonce".to_string()))?;
409
410 let sealing_key = aead::LessSafeKey::new(unbound_key);
411
412 let mut in_out = data.to_vec();
413 sealing_key
414 .seal_in_place_append_tag(nonce, aead::Aad::empty(), &mut in_out)
415 .map_err(|_| TorshError::InvalidArgument("Encryption failed".to_string()))?;
416
417 Ok((in_out, nonce_bytes))
418 }
419
420 fn decrypt_chacha20(&self, encrypted: &[u8], nonce: &[u8], key: &[u8]) -> Result<Vec<u8>> {
422 let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, key).map_err(|_| {
423 TorshError::InvalidArgument("Invalid key for ChaCha20-Poly1305".to_string())
424 })?;
425
426 let nonce = aead::Nonce::try_assume_unique_for_key(nonce)
427 .map_err(|_| TorshError::InvalidArgument("Invalid nonce".to_string()))?;
428
429 let opening_key = aead::LessSafeKey::new(unbound_key);
430
431 let mut in_out = encrypted.to_vec();
432 let decrypted = opening_key
433 .open_in_place(nonce, aead::Aad::empty(), &mut in_out)
434 .map_err(|_| TorshError::InvalidArgument("Decryption failed".to_string()))?;
435
436 Ok(decrypted.to_vec())
437 }
438
439 fn derive_key_from_password(&self, password: &str, salt: &[u8]) -> Result<Vec<u8>> {
441 use ring::pbkdf2;
442
443 let iterations =
444 std::num::NonZeroU32::new(100_000).expect("100_000 is a valid non-zero u32");
445 let mut key = vec![0u8; 32]; pbkdf2::derive(
448 pbkdf2::PBKDF2_HMAC_SHA256,
449 iterations,
450 salt,
451 password.as_bytes(),
452 &mut key,
453 );
454
455 Ok(key)
456 }
457
458 fn generate_salt(&self) -> Vec<u8> {
460 use ring::rand::{SecureRandom, SystemRandom};
461
462 let rng = SystemRandom::new();
463 let mut salt = vec![0u8; 32];
464 rng.fill(&mut salt).expect("Failed to generate salt");
465 salt
466 }
467
468 fn generate_nonce(&self, len: usize) -> Vec<u8> {
470 use ring::rand::{SecureRandom, SystemRandom};
471
472 let rng = SystemRandom::new();
473 let mut nonce = vec![0u8; len];
474 rng.fill(&mut nonce).expect("Failed to generate nonce");
475 nonce
476 }
477
478 pub fn save_encrypted<P: AsRef<Path>>(encrypted: &EncryptedPackage, path: P) -> Result<()> {
480 let serialized = oxicode::serde::encode_to_vec(encrypted, oxicode::config::standard())
481 .map_err(|e| TorshError::SerializationError(e.to_string()))?;
482
483 fs::write(path, serialized).map_err(|e| TorshError::IoError(e.to_string()))?;
484 Ok(())
485 }
486
487 pub fn load_encrypted<P: AsRef<Path>>(path: P) -> Result<EncryptedPackage> {
489 let data = fs::read(path).map_err(|e| TorshError::IoError(e.to_string()))?;
490
491 let (encrypted, _) = oxicode::serde::decode_from_slice(&data, oxicode::config::standard())
492 .map_err(|e| TorshError::SerializationError(e.to_string()))?;
493
494 Ok(encrypted)
495 }
496}
497
498#[cfg(test)]
499mod tests {
500 use super::*;
501
502 #[test]
503 fn test_package_signer_creation() {
504 let signer = PackageSigner::new();
505 assert!(signer.public_key().is_some());
506 assert!(signer.export_signing_key().is_some());
507 }
508
509 #[test]
510 fn test_sign_and_verify_package() {
511 let signer = PackageSigner::new();
512 let package = Package::new("test".to_string(), "1.0.0".to_string());
513
514 let signature = signer.sign_package(&package).unwrap();
515 assert_eq!(signature.algorithm, SignatureAlgorithm::Ed25519);
516
517 let is_valid = signer.verify_package(&package, &signature).unwrap();
518 assert!(is_valid);
519 }
520
521 #[test]
522 fn test_signature_fails_on_modified_package() {
523 let signer = PackageSigner::new();
524 let mut package = Package::new("test".to_string(), "1.0.0".to_string());
525
526 let signature = signer.sign_package(&package).unwrap();
527
528 package.add_source_file("new", "new content").unwrap();
530
531 let is_valid = signer.verify_package(&package, &signature).unwrap();
532 assert!(!is_valid);
533 }
534
535 #[test]
536 fn test_encrypt_decrypt_package() {
537 let encryptor = PackageEncryptor::new(EncryptionAlgorithm::Aes256Gcm);
538 let package = Package::new("secret".to_string(), "1.0.0".to_string());
539 let password = "super_secret_password";
540
541 let encrypted = encryptor
542 .encrypt_package_with_password(&package, password)
543 .unwrap();
544 assert_eq!(encrypted.algorithm, EncryptionAlgorithm::Aes256Gcm);
545
546 let decrypted = encryptor
547 .decrypt_package_with_password(&encrypted, password)
548 .unwrap();
549 assert_eq!(decrypted.name(), package.name());
550 assert_eq!(decrypted.get_version(), package.get_version());
551 }
552
553 #[test]
554 fn test_decrypt_with_wrong_password_fails() {
555 let encryptor = PackageEncryptor::new(EncryptionAlgorithm::Aes256Gcm);
556 let package = Package::new("secret".to_string(), "1.0.0".to_string());
557
558 let encrypted = encryptor
559 .encrypt_package_with_password(&package, "correct_password")
560 .unwrap();
561
562 let result = encryptor.decrypt_package_with_password(&encrypted, "wrong_password");
563 assert!(result.is_err());
564 }
565
566 #[test]
567 fn test_chacha20_encryption() {
568 let encryptor = PackageEncryptor::new(EncryptionAlgorithm::ChaCha20Poly1305);
569 let package = Package::new("test".to_string(), "1.0.0".to_string());
570 let password = "test_password";
571
572 let encrypted = encryptor
573 .encrypt_package_with_password(&package, password)
574 .unwrap();
575 assert_eq!(encrypted.algorithm, EncryptionAlgorithm::ChaCha20Poly1305);
576
577 let decrypted = encryptor
578 .decrypt_package_with_password(&encrypted, password)
579 .unwrap();
580 assert_eq!(decrypted.name(), package.name());
581 }
582
583 #[test]
584 fn test_trusted_key_verification() {
585 let signer = PackageSigner::new();
586 let mut verifier = PackageSigner::verifier_only();
587
588 verifier
590 .add_trusted_key(&signer.public_key().unwrap())
591 .unwrap();
592
593 let package = Package::new("test".to_string(), "1.0.0".to_string());
594 let signature = signer.sign_package(&package).unwrap();
595
596 let is_valid = verifier.verify_package(&package, &signature).unwrap();
597 assert!(is_valid);
598 }
599
600 #[test]
601 fn test_untrusted_key_verification_fails() {
602 let signer = PackageSigner::new();
603 let mut verifier = PackageSigner::verifier_only();
604
605 let other_signer = PackageSigner::new();
607 verifier
608 .add_trusted_key(&other_signer.public_key().unwrap())
609 .unwrap();
610
611 let package = Package::new("test".to_string(), "1.0.0".to_string());
612 let signature = signer.sign_package(&package).unwrap();
613
614 let is_valid = verifier.verify_package(&package, &signature).unwrap();
615 assert!(!is_valid);
616 }
617}