fxfs_crypto/cipher/
fxfs.rs1use super::{
5 CbcDecryptProcessor, CbcEncryptProcessor, Cipher, FSCRYPT_PADDING, SECTOR_SIZE, Tweak,
6 UnwrappedKey, XtsProcessor,
7};
8use aes::Aes256;
9use aes::cipher::generic_array::GenericArray;
10use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
11use anyhow::Error;
12use std::hash::{Hash, Hasher};
13use zerocopy::IntoBytes;
14
15#[derive(Debug)]
16pub struct FxfsCipher {
17 key: Aes256,
18}
19impl FxfsCipher {
20 pub fn new(key: &UnwrappedKey) -> Self {
21 Self { key: Aes256::new(GenericArray::from_slice(key)) }
22 }
23}
24impl Cipher for FxfsCipher {
25 fn encrypt(
26 &self,
27 _ino: u64,
28 _device_offset: u64,
29 file_offset: u64,
30 buffer: &mut [u8],
31 ) -> Result<(), Error> {
32 fxfs_trace::duration!(c"encrypt", "len" => buffer.len());
33 assert_eq!(file_offset % SECTOR_SIZE, 0);
34 let mut sector_offset = file_offset / SECTOR_SIZE;
35 assert_eq!(buffer.len() % (SECTOR_SIZE as usize), 0);
36 for sector in buffer.chunks_exact_mut(SECTOR_SIZE as usize) {
37 let mut tweak = Tweak(sector_offset as u128);
38 self.key.encrypt_block(GenericArray::from_mut_slice(tweak.as_mut_bytes()));
40 self.key.encrypt_with_backend(XtsProcessor::new(tweak, sector));
41 sector_offset += 1;
42 }
43 Ok(())
44 }
45
46 fn decrypt(
47 &self,
48 _ino: u64,
49 _device_offset: u64,
50 file_offset: u64,
51 buffer: &mut [u8],
52 ) -> Result<(), Error> {
53 fxfs_trace::duration!(c"decrypt", "len" => buffer.len());
54 assert_eq!(file_offset % SECTOR_SIZE, 0);
55 let mut sector_offset = file_offset / SECTOR_SIZE;
56 assert_eq!(buffer.len() % (SECTOR_SIZE as usize), 0);
57 for sector in buffer.chunks_exact_mut(SECTOR_SIZE as usize) {
58 let mut tweak = Tweak(sector_offset as u128);
59 self.key.encrypt_block(GenericArray::from_mut_slice(tweak.as_mut_bytes()));
61 self.key.decrypt_with_backend(XtsProcessor::new(tweak, sector));
62 sector_offset += 1;
63 }
64 Ok(())
65 }
66
67 fn encrypt_filename(&self, object_id: u64, buffer: &mut Vec<u8>) -> Result<(), Error> {
68 buffer.resize(buffer.len().next_multiple_of(FSCRYPT_PADDING), 0);
70 self.key.encrypt_with_backend(CbcEncryptProcessor::new(Tweak(object_id as u128), buffer));
71 Ok(())
72 }
73
74 fn decrypt_filename(&self, object_id: u64, buffer: &mut Vec<u8>) -> Result<(), Error> {
75 self.key.decrypt_with_backend(CbcDecryptProcessor::new(Tweak(object_id as u128), buffer));
76 if let Some(i) = buffer.iter().rposition(|x| *x != 0) {
78 let new_len = i + 1;
79 buffer.truncate(new_len);
80 }
81 Ok(())
82 }
83
84 fn hash_code(&self, _raw_filename: &[u8], filename: &str) -> u32 {
85 if filename.is_empty() {
86 return 0;
87 }
88 let mut hasher = rustc_hash::FxHasher::default();
89 filename.hash(&mut hasher);
90 hasher.finish() as u32
91 }
92
93 fn hash_code_casefold(&self, filename: &str) -> u32 {
94 if filename.is_empty() {
95 return 0;
96 }
97 let mut hasher = rustc_hash::FxHasher::default();
98 for ch in fxfs_unicode::casefold(filename.chars()) {
99 ch.hash(&mut hasher);
100 }
101 let hash = hasher.finish() as u32;
102 hash
107 }
108
109 fn supports_inline_encryption(&self) -> bool {
110 false
111 }
112
113 fn crypt_ctx(&self, _ino: u64, _file_offset: u64) -> Option<(u32, u8)> {
114 None
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::{FxfsCipher, UnwrappedKey};
121 use crate::Cipher;
122 use std::sync::Arc;
123
124 #[test]
129 fn test_encrypt_filename() {
130 let raw_key_hex = "1fcdf30b7d191bd95d3161fe08513b864aa15f27f910f1c66eec8cfa93e9893b";
131 let raw_key_bytes: [u8; 32] =
132 hex::decode(raw_key_hex).expect("decode failed").try_into().unwrap();
133 let unwrapped_key = UnwrappedKey::new(raw_key_bytes.to_vec());
134 let cipher: Arc<dyn Cipher> = Arc::new(FxfsCipher::new(&unwrapped_key));
135 let object_id = 2;
136 let mut text = "filename".to_string().as_bytes().to_vec();
137 cipher.encrypt_filename(object_id, &mut text).expect("encrypt filename failed");
138 assert_eq!(text, hex::decode("52d56369103a39b3ea1e09c85dd51546").expect("decode failed"));
139 }
140
141 #[test]
145 fn test_decrypt_filename() {
146 let raw_key_hex = "1fcdf30b7d191bd95d3161fe08513b864aa15f27f910f1c66eec8cfa93e9893b";
147 let raw_key_bytes: [u8; 32] =
148 hex::decode(raw_key_hex).expect("decode failed").try_into().unwrap();
149 let unwrapped_key = UnwrappedKey::new(raw_key_bytes.to_vec());
150 let cipher: Arc<dyn Cipher> = Arc::new(FxfsCipher::new(&unwrapped_key));
151 let object_id = 2;
152 let mut text = hex::decode("52d56369103a39b3ea1e09c85dd51546").expect("decode failed");
153 cipher.decrypt_filename(object_id, &mut text).expect("encrypt filename failed");
154 assert_eq!(text, "filename".to_string().as_bytes().to_vec());
155 }
156 #[test]
157 fn test_hash_code() {
158 let unwrapped_key = UnwrappedKey::new(vec![0; 32]);
162 let cipher: Arc<dyn Cipher> = Arc::new(FxfsCipher::new(&unwrapped_key));
163 assert_eq!(cipher.hash_code("Straße".as_bytes(), "Straße"), 433651741);
164 }
165
166 #[test]
167 fn test_hash_code_casefold() {
168 let unwrapped_key = UnwrappedKey::new(vec![0; 32]);
172 let cipher: Arc<dyn Cipher> = Arc::new(FxfsCipher::new(&unwrapped_key));
173 assert_eq!(cipher.hash_code_casefold("Straße"), 3602031996);
174 }
175}