1use aes_gcm::Aes256Gcm;
2use aead::{Aead, NewAead, generic_array::GenericArray};
3use std::{fmt, error};
4use std::convert::{TryInto, TryFrom};
5
6#[derive(Debug, Clone)]
7pub enum InvalidKeyError {
8 InvalidKeySizeError,
9 InvalidKeyBase64Error
10}
11
12impl fmt::Display for InvalidKeyError {
13 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
14 match self {
15 InvalidKeyError::InvalidKeySizeError => write!(f, "{}", "Please provide a 32-byte, base64-encoded, key"),
16 InvalidKeyError::InvalidKeyBase64Error => write!(f, "{}", "Please provide a valid base64"),
17 }
18 }
19}
20
21impl error::Error for InvalidKeyError {
22 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
23 None
25 }
26}
27
28pub struct Key {
29 pub u8_array: [u8; 32]
30}
31
32impl TryFrom<&str> for Key {
33 type Error = InvalidKeyError;
34 fn try_from(base64_key: &str) -> Result<Self, InvalidKeyError> {
35 let key = match base64::decode(base64_key) {
36 Ok(data) => data,
37 Err(_) => return Err(InvalidKeyError::InvalidKeyBase64Error)
38 };
39
40 let u8_array: Result<[u8; 32], _> = key.as_slice().try_into();
41 match u8_array {
42 Ok(value) => Ok(Self {
43 u8_array: value
44 }),
45 Err(_) => Err(InvalidKeyError::InvalidKeySizeError)
46 }
47 }
48}
49
50impl TryFrom<String> for Key {
51 type Error = InvalidKeyError;
52 fn try_from(base64_key: String) -> Result<Self, InvalidKeyError> {
53 Self::try_from(&base64_key[..])
54 }
55}
56
57#[derive(Debug, Clone)]
58pub enum InvalidIvError {
59 InvalidIvSizeError,
60 InvalidIvBase64Error
61}
62
63
64impl fmt::Display for InvalidIvError {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 match self {
67 InvalidIvError::InvalidIvSizeError => write!(f, "{}", "Please provide a 12-byte, base64-encoded, iv"),
68 InvalidIvError::InvalidIvBase64Error => write!(f, "{}", "Please provide a valid base64"),
69 }
70 }
71}
72
73impl error::Error for InvalidIvError {
74 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
75 None
77 }
78}
79
80pub struct Iv {
81 pub u8_array: [u8; 12]
82}
83
84impl TryFrom<&str> for Iv {
85 type Error = InvalidIvError;
86 fn try_from(base64_iv: &str) -> Result<Iv, InvalidIvError> {
87 let iv = match base64::decode(base64_iv) {
88 Ok(data) => data,
89 Err(_) => return Err(InvalidIvError::InvalidIvBase64Error)
90 };
91
92 let u8_array: Result<[u8; 12], _> = iv.as_slice().try_into();
93 match u8_array {
94 Ok(value) => Ok(Iv {
95 u8_array: value
96 }),
97 Err(_) => Err(InvalidIvError::InvalidIvSizeError)
98 }
99 }
100}
101impl Iv {
102 pub fn generate() -> Iv {
103 Iv {
104 u8_array: rand::random::<[u8; 12]>()
105 }
106 }
107}
108
109impl From<&Iv> for String {
110 fn from(iv: &Iv) -> String {
111 base64::encode(&iv.u8_array)
112 }
113}
114
115impl fmt::Display for Iv {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 write!(f, "{}", String::from(self))
118 }
119}
120
121
122pub struct Encrypted {
123 pub u8_vec: Vec<u8>
124}
125
126impl TryFrom<&str> for Encrypted {
127 type Error = base64::DecodeError;
128 fn try_from(base64_encrypted: &str) -> Result<Encrypted, base64::DecodeError> {
129 Ok(Encrypted {
130 u8_vec: base64::decode(base64_encrypted)?
131 })
132 }
133}
134
135impl From<&Encrypted> for String {
136 fn from(encrypted: &Encrypted) -> String {
137 base64::encode(&encrypted.u8_vec)
138 }
139}
140
141impl fmt::Display for Encrypted {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(f, "{}", String::from(self))
144 }
145}
146
147pub struct Decrypted<'a> {
148 value: &'a str
149}
150impl<'a> From<&'a str> for Decrypted<'a> {
151 fn from(value: &'a str) -> Self {
152 Self { value: value }
153 }
154}
155
156impl From<&Decrypted<'_>> for String {
157 fn from(decrypted: &Decrypted<'_>) -> String {
158 String::from(decrypted.value)
159 }
160}
161
162impl<'a> fmt::Display for Decrypted<'a> {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 write!(f, "{}", String::from(self))
165 }
166}
167
168
169pub struct EncryptedAndIv {
170 pub encrypted: Encrypted,
171 pub iv: Iv
172}
173
174
175#[derive(Debug, Clone)]
176pub enum EncryptionError {
177 GenericEncryptionError
178}
179impl fmt::Display for EncryptionError {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 match self {
182 EncryptionError::GenericEncryptionError => write!(f, "{}", "Encryption error"),
183 }
184 }
185}
186
187impl error::Error for EncryptionError {
188 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
189 None
191 }
192}
193
194pub fn encrypt<'a>(key: &Key, decrypted: &Decrypted) -> Result<EncryptedAndIv, EncryptionError> {
195 let iv = Iv::generate();
196 let nonce = GenericArray::from_slice(&iv.u8_array);
197 let client = Aes256Gcm::new(GenericArray::clone_from_slice(&key.u8_array));
198 match client.encrypt(nonce, decrypted.value.as_bytes()) {
199 Ok(ciphertext) => Ok(EncryptedAndIv {
200 iv: iv,
201 encrypted: Encrypted {
202 u8_vec: ciphertext
203 }
204 }),
205 Err(_) => Err(EncryptionError::GenericEncryptionError)
206 }
207}
208
209#[derive(Debug, Clone)]
210pub enum DecryptionError {
211 InvalidUTF8DecryptionError,
212 GenericDecryptionError
213}
214impl fmt::Display for DecryptionError {
215 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216 match self {
217 DecryptionError::InvalidUTF8DecryptionError => write!(f, "{}", "Decryption error: invalid UTF-8"),
218 DecryptionError::GenericDecryptionError => write!(f, "{}", "Decryption error"),
219 }
220 }
221}
222
223impl error::Error for DecryptionError {
224 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
225 None
227 }
228}
229
230pub fn decrypt(key: &Key, encrypted_and_iv: EncryptedAndIv) -> Result<String, DecryptionError> {
231 let nonce = GenericArray::from_slice(&encrypted_and_iv.iv.u8_array);
232 let client = Aes256Gcm::new(GenericArray::clone_from_slice(&key.u8_array));
233
234 match client.decrypt(nonce, encrypted_and_iv.encrypted.u8_vec.as_ref()) {
235 Ok(decrypted_u8_vec) => match String::from_utf8(decrypted_u8_vec) {
236 Ok(decrypted_string) => Ok(decrypted_string),
237 Err(_) => Err(DecryptionError::InvalidUTF8DecryptionError)
238 },
239 Err(_) => Err(DecryptionError::GenericDecryptionError)
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 #[test]
247 fn key_try_from_invalid_base64_fails() {
248 match Key::try_from("012") {
249 Ok(_) => assert!(false),
250 Err(e) => match e {
251 InvalidKeyError::InvalidKeySizeError => assert!(false, "Should err an InvalidKeyError::InvalidKeyBase64Error"),
252 InvalidKeyError::InvalidKeyBase64Error => assert!(true)
253 }
254 }
255 }
256
257 #[test]
258 fn key_try_from_valid_3byte_fails() {
259 match Key::try_from("MDEy") {
260 Ok(_) => assert!(false),
261 Err(e) => match e {
262 InvalidKeyError::InvalidKeyBase64Error => assert!(false, "Should err an InvalidKeyError::InvalidKeySizeError"),
263 InvalidKeyError::InvalidKeySizeError => assert!(true)
264 }
265 }
266 }
267
268 #[test]
269 fn key_try_from_valid_33byte_fails() {
270 match Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEy") {
271 Ok(_) => assert!(false),
272 Err(e) => match e {
273 InvalidKeyError::InvalidKeyBase64Error => assert!(false, "Should err an InvalidKeyError::InvalidKeySizeError"),
274 InvalidKeyError::InvalidKeySizeError => assert!(true)
275 }
276 }
277 }
278
279 #[test]
280 fn key_try_from_valid_32_bytes_succeeds() {
281 match Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=") {
282 Err(_) => assert!(false, "Should succeed"),
283 Ok(key) => assert_eq!(key.u8_array, [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49])
284 }
285 }
286
287 #[test]
288 fn iv_try_from_invalid_base64_fails() {
289 match Iv::try_from("012") {
290 Ok(_) => assert!(false),
291 Err(e) => match e {
292 InvalidIvError::InvalidIvSizeError => assert!(false, "Should err an InvalidIvError::InvalidIvBase64Error"),
293 InvalidIvError::InvalidIvBase64Error => assert!(true)
294 }
295 }
296 }
297
298 #[test]
299 fn iv_try_from_valid_3byte_fails() {
300 match Iv::try_from("YWJj") {
301 Ok(_) => assert!(false),
302 Err(e) => match e {
303 InvalidIvError::InvalidIvBase64Error => assert!(false, "Should err an InvalidIvError::InvalidIvSizeError"),
304 InvalidIvError::InvalidIvSizeError => assert!(true)
305 }
306 }
307 }
308
309 #[test]
310 fn iv_try_from_valid_13byte_fails() {
311 match Iv::try_from("MDEyMzQ1Njc4OTAxMg==") {
312 Ok(_) => assert!(false),
313 Err(e) => match e {
314 InvalidIvError::InvalidIvBase64Error => assert!(false, "Should err an InvalidIvError::InvalidIvSizeError"),
315 InvalidIvError::InvalidIvSizeError => assert!(true)
316 }
317 }
318 }
319
320 #[test]
321 fn iv_try_from_valid_12byte_succeeds() {
322 match Iv::try_from("MDEyMzQ1Njc4OTAx") {
323 Err(_) => assert!(false, "Should succeeds"),
324 Ok(iv) => assert_eq!(iv.u8_array, [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49])
325 }
326 }
327
328 #[test]
329 fn iv_generate() {
330 assert!(
331 Iv::generate().u8_array != Iv::generate().u8_array,
332 "Should generate almost unique values"
333 )
334 }
335
336 #[test]
337 fn iv_format() {
338 assert_eq!(
339 format!("{}", Iv::try_from("MDEyMzQ1Njc4OTAx").unwrap()),
340 "MDEyMzQ1Njc4OTAx"
341 )
342 }
343
344 #[test]
345 fn encrypted_from64_invalid_base64() {
346 match Encrypted::try_from("aaaaaaa") {
347 Ok(_) => assert!(false, "Should err"),
348 Err(_) => assert!(true)
349 }
350 }
351
352 #[test]
353 fn encrypted_from64_valid_base64() {
354 match Encrypted::try_from("YWFhYWFhYQ==") {
355 Err(_) => assert!(false, "Should ok"),
356 Ok(encryped) => assert_eq!(encryped.u8_vec, vec![97, 97, 97, 97, 97, 97, 97])
357 }
358 }
359
360 #[test]
361 fn encrypted_format() {
362 assert_eq!(
363 format!("{}", Encrypted::try_from("YWFhYWFhYQ==").unwrap()),
364 "YWFhYWFhYQ=="
365 )
366 }
367
368 #[test]
380 fn encrypted_values_are_different_for_same_inputs() {
381 let encrypted_1 = encrypt(
382 &Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=").unwrap(),
383 &Decrypted::from("This is a text.")
384 ).unwrap();
385 let encrypted_2 = encrypt(
386 &Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=").unwrap(),
387 &Decrypted::from("This is a text.")
388 ).unwrap();
389 assert!(encrypted_1.encrypted.u8_vec != encrypted_2.encrypted.u8_vec)
390 }
391
392 #[test]
393 fn encrypted_values_are_different_for_different_inputs() {
394 let encrypted_1 = encrypt(
395 &Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=").unwrap(),
396 &Decrypted::from("This is a text.")
397 ).unwrap();
398 let encrypted_2 = encrypt(
399 &Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=").unwrap(),
400 &Decrypted::from("This is another text.")
401 ).unwrap();
402 assert!(encrypted_1.encrypted.u8_vec != encrypted_2.encrypted.u8_vec)
403 }
404
405 #[test]
406 fn encrypt_decrypt_is_iso() {
407 let key = Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=").unwrap();
408 let encrypted = encrypt(
409 &key,
410 &Decrypted::from("This is a text.")
411 ).unwrap();
412
413 assert_eq!(decrypt(&key, encrypted).unwrap(), String::from("This is a text."))
414 }
415
416 #[test]
417 fn encrypt_decrypt_is_iso_with_string_key() {
418 let key = Key::try_from(String::from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=")).unwrap();
419 let encrypted = encrypt(
420 &key,
421 &Decrypted::from("This is a text.")
422 ).unwrap();
423
424 assert_eq!(decrypt(&key, encrypted).unwrap(), String::from("This is a text."))
425 }
426
427 #[test]
428 fn decrypt_fails_when_non_utf8() {
429 let key = Key::try_from("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=").unwrap();
430
431 let iv = Iv::generate();
432 let nonce = GenericArray::from_slice(&iv.u8_array);
433 let client = Aes256Gcm::new(GenericArray::clone_from_slice(&key.u8_array));
434 let invalid_utf8_bytes: &[u8] = &[133u8, 133u8];
435 let ciphertext = client.encrypt(nonce, invalid_utf8_bytes).unwrap();
436
437 let encrypted_and_iv = EncryptedAndIv {
438 iv: iv,
439 encrypted: Encrypted {
440 u8_vec: ciphertext
441 }
442 };
443
444 match decrypt(&key, encrypted_and_iv) {
445 Ok(_) => assert!(false, "Should err InvalidUTF8DecryptionError"),
446 Err(e) => match e {
447 DecryptionError::GenericDecryptionError => assert!(false, "Should err InvalidUTF8DecryptionError"),
448 DecryptionError::InvalidUTF8DecryptionError => assert!(true)
449 }
450 }
451 }
452
453 }