dexios_core/cipher.rs
1//! This module is used for standard, typical encryption and decryption.
2//!
3//! The data is fully loaded into memory before encryption/decryption, and it is processed within the same "block"
4//!
5//! # Examples
6//! ```rust,ignore
7//! // obviously the key should contain data, not be an empty vec
8//! let raw_key = Protected::new(vec![0u8; 128]);
9//! let salt = gen_salt();
10//! let key = balloon_hash(raw_key, &salt, &HeaderVersion::V4).unwrap();
11//! let cipher = Ciphers::initialize(key, &Algorithm::XChaCha20Poly1305).unwrap();
12//!
13//! let secret = "super secret information";
14//!
15//! let nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::MemoryMode);
16//! let encrypted_data = cipher.encrypt(&nonce, secret.as_bytes()).unwrap();
17//!
18//! let decrypted_data = cipher.decrypt(&nonce, encrypted_data.as_slice()).unwrap();
19//!
20//! assert_eq!(secret, decrypted_data);
21//! ```
22
23use aead::{Aead, AeadInPlace, KeyInit, Payload};
24use aes_gcm::Aes256Gcm;
25use chacha20poly1305::XChaCha20Poly1305;
26use deoxys::DeoxysII256;
27
28use crate::primitives::Algorithm;
29use crate::protected::Protected;
30
31/// This `enum` defines all possible cipher types, for each AEAD that is supported by `dexios-core`
32pub enum Ciphers {
33 Aes256Gcm(Box<Aes256Gcm>),
34 XChaCha(Box<XChaCha20Poly1305>),
35 DeoxysII(Box<DeoxysII256>),
36}
37
38impl Ciphers {
39 /// This can be used to quickly initialise a `Cipher`
40 ///
41 /// The returned `Cipher` can be used for both encryption and decryption
42 ///
43 /// You just need to provide the `argon2id`/`balloon` hashed key, and the algorithm to use
44 ///
45 /// # Examples
46 /// ```rust,ignore
47 /// // obviously the key should contain data, not be an empty vec
48 /// let raw_key = Protected::new(vec![0u8; 128]);
49 /// let salt = gen_salt();
50 /// let key = balloon_hash(raw_key, &salt, &HeaderVersion::V4).unwrap();
51 /// let cipher = Ciphers::initialize(key, &Algorithm::XChaCha20Poly1305).unwrap();
52 /// ```
53 ///
54 pub fn initialize(key: Protected<[u8; 32]>, algorithm: &Algorithm) -> anyhow::Result<Self> {
55 let cipher = match algorithm {
56 Algorithm::Aes256Gcm => {
57 let cipher = Aes256Gcm::new_from_slice(key.expose())
58 .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;
59
60 Ciphers::Aes256Gcm(Box::new(cipher))
61 }
62 Algorithm::XChaCha20Poly1305 => {
63 let cipher = XChaCha20Poly1305::new_from_slice(key.expose())
64 .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;
65
66 Ciphers::XChaCha(Box::new(cipher))
67 }
68 Algorithm::DeoxysII256 => {
69 let cipher = DeoxysII256::new_from_slice(key.expose())
70 .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;
71
72 Ciphers::DeoxysII(Box::new(cipher))
73 }
74 };
75
76 drop(key);
77 Ok(cipher)
78 }
79
80 /// This can be used to encrypt data with a given `Ciphers` object
81 ///
82 /// It requires the nonce, and either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD)
83 pub fn encrypt<'msg, 'aad>(
84 &self,
85 nonce: &[u8],
86 plaintext: impl Into<Payload<'msg, 'aad>>,
87 ) -> aead::Result<Vec<u8>> {
88 match self {
89 Ciphers::Aes256Gcm(c) => c.encrypt(nonce.as_ref().into(), plaintext),
90 Ciphers::XChaCha(c) => c.encrypt(nonce.as_ref().into(), plaintext),
91 Ciphers::DeoxysII(c) => c.encrypt(nonce.as_ref().into(), plaintext),
92 }
93 }
94
95 pub fn encrypt_in_place(
96 &self,
97 nonce: &[u8],
98 aad: &[u8],
99 buffer: &mut dyn aead::Buffer,
100 ) -> Result<(), aead::Error> {
101 match self {
102 Ciphers::Aes256Gcm(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
103 Ciphers::XChaCha(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
104 Ciphers::DeoxysII(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
105 }
106 }
107
108 /// This can be used to decrypt data with a given `Ciphers` object
109 ///
110 /// It requires the nonce used for encryption, and either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD)
111 ///
112 /// NOTE: The data will not decrypt successfully if an AAD was provided for encryption, but is not present/has been modified while decrypting
113 pub fn decrypt<'msg, 'aad>(
114 &self,
115 nonce: &[u8],
116 ciphertext: impl Into<Payload<'msg, 'aad>>,
117 ) -> aead::Result<Vec<u8>> {
118 match self {
119 Ciphers::Aes256Gcm(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
120 Ciphers::XChaCha(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
121 Ciphers::DeoxysII(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
122 }
123 }
124}