1use std::collections::HashMap;
2
3use aes::cipher::generic_array::GenericArray;
4use aes::cipher::{BlockEncrypt, KeyInit};
5use aes::Aes128;
6use aes_gcm::{AeadInPlace, Aes128Gcm};
7use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
8use cipher::BlockDecrypt;
9use hkdf::Hkdf;
10use pbkdf2::pbkdf2_hmac_array;
11use rand::distributions::{Alphanumeric, DistString};
12use serde::{Deserialize, Serialize};
13use sha2::{Sha256, Sha512};
14
15pub mod rsa;
16
17use crate::http::UserSession;
18use crate::protocol::commands::UserAttributesResponse;
19use crate::Result;
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23pub struct StorageQuotas {
24 pub memory_used: u64,
26 pub memory_total: u64,
28}
29
30pub(crate) fn prepare_key_v1(password: &[u8]) -> [u8; 16] {
31 let mut data = GenericArray::from([
32 0x93u8, 0xC4, 0x67, 0xE3, 0x7D, 0xB0, 0xC7, 0xA4, 0xD1, 0xBE, 0x3F, 0x81, 0x01, 0x52, 0xCB,
33 0x56,
34 ]);
35
36 for _ in 0..65536 {
37 for chunk in password.chunks(16) {
38 let mut key = [0u8; 16];
39 key[0..chunk.len()].copy_from_slice(chunk);
40 let aes = Aes128::new(&GenericArray::from(key));
41 aes.encrypt_block(&mut data);
42 }
43 }
44
45 data.into()
46}
47
48pub(crate) fn prepare_key_v2(password: &[u8], salt: &[u8]) -> [u8; 32] {
49 pbkdf2_hmac_array::<Sha512, 32>(password, salt, 100_000)
50}
51
52pub(crate) fn encrypt_ebc_in_place(key: &[u8], data: &mut [u8]) {
53 let aes = Aes128::new(key.into());
54 for block in data.chunks_mut(16) {
55 aes.encrypt_block(block.into())
56 }
57}
58
59pub(crate) fn decrypt_ebc_in_place(key: &[u8], data: &mut [u8]) {
60 let aes = Aes128::new(key.into());
61 for block in data.chunks_mut(16) {
62 aes.decrypt_block(block.into())
63 }
64}
65
66pub(crate) fn unmerge_key_mac(key: &mut [u8]) {
67 let (fst, snd) = key.split_at_mut(16);
68 for (a, b) in fst.iter_mut().zip(snd) {
69 *a ^= *b;
70 }
71}
72
73pub(crate) fn merge_key_mac(key: &mut [u8]) {
74 let (fst, snd) = key.split_at_mut(16);
75 for (a, b) in fst.iter_mut().zip(snd) {
76 *a ^= *b;
77 }
78}
79
80pub(crate) fn random_string(len: usize) -> String {
81 let mut rng = rand::thread_rng();
82 Alphanumeric.sample_string(&mut rng, len)
83}
84
85#[repr(u8)]
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
87enum KeysAttrTag {
88 Version = 1,
89 CreationTime = 2,
90 Identity = 3,
91 Generation = 4,
92 Attr = 5,
93 PrivEd25519 = 16,
94 PrivCu25519 = 17,
95 PrivRsa = 18,
96 AuthringEd25519 = 32,
97 AuthringCu25519 = 33,
98 ShareKeys = 48,
99 PendingOutshares = 64,
100 PendingInshares = 65,
101 Backups = 80,
102 Warnings = 96,
103}
104
105impl TryFrom<u8> for KeysAttrTag {
106 type Error = ();
107
108 fn try_from(value: u8) -> Result<Self, Self::Error> {
109 match value {
110 1 => Ok(KeysAttrTag::Version),
111 2 => Ok(KeysAttrTag::CreationTime),
112 3 => Ok(KeysAttrTag::Identity),
113 4 => Ok(KeysAttrTag::Generation),
114 5 => Ok(KeysAttrTag::Attr),
115 16 => Ok(KeysAttrTag::PrivEd25519),
116 17 => Ok(KeysAttrTag::PrivCu25519),
117 18 => Ok(KeysAttrTag::PrivRsa),
118 32 => Ok(KeysAttrTag::AuthringEd25519),
119 33 => Ok(KeysAttrTag::AuthringCu25519),
120 48 => Ok(KeysAttrTag::ShareKeys),
121 64 => Ok(KeysAttrTag::PendingOutshares),
122 65 => Ok(KeysAttrTag::PendingInshares),
123 80 => Ok(KeysAttrTag::Backups),
124 96 => Ok(KeysAttrTag::Warnings),
125 _ => Err(()),
126 }
127 }
128}
129
130pub(crate) fn extract_share_keys(
131 session: &UserSession,
132 attr: &UserAttributesResponse,
133) -> Result<HashMap<String, Vec<u8>>> {
134 let hkdf = Hkdf::<Sha256>::new(None, &session.key);
135 let mut derived_key = [0u8; 16];
136 hkdf.expand(&[1], &mut derived_key)?;
137
138 let attr_value = BASE64_URL_SAFE_NO_PAD.decode(&attr.attr_value)?;
139
140 assert_eq!(attr_value[0], 20);
147 let (iv, data) = attr_value[2..].split_at(12);
148 let gcm = Aes128Gcm::new(derived_key.as_slice().into());
149 let mut data = data.to_vec();
150 gcm.decrypt_in_place(iv.into(), &[], &mut data)?;
151
152 let mut share_keys = HashMap::default();
156
157 let mut cursor = 0;
158 while cursor < data.len() {
159 let Ok(tag) = KeysAttrTag::try_from(data[cursor]) else {
160 continue;
161 };
162 let len = (usize::from(data[cursor + 1]) << 16)
163 + (usize::from(data[cursor + 2]) << 8)
164 + usize::from(data[cursor + 3]);
165 cursor += 4;
166
167 if tag == KeysAttrTag::ShareKeys {
168 for chunk in data[cursor..(cursor + len)].chunks(23) {
177 let (handle, rest) = chunk.split_at(6);
178 let (share_key, _trust) = rest.split_at(16);
179 let handle = BASE64_URL_SAFE_NO_PAD.encode(handle);
180 share_keys.insert(handle, share_key.to_vec());
181 }
182
183 break;
184 }
185
186 cursor += len;
187 }
188
189 Ok(share_keys)
190}
191
192pub(crate) fn extract_attachments(attrs_str: &str) -> (Option<String>, Option<String>) {
193 let mut thumbnail_handle = None;
194 let mut preview_image_handle = None;
195
196 let attrs = attrs_str
198 .split('/')
199 .filter_map(|it| it.split_once(':')?.1.split_once('*'));
200
201 for (kind, handle) in attrs {
202 match kind {
203 "0" => {
204 thumbnail_handle = Some(handle.to_string());
205 }
206 "1" => {
207 preview_image_handle = Some(handle.to_string());
208 }
209 _ => continue,
210 }
211 }
212
213 (thumbnail_handle, preview_image_handle)
214}
215
216#[allow(unused)]
218pub(crate) fn chunks_iterator() -> impl Iterator<Item = (u64, u64)> {
219 std::iter::successors(Some(131_072), |&(mut chunk_size): &u64| {
220 if chunk_size < 1_048_576 {
221 chunk_size += 131_072;
222 }
223 Some(chunk_size)
224 })
225 .scan(0, |start, chunk_size| {
226 let bounds = (*start, *start + chunk_size - 1);
227 *start = bounds.1 + 1;
228 Some(bounds)
229 })
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 fn test_buffer(size: usize, start: usize, step: usize) -> Vec<u8> {
237 (0..size)
238 .map(|i| u8::try_from((start + i * step) % 255).unwrap())
239 .collect()
240 }
241
242 #[test]
243 fn prepare_key_v1_8_bytes_test() {
244 let buffer = test_buffer(8, 0, 1);
245 let result = prepare_key_v1(buffer.as_slice());
246 let result = hex::encode(result);
247
248 assert_eq!(result.as_str(), "c4589a459956887caf0b408635c3c03b");
249 }
250
251 #[test]
252 fn prepare_key_v1_10_bytes_test() {
253 let buffer = test_buffer(10, 0, 1);
254 let result = prepare_key_v1(buffer.as_slice());
255 let result = hex::encode(result);
256
257 assert_eq!(result.as_str(), "59930b1c55d783ac77df4c4ff261b0f1");
258 }
259
260 #[test]
261 fn prepare_key_v1_64_bytes_test() {
262 let buffer = test_buffer(64, 0, 1);
263 let result = prepare_key_v1(buffer.as_slice());
264 let result = hex::encode(result);
265
266 assert_eq!(result.as_str(), "83bd84689f057f9ed9834b3ecb81d80e");
267 }
268}