1pub mod credentials;
47pub mod decrypt;
48pub mod encrypt;
49pub mod error;
50
51pub use secure_types;
52pub use zeroize;
53
54pub use credentials::Credentials;
55pub use decrypt::decrypt_data;
56pub use encrypt::encrypt_data;
57
58use bincode::{Decode, Encode, config::standard, decode_from_slice};
59use error::Error;
60use zeroize::Zeroize;
61
62pub use argon2_rs::Argon2;
63
64const HEADER_LEN: usize = 8;
65const ENCRYPTED_INFO_START: usize = 12;
66pub const RECOMMENDED_SALT_LEN: usize = 64;
67
68pub(crate) fn extract_encrypted_info_and_data(
69 encrypted_data: &[u8],
70) -> Result<(Vec<u8>, Vec<u8>), Error> {
71 let encrypted_info_length = u32::from_le_bytes(
72 encrypted_data[HEADER_LEN..ENCRYPTED_INFO_START]
73 .try_into()
74 .map_err(|_| Error::EncryptedInfo)?,
75 );
76
77 let encrypted_info_end = ENCRYPTED_INFO_START + (encrypted_info_length as usize);
78 let encrypted_info = &encrypted_data[ENCRYPTED_INFO_START..encrypted_info_end];
79 let encrypted_data = &encrypted_data[encrypted_info_end..];
80 Ok((encrypted_info.to_vec(), encrypted_data.to_vec()))
81}
82
83#[derive(Default, Clone, Debug, Encode, Decode)]
84pub struct EncryptedInfo {
85 pub password_salt: Vec<u8>,
86 pub username_salt: Vec<u8>,
87 pub cipher_nonce: Vec<u8>,
88 pub argon2: Argon2,
89}
90
91impl EncryptedInfo {
92 pub fn new(
93 password_salt: Vec<u8>,
94 username_salt: Vec<u8>,
95 cipher_nonce: Vec<u8>,
96 argon2: Argon2,
97 ) -> Self {
98 Self {
99 password_salt,
100 username_salt,
101 cipher_nonce,
102 argon2,
103 }
104 }
105
106 pub fn from_encrypted_data(data: &[u8]) -> Result<Self, Error> {
107 let (encrypted_info, _) = extract_encrypted_info_and_data(data)?;
108
109 let info: (EncryptedInfo, usize) = decode_from_slice(&encrypted_info, standard())
110 .map_err(|e| Error::DecodingFailed(e.to_string()))?;
111
112 Ok(info.0)
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use secure_types::{SecureBytes, SecureString};
120
121 #[test]
122 fn can_encrypt_decrypt() {
123 let exposed_data: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
124 let credentials = Credentials::new(
125 SecureString::from("username"),
126 SecureString::from("password"),
127 SecureString::from("password"),
128 );
129
130 let m_cost = 24_000;
131 let t_cost = 3;
132 let p_cost = 1;
133
134 let argon2 = Argon2::new(m_cost, t_cost, p_cost);
135
136 let secure_data = SecureBytes::from_vec(exposed_data.clone()).unwrap();
137
138 let encrypted_data = encrypt_data(argon2, secure_data, credentials.clone()).unwrap();
139 let decrypted_data = decrypt_data(encrypted_data, credentials).unwrap();
140
141 decrypted_data.unlock_slice(|decrypted_data| {
142 assert_eq!(exposed_data, decrypted_data);
143 });
144 }
145}