1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use std::convert::TryFrom;

use aes_gcm::{Aes256Gcm, Key, Nonce};
use aes_gcm::aead::{Aead, NewAead};
use argon2::{Argon2, PasswordHasher};
use argon2::password_hash::SaltString;
use rand::Rng;
use rand::rngs::OsRng;
use crate::header_v0::HeaderBinaryV0;


pub struct Entry {
	pub header: [u8; 1024],
	pub salt: [u8; 22],
	pub nonce: [u8; 12],
	pub ciphertext: Vec<u8>,
}

pub struct EntryUnlocked {
	pub header: [u8; 1024],
	pub salt: [u8; 22],
	pub nonce: [u8; 12],
	pub text: Vec<u8>,
}

impl Entry {
	pub fn encrypt(value: &[u8], header: &HeaderBinaryV0, password: &str) -> Self {
		let salt = SaltString::generate(&mut OsRng);

		let password_hash = Argon2::default().hash_password(password.as_bytes(), &salt).unwrap().hash.unwrap();

		let cipher = Aes256Gcm::new(Key::from_slice(password_hash.as_bytes()));

		let random_bytes = rand::thread_rng().gen::<[u8; 12]>();
		let nonce = Nonce::from_slice(&random_bytes);

		Self {
			header: <[u8; 1024]>::try_from(header.to_bytes()).unwrap(),
			salt: <[u8; 22]>::try_from(salt.as_bytes()).unwrap(),
			nonce: <[u8; 12]>::try_from(nonce.as_slice()).unwrap(),
			ciphertext: cipher.encrypt(nonce, value).unwrap(),
		}
	}

	pub fn decrypt(&self, password: &str) -> EntryUnlocked{
		let nonce = Nonce::from_slice(&self.nonce);

		let password_hash = Argon2::default().hash_password(password.as_bytes(), &String::from_utf8(Vec::from(self.salt)).unwrap()).unwrap().hash.unwrap();
		let cipher = Aes256Gcm::new(Key::from_slice(password_hash.as_bytes()));

		let ciphertext = &self.ciphertext;

		EntryUnlocked {
			header: self.header,
			salt: self.salt,
			nonce: self.nonce,
			text: cipher.decrypt(nonce, ciphertext.as_slice()).unwrap()
		}
	}
	pub fn from_bytes(file: &[u8]) -> Self {
		let header_and_rest = file.split_at(1024);
		let salt_and_rest = header_and_rest.1.split_at(22);
		let nonce_and_rest = salt_and_rest.1.split_at(12);
		Self {
			header: <[u8; 1024]>::try_from(header_and_rest.0).unwrap(),
			salt: <[u8; 22]>::try_from(salt_and_rest.0).unwrap(),
			nonce: <[u8; 12]>::try_from(nonce_and_rest.0).unwrap(),
			ciphertext: Vec::from(nonce_and_rest.1)
		}
	}
	pub fn to_bytes(&self) -> Vec<u8> {
		let mut file = Vec::new();
		file.extend_from_slice(&self.header);
		file.extend_from_slice(&self.salt);
		file.extend_from_slice(&self.nonce);
		file.extend_from_slice(&self.ciphertext);
		file
	}
}