cloud_disk_sync/encryption/
types.rs

1use rand::RngCore;
2use rand::rngs::OsRng;
3// src/encryption/types.rs
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7pub enum EncryptionAlgorithm {
8    /// AES-GCM with 256-bit key
9    Aes256Gcm,
10    /// AES-CBC with 256-bit key
11    Aes256Cbc,
12    /// ChaCha20-Poly1305
13    ChaCha20Poly1305,
14    /// XChaCha20-Poly1305
15    XChaCha20Poly1305,
16    /// AES-GCM-SIV
17    Aes256GcmSiv,
18}
19
20impl EncryptionAlgorithm {
21    pub fn key_size(&self) -> usize {
22        match self {
23            Self::Aes256Gcm => 32,
24            Self::Aes256Cbc => 32,
25            Self::ChaCha20Poly1305 => 32,
26            Self::XChaCha20Poly1305 => 32,
27            Self::Aes256GcmSiv => 32,
28        }
29    }
30
31    pub fn iv_size(&self) -> usize {
32        match self {
33            Self::Aes256Gcm => 12,
34            Self::Aes256Cbc => 16,
35            Self::ChaCha20Poly1305 => 12,
36            Self::XChaCha20Poly1305 => 24,
37            Self::Aes256GcmSiv => 12,
38        }
39    }
40
41    pub fn tag_size(&self) -> usize {
42        match self {
43            Self::Aes256Gcm => 16,
44            Self::Aes256Cbc => 0, // CBC模式需要单独计算HMAC
45            Self::ChaCha20Poly1305 => 16,
46            Self::XChaCha20Poly1305 => 16,
47            Self::Aes256GcmSiv => 16,
48        }
49    }
50
51    pub fn recommended_iv_mode(&self) -> IvMode {
52        match self {
53            Self::Aes256Gcm => IvMode::Random,
54            Self::Aes256Cbc => IvMode::Random,
55            Self::ChaCha20Poly1305 => IvMode::Random,
56            Self::XChaCha20Poly1305 => IvMode::Random,
57            Self::Aes256GcmSiv => IvMode::Random,
58        }
59    }
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
63pub enum IvMode {
64    /// 随机生成IV(推荐)
65    Random,
66    /// 从文件数据派生IV(基于内容)
67    Derived,
68    /// 使用固定IV(不推荐,仅用于测试)
69    Fixed,
70    /// 基于计数器生成IV
71    Counter,
72    /// 基于文件偏移量生成IV
73    FileOffset,
74}
75
76impl IvMode {
77    pub fn requires_unique_per_file(&self) -> bool {
78        match self {
79            Self::Random => true,
80            Self::Derived => true,
81            Self::Fixed => false,
82            Self::Counter => true,
83            Self::FileOffset => true,
84        }
85    }
86
87    pub fn generate_iv(&self, context: &IvContext) -> Vec<u8> {
88        match self {
89            Self::Random => self.generate_random_iv(context.iv_size),
90            Self::Derived => self.generate_derived_iv(context),
91            Self::Fixed => context.fixed_iv.clone().unwrap_or_default(),
92            Self::Counter => self.generate_counter_iv(context),
93            Self::FileOffset => self.generate_file_offset_iv(context),
94        }
95    }
96
97    fn generate_random_iv(&self, size: usize) -> Vec<u8> {
98        let mut iv = vec![0u8; size];
99        for b in iv.iter_mut() {
100            *b = rand::random();
101        }
102        iv
103    }
104
105    fn generate_derived_iv(&self, context: &IvContext) -> Vec<u8> {
106        use sha2::{Digest, Sha256};
107        let mut hasher = Sha256::new();
108
109        if let Some(data) = &context.data {
110            hasher.update(data);
111        }
112
113        if let Some(file_path) = &context.file_path {
114            hasher.update(file_path.as_bytes());
115        }
116
117        if let Some(file_hash) = &context.file_hash {
118            hasher.update(file_hash);
119        }
120
121        let result = hasher.finalize();
122        result[..context.iv_size].to_vec()
123    }
124
125    fn generate_counter_iv(&self, context: &IvContext) -> Vec<u8> {
126        let counter = context.counter.unwrap_or(0);
127        let mut iv = vec![0u8; context.iv_size];
128
129        // 将计数器编码到IV中
130        for i in 0..8 {
131            if i < context.iv_size {
132                iv[i] = ((counter >> (i * 8)) & 0xFF) as u8;
133            }
134        }
135
136        iv
137    }
138
139    fn generate_file_offset_iv(&self, context: &IvContext) -> Vec<u8> {
140        let offset = context.file_offset.unwrap_or(0);
141        let mut iv = vec![0u8; context.iv_size];
142
143        for i in 0..8 {
144            if i < context.iv_size {
145                iv[i] = ((offset >> (i * 8)) & 0xFF) as u8;
146            }
147        }
148
149        iv
150    }
151}
152
153#[derive(Debug, Clone)]
154pub struct IvContext {
155    pub iv_size: usize,
156    pub data: Option<Vec<u8>>,
157    pub file_path: Option<String>,
158    pub file_hash: Option<String>,
159    pub counter: Option<u64>,
160    pub file_offset: Option<u64>,
161    pub fixed_iv: Option<Vec<u8>>,
162}