authnz_common/types/keys/
encryption.rs1#[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)]
10pub 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 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 pub fn encrypt(&self, message: &impl serde::Serialize) -> MResult<(Vec<u8>, Vec<u8>)> {
128 self.inner.encrypt(message)
129 }
130
131 pub fn decrypt<T: serde::de::DeserializeOwned>(&self, ciphertext: &[u8], nonce: &[u8]) -> MResult<T> {
133 self.inner.decrypt(ciphertext, nonce)
134 }
135
136 pub fn pack(&self) -> Vec<u8> {
138 self.inner.pack()
139 }
140
141 pub fn unpack(key: impl AsRef<[u8]>) -> MResult<Self> {
143 Ok(CipherKey {
144 inner: InnerCipherKey::unpack(key)?,
145 })
146 }
147}