Skip to main content

authnz_common/types/keys/
encryption.rs

1//! Encryption module.
2
3#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
4use crate::{MResult, ServerError};
5
6#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
7use crate::{CResult, ClientError};
8
9#[derive(Clone)]
10/// Encryption key.
11pub struct CipherKey {
12  inner: InnerCipherKey,
13}
14
15#[non_exhaustive]
16#[derive(Clone)]
17enum InnerCipherKey {
18  Chacha20Poly1305([u8; 32]),
19}
20
21impl InnerCipherKey {
22  fn encrypt(&self, message: &impl serde::Serialize) -> MResult<(Vec<u8>, Vec<u8>)> {
23    #[allow(unreachable_patterns)]
24    match self {
25      Self::Chacha20Poly1305(key) => {
26        use chacha20poly1305::{
27          ChaCha20Poly1305,
28          aead::{Aead, AeadCore, KeyInit, OsRng, generic_array::GenericArray},
29          consts::U32,
30        };
31
32        let serialized = rmp_serde::to_vec(message).map_err(|e| {
33          ServerError::from_private(e)
34            .with_private_str("Can't serialize data to encrypt!")
35            .with_500()
36        })?;
37        let key = GenericArray::<u8, U32>::from_slice(key);
38        let cipher = ChaCha20Poly1305::new(key);
39        let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
40        let ciphertext = cipher.encrypt(&nonce, serialized.as_ref()).map_err(|e| {
41          ServerError::from_private_str(e.to_string())
42            .with_private_str("Can't encrypt given data!")
43            .with_500()
44        })?;
45        Ok((ciphertext, nonce.to_vec()))
46      }
47      _ => unreachable!(),
48    }
49  }
50
51  fn decrypt<T: serde::de::DeserializeOwned>(&self, ciphertext: &[u8], nonce: &[u8]) -> MResult<T> {
52    #[allow(unreachable_patterns)]
53    match self {
54      Self::Chacha20Poly1305(key) => {
55        use chacha20poly1305::{
56          ChaCha20Poly1305,
57          aead::{Aead, KeyInit, generic_array::GenericArray},
58          consts::{U12, U32},
59        };
60
61        let key = GenericArray::<u8, U32>::from_slice(key);
62        let cipher = ChaCha20Poly1305::new(key);
63        let nonce = GenericArray::<u8, U12>::from_slice(nonce);
64        let plaintext = cipher.decrypt(nonce, ciphertext).map_err(|e| {
65          ServerError::from_private_str(e.to_string())
66            .with_private_str("Can't decrypt given ciphertext!")
67            .with_500()
68        })?;
69        let deserialized = rmp_serde::from_slice::<T>(plaintext.as_slice()).map_err(|e| {
70          ServerError::from_private(e)
71            .with_private_str("Can't deserialize decrypted data!")
72            .with_500()
73        })?;
74        Ok(deserialized)
75      }
76      _ => unreachable!(),
77    }
78  }
79
80  fn pack(&self) -> Vec<u8> {
81    #[allow(unreachable_patterns)]
82    match self {
83      Self::Chacha20Poly1305(key) => {
84        let mut packed = b"chacha20poly1305::".to_vec();
85        packed.extend_from_slice(key);
86        packed
87      }
88      _ => unreachable!(),
89    }
90  }
91
92  fn unpack(key: impl AsRef<[u8]>) -> MResult<Self> {
93    if key.as_ref().starts_with(b"chacha20poly1305::") {
94      use std::mem::MaybeUninit;
95
96      let key = &key.as_ref()[b"chacha20poly1305::".len()..];
97      if key.len() != 32 {
98        return Err(ServerError::from_private_str("Invalid encryption key length!").with_500());
99      }
100
101      let buffer: [MaybeUninit<u8>; 32] = unsafe { MaybeUninit::uninit().assume_init() };
102      let mut buffer = unsafe { std::mem::transmute::<[MaybeUninit<u8>; 32], [u8; 32]>(buffer) };
103      buffer.copy_from_slice(key);
104
105      return Ok(Self::Chacha20Poly1305(buffer));
106    }
107
108    Err(ServerError::from_private_str("Invalid packed key format!").with_500())
109  }
110}
111
112impl CipherKey {
113  /// Generates an encryption (`ChaCha20Poly1305`) key.
114  pub fn new_chacha20poly1305() -> Self {
115    use rand::Rng;
116
117    let mut arr: [u8; 32] = [0; 32];
118    let mut rng = rand::rng();
119    rng.fill(arr.as_mut_slice());
120
121    Self {
122      inner: InnerCipherKey::Chacha20Poly1305(arr),
123    }
124  }
125
126  /// Encrypts serializable `message` by encryption key, providing `ciphertext` and its `nonce`.
127  pub fn encrypt(&self, message: &impl serde::Serialize) -> MResult<(Vec<u8>, Vec<u8>)> {
128    self.inner.encrypt(message)
129  }
130
131  /// Decrypts deserializable message from `ciphertext`, its `nonce` and provided key.
132  pub fn decrypt<T: serde::de::DeserializeOwned>(&self, ciphertext: &[u8], nonce: &[u8]) -> MResult<T> {
133    self.inner.decrypt(ciphertext, nonce)
134  }
135
136  /// Packs encryption key.
137  pub fn pack(&self) -> Vec<u8> {
138    self.inner.pack()
139  }
140
141  /// Unpacks encryption key.
142  pub fn unpack(key: impl AsRef<[u8]>) -> MResult<Self> {
143    Ok(CipherKey {
144      inner: InnerCipherKey::unpack(key)?,
145    })
146  }
147}