1use std::io::{Read, Write};
20use std::fs::{self, File};
21use std::io::{Error, ErrorKind};
22use aes::Aes256;
23use aes::cipher::{
24 BlockEncrypt, BlockDecrypt, KeyInit,
25 generic_array::GenericArray,
26};
27use hmac_sha256::Hash;
28
29enum Stage {
30 Encrypt,
31 Decrypt(Option<u8>)
32}
33
34const SMALL_FILE_SIZE_LIMIT: u64 = 26_214_400 * 2;
35const CHUNK_SIZE: usize = 26_214_400;
36pub const FILE_EXTENSION: &str = ".cryptile";
37
38
39fn cipher_init(key: &[u8; 32]) -> Aes256 {
40 let key = GenericArray::from(*key);
41 Aes256::new(&key)
42}
43
44fn encrypt_chunk_serially(blocks: &mut Vec<[u8; 16]>, cipher: &Aes256) {
45 for byte_block in blocks.iter_mut() {
46 let mut block = GenericArray::from(byte_block.to_owned());
47
48 cipher.encrypt_block(&mut block);
49
50 for (i, byte) in block.bytes().enumerate() {
51 if let Ok(byte) = byte {
52 (*byte_block)[i] = byte;
53 }
54 }
55 }
56}
57
58fn decrypt_chunk_serially(blocks: &mut Vec<[u8; 16]>, cipher: &Aes256) {
59 for byte_block in blocks.iter_mut() {
60 let mut block = GenericArray::from(byte_block.to_owned());
61
62 cipher.decrypt_block(&mut block);
63
64 for (i, byte) in block.bytes().enumerate() {
65 if let Ok(byte) = byte {
66 (*byte_block)[i] = byte;
67 }
68 }
69 }
70}
71
72fn encrypt_small_file(r_file: &mut File, cipher: &Aes256, w_file: &mut File) -> Result<(), Error> {
129 let mut blocks = read_entire_as_blocks(r_file, Stage::Encrypt)?;
130 encrypt_chunk_serially(&mut blocks, &cipher);
131 write_entire_from_blocks(w_file, &blocks, Stage::Encrypt)?;
132
133 Ok(())
134}
135
136fn encrypt_large_file(r_file: &mut File, cipher: &Aes256, w_file: &mut File) -> Result<(), Error> {
137 println!("Encrypting large file in parts...");
138 loop {
139 let (mut blocks, cont) = read_chunk_as_blocks(r_file, Stage::Encrypt)?;
140 encrypt_chunk_serially(&mut blocks, &cipher);
141 write_entire_from_blocks(w_file, &blocks, Stage::Encrypt)?;
142
143 if !cont {
144 break
145 }
146 }
147
148 Ok(())
149}
150
151fn decrypt_small_file(r_file: &mut File, cipher: &Aes256, w_file: &mut File) -> Result<(), Error> {
152 let mut blocks = read_entire_as_blocks(r_file, Stage::Decrypt(None))?;
153 decrypt_chunk_serially(&mut blocks, &cipher);
154 let last_block = blocks.last();
155 if let Some(block) = last_block {
156 if let Some(padding) = block.last() {
157 write_entire_from_blocks(w_file, &blocks, Stage::Decrypt(Some(*padding)))?;
158 }
159 else {
160 return Err(Error::from(ErrorKind::UnexpectedEof))
161 }
162 }
163 else {
164 return Err(Error::from(ErrorKind::UnexpectedEof))
165 }
166 Ok(())
167}
168
169fn decrypt_large_file(r_file: &mut File, cipher: &Aes256, w_file: &mut File) -> Result<(), Error> {
170 println!("Decrypting large file in parts...");
171 loop {
172 let (mut blocks, cont) = read_chunk_as_blocks(r_file, Stage::Decrypt(None))?;
173 decrypt_chunk_serially(&mut blocks, &cipher);
174
175 if !cont {
176 let last_block = blocks.last();
177 if let Some(block) = last_block {
178 if let Some(padding) = block.last() {
179 write_entire_from_blocks(w_file, &blocks, Stage::Decrypt(Some(*padding)))?;
180 }
181 else {
182 return Err(Error::from(ErrorKind::UnexpectedEof))
183 }
184 }
185 else {
186 return Err(Error::from(ErrorKind::UnexpectedEof))
187 }
188 break
189 }
190 write_entire_from_blocks(w_file, &blocks, Stage::Decrypt(None))?;
191 }
192 Ok(())
193}
194
195fn hash_encrypt_write(hash: [u8; 32], cipher: &Aes256, file: &mut File) -> Result<(), Error> {
196 let mut temp_block = [0u8; 16];
197 for (i, byte) in hash[0..16].iter().enumerate() {
198 temp_block[i] = *byte;
199 }
200 let mut block1 = GenericArray::from(temp_block);
201
202 let mut temp_block = [0u8; 16];
203 for (i, byte) in hash[16..32].iter().enumerate() {
204 temp_block[i] = *byte;
205 }
206 let mut block2 = GenericArray::from(temp_block);
207
208 cipher.encrypt_block(&mut block1);
209 cipher.encrypt_block(&mut block2);
210
211 file.write(&block1)?;
212 file.write(&block2)?;
213 Ok(())
214}
215
216fn hash_read_decrypt(cipher: &Aes256, file: &mut File) -> Result<[u8; 32], Error> {
217 let mut block1 = [0u8; 16];
218 let mut block2 = [0u8; 16];
219 file.read(&mut block1)?;
220 file.read(&mut block2)?;
221
222 let mut block1 = GenericArray::from(block1);
223 let mut block2 = GenericArray::from(block2);
224
225 cipher.decrypt_block(&mut block1);
226 cipher.decrypt_block(&mut block2);
227
228 let mut res = [0u8; 32];
229 let mut i: usize = 0;
230 for byte in block1 {
231 res[i] = byte;
232 i += 1;
233 }
234 for byte in block2 {
235 res[i] = byte;
236 i += 1;
237 }
238
239 Ok(res)
240}
241
242fn read_entire_as_blocks(file: &mut File, stage: Stage) -> Result<Vec<[u8; 16]>, Error> {
243 let mut bytes = Vec::new();
244
245 loop {
246 let mut block = [0u8; 16];
247 match file.read(&mut block) {
248 Ok(b) if b < 16 => {
249 if let Stage::Encrypt = stage {
250 let padding = (16 - b) as u8;
251 block[16 - 1] = padding;
252 bytes.push(block);
253 }
254 break
255 },
256 Err(e) => return Err(Error::from(e)),
257 Ok(_) => ()
258 }
259 bytes.push(block);
260 }
261
262 Ok(bytes)
263}
264
265fn read_chunk_as_blocks(file: &mut File, stage: Stage) -> Result<(Vec<[u8; 16]>, bool), Error> {
266 let mut bytes = Vec::new();
267 let n_blocks = CHUNK_SIZE / 16;
268 let mut cont = true;
269
270 loop {
271 let mut block = [0u8; 16];
272 match file.read(&mut block) {
273 Ok(b) if b < 16 => {
274 if let Stage::Encrypt = stage {
275 let padding = (16 - b) as u8;
276 block[16 - 1] = padding;
277 bytes.push(block);
278 }
279 cont = false;
280 break
281 },
282 Err(e) => return Err(Error::from(e)),
283 Ok(_) => ()
284 }
285 bytes.push(block);
286 if bytes.len() >= n_blocks {
287 break
288 }
289 }
290
291 Ok((bytes, cont))
292}
293
294fn write_entire_from_blocks(file: &mut File, blocks: &Vec<[u8; 16]>, stage: Stage) -> Result<(), Error> {
295
296 let mut blocks = blocks.iter().peekable();
297 while let Some(block) = blocks.next() {
298 if blocks.peek().is_none() {
299 if let Stage::Decrypt(Some(padding)) = stage {
300 if padding > 16 {
301 return Err(Error::from(ErrorKind::InvalidInput));
302 }
303 let t = (16 - padding) as usize;
304 if let Err(e) = file.write(&block[..t]) {
305 return Err(e)
306 }
307 break
308 }
309 }
310 if let Err(e) = file.write(block) {
311 return Err(e)
312 }
313 }
314
315 Ok(())
316}
317
318pub fn encrypt(filename: &str, key: &[u8; 32]) -> Result<(), Error> {
326 let key_hash = Hash::hash(key);
327 let cipher = cipher_init(key);
328 let new_file_name = filename.to_owned() + FILE_EXTENSION;
329
330 let mut reader = File::open(filename)?;
331 let size = reader.metadata()?.len();
332 let mut writer = File::create(&new_file_name)?;
333
334 hash_encrypt_write(key_hash, &cipher, &mut writer)?;
335
336 if size < SMALL_FILE_SIZE_LIMIT {
337 encrypt_small_file(&mut reader, &cipher, &mut writer)?;
338 }
339 else {
340 encrypt_large_file(&mut reader, &cipher, &mut writer)?;
341 }
342
343 Ok(())
344}
345
346pub fn decrypt(filename: &str, key: &[u8; 32]) -> Result<(), Error> {
362 if !filename.ends_with(FILE_EXTENSION) {
363 return Err(Error::from(ErrorKind::Unsupported))
364 }
365
366 let key_hash = Hash::hash(key);
367 let cipher = cipher_init(key);
368
369 let new_file_name = filename.replace(FILE_EXTENSION, "");
370
371 let mut reader = File::open(filename)?;
372 let size = reader.metadata()?.len();
373
374 let hash = hash_read_decrypt(&cipher, &mut reader)?;
375 if key_hash != hash {
376 return Err(Error::from(ErrorKind::InvalidInput))
377 }
378 let mut writer = File::create(&new_file_name)?;
379
380 if size < SMALL_FILE_SIZE_LIMIT {
381 decrypt_small_file(&mut reader, &cipher, &mut writer)?;
382 }
383 else {
384 decrypt_large_file(&mut reader, &cipher, &mut writer)?;
385 }
386
387 Ok(())
388}
389
390pub fn is_correct_key(filename: &str, key: &[u8; 32]) -> Result<bool, Error> {
418 if !filename.ends_with(FILE_EXTENSION) {
419 return Err(Error::from(ErrorKind::Unsupported))
420 }
421
422 let key_hash = Hash::hash(key);
423 let cipher = cipher_init(key);
424 let mut reader = File::open(filename)?;
425
426 let hash = hash_read_decrypt(&cipher, &mut reader)?;
427 if key_hash != hash {
428 return Ok(false)
429 }
430
431 Ok(true)
432}
433
434pub fn delete(filename: &str) {
438 _ = fs::remove_file(filename);
439}
440
441
442
443pub mod benches {
444 use super::*;
445
446 pub fn bench_serially_encrypt(filename: &str) {
447 let pass = "0123456789ABCDEF";
448 let pass: Vec<u8> = (*pass).bytes().collect();
449 let key = Hash::hash(&pass);
450 encrypt(filename, &key).expect("Error in Encrypting");
451 }
452
453 pub fn bench_serially_decrypt(filename: &str) {
456 let pass = "0123456789ABCDEF";
457 let pass: Vec<u8> = (*pass).bytes().collect();
458 let key = Hash::hash(&pass);
459 decrypt(filename, &key).expect("Error in Decrypting");
460 }
461
462 }
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469 use std::time::Duration;
470 use std::thread;
471 use std::thread::available_parallelism;
472 use threads_pool::ThreadPool;
473 const TEST_KEY: &str = "0123456789ABCDEF0123456789ABCDEF";
474
475 #[test]
476 fn encrypt_file() {
477 let pass = "0123456789ABCDEF";
478 let pass: Vec<u8> = (*pass).bytes().collect();
479 let key = Hash::hash(&pass);
480 encrypt("test.jpg", &key).expect("Error in Encrypting");
481 }
482
483 #[test]
484 fn decrypt_file() {
485 let pass = "0123456789ABCDEF";
486 let pass: Vec<u8> = (*pass).bytes().collect();
487 let key = Hash::hash(&pass);
488 decrypt("test.jpg.cryptile", &key).expect("Error in Decrypting");
489 }
490
491 #[test]
492 fn num_cpus() {
493 let default_parallelism_approx = available_parallelism().unwrap().get();
494
495 println!("Number of availaible parallelism: {}", default_parallelism_approx);
496 }
497
498 #[test]
499 fn thread_pool_test() {
500 let pool = ThreadPool::new(4);
501
502 for i in 1..=10 {
503 println!("Starting thread {}", i);
504 pool.execute(move || {
505 thread::sleep(Duration::from_secs(1));
506 println!("thread {} finished", i);
507 }).unwrap();
508 }
509
510 drop(pool);
511
512 println!("finished function... All tasks should be completed before this");
513 }
514}