extensible_encrypter/
decrypter.rs1use crate::error::{self, DefaultError};
2use crate::prelude::*;
3use aes_gcm_siv::aead::Aead;
4use aes_gcm_siv::{aead::KeyInit, Aes256GcmSiv, Nonce};
5use pbkdf2::password_hash::SaltString;
6
7pub mod builder;
8
9pub struct Aes256GcmSivConfig {
10 hash_rounds: u32,
11 hash_algorithm: super::hasher::pbkdf2::Algorithm,
12}
13
14impl Aes256GcmSivConfig {
15 pub fn set_hash_algorithm(&mut self, hash_algorithm: super::hasher::pbkdf2::Algorithm) {
16 self.hash_algorithm = hash_algorithm;
17 }
18
19 pub fn set_hash_rounds(&mut self, hash_rounds: u32) {
20 self.hash_rounds = hash_rounds;
21 }
22}
23
24impl Default for Aes256GcmSivConfig {
26 fn default() -> Self {
27 Self {
28 hash_rounds: 600_000,
29 hash_algorithm: super::hasher::pbkdf2::Algorithm::Pbkdf2Sha512,
30 }
31 }
32}
33
34pub enum DecrypterCipher {
35 Aes256GcmSiv(Aes256GcmSivConfig),
36}
37
38pub trait DecryptProvider {
39 type Cipher;
40
41 fn decrypt(
42 &self,
43 input: &mut DecryptData,
44 cipher: Self::Cipher,
45 ) -> Result<DecryptionResult, DefaultError>;
46}
47
48pub struct PBKDF2DecryptProvide;
49
50impl DecryptProvider for PBKDF2DecryptProvide {
51 type Cipher = DecrypterCipher;
52
53 fn decrypt(
54 &self,
55 input: &mut DecryptData,
56 cipher: Self::Cipher,
57 ) -> Result<DecryptionResult, DefaultError> {
58 match cipher {
59 DecrypterCipher::Aes256GcmSiv(config) => {
60 tracing::info!("Decrypting: Aes256GcmSiv");
61
62 let salt = String::from_utf8(input.salt().clone())?;
64 let salt = SaltString::from_b64(salt.as_str()).expect("salt is base64 encoded");
65
66 let nonce = Nonce::try_from(&input.nonce()[..]).map_err(|_err| {
67 DefaultError::ErrorMessage("Failed parsing nonce from slice".to_string())
68 })?;
69 let ciphertext = input.ciphertext();
70
71 let hasher = super::hasher::pbkdf2::Hasher::hash(
73 "password",
74 &config.hash_rounds,
75 config.hash_algorithm,
76 Some(salt),
77 )?;
78
79 let key = hex::decode(hasher.hash().as_str())?;
81 let decryption_key_array: [u8; 32] = key.try_into().unwrap();
82
83 let decryption_cipher =
85 Aes256GcmSiv::new_from_slice(&decryption_key_array).unwrap();
86
87 let decrypted_message = match decryption_cipher.decrypt(&nonce, ciphertext.as_ref())
89 {
90 Ok(message) => message,
91 Err(err) => {
92 return Err(DefaultError::ErrorMessage(format!(
93 "Failed to decrypt due to {}.",
94 err
95 )))
96 }
97 };
98
99 let decrypted_message = String::from_utf8(decrypted_message).unwrap();
101
102 println!("Decrypted message: {}", decrypted_message);
104
105 Ok(DecryptionResult::new(decrypted_message))
106 }
107 }
108 }
109}
110
111pub struct DecryptionResult {
112 plaintext: String,
113}
114
115impl DecryptionResult {
116 pub fn new(plaintext: String) -> Self {
117 Self { plaintext }
118 }
119
120 pub fn plaintext(&self) -> &str {
121 &self.plaintext
122 }
123}
124
125pub struct Decrypter;
126
127impl Decrypter {
128 pub fn decrypt<CipherType>(
130 input: impl DecrypterPayload,
131 provider: impl DecryptProvider<Cipher = CipherType>,
132 cipher: CipherType,
133 ) -> error::Result<DecryptionResult> {
134 let input = &mut DecryptData::from_payload(&input);
135
136 provider.decrypt(input, cipher)
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use tracing_test::traced_test;
144
145 #[traced_test]
146 #[test]
147 fn aes256_gcm_siv_pbkdf2_sha256() {
148 let ciphertext = "e7550de30e76d4546082d17e762032b6dfcc650e2d4072cc6e52bf";
149 let nonce = "66444888d4f0e1a69f387dfe";
150 let salt = "30656e4d7a36716534452b414837384d4a4946635967";
151
152 let ciphertext = hex::decode(ciphertext).unwrap();
153 let nonce = hex::decode(nonce).unwrap();
154 let salt = hex::decode(salt).unwrap();
155
156 let input = &mut builder::DecrypterBuilder::new()
157 .salt(salt)
158 .nonce(nonce)
159 .ciphertext(ciphertext)
160 .build();
161
162 let provider = PBKDF2DecryptProvide {};
163
164 let mut cipher_config = Aes256GcmSivConfig::default();
165 cipher_config.set_hash_algorithm(crate::hasher::pbkdf2::Algorithm::Pbkdf2Sha256);
166 cipher_config.set_hash_rounds(20); let result = Decrypter::decrypt(
169 input,
170 provider,
171 DecrypterCipher::Aes256GcmSiv(cipher_config),
172 );
173 let result = result.expect("Decryption failed");
174
175 assert_eq!(result.plaintext, "hello there");
176 }
177}