extensible_encrypter/
decrypter.rs
1use 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
14#[allow(dead_code)]
15impl Aes256GcmSivConfig {
16 pub fn set_hash_algorithm(&mut self, hash_algorithm: super::hasher::pbkdf2::Algorithm) {
17 self.hash_algorithm = hash_algorithm;
18 }
19
20 pub fn set_hash_rounds(&mut self, hash_rounds: u32) {
21 self.hash_rounds = hash_rounds;
22 }
23}
24
25impl Default for Aes256GcmSivConfig {
27 fn default() -> Self {
28 Self {
29 hash_rounds: 600_000,
30 hash_algorithm: super::hasher::pbkdf2::Algorithm::Pbkdf2Sha512,
31 }
32 }
33}
34
35pub enum DecrypterCipher {
36 Aes256GcmSiv(Aes256GcmSivConfig),
37}
38
39pub trait DecryptProvider {
40 type Cipher;
41
42 fn decrypt(
43 &self,
44 input: &mut DecryptData,
45 cipher: Self::Cipher,
46 ) -> Result<DecryptionResult, DefaultError>;
47}
48
49pub struct PBKDF2DecryptProvide;
50
51impl DecryptProvider for PBKDF2DecryptProvide {
52 type Cipher = DecrypterCipher;
53
54 fn decrypt(
55 &self,
56 input: &mut DecryptData,
57 cipher: Self::Cipher,
58 ) -> Result<DecryptionResult, DefaultError> {
59 match cipher {
60 DecrypterCipher::Aes256GcmSiv(config) => {
61 tracing::info!("Decrypting: Aes256GcmSiv");
62
63 let salt = String::from_utf8(input.salt().clone())?;
65 let salt = SaltString::from_b64(salt.as_str()).expect("salt is base64 encoded");
66
67 let nonce = Nonce::from_slice(input.nonce());
68 let ciphertext = input.ciphertext();
69
70 let hasher = super::hasher::pbkdf2::Hasher::hash(
72 "password",
73 &config.hash_rounds,
74 config.hash_algorithm,
75 Some(salt),
76 )
77 .unwrap();
78
79 let key = hex::decode(hasher.hash().as_str()).unwrap();
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}