serde_crypt/
lib.rs

1#![forbid(unsafe_code)]
2
3//! The end-to-end encrypted `serde::Serializer` and `serde::Deserializer`.
4//! **wasm-ready**.
5//!
6//! ## Example
7//!
8//! ```rust
9//! use ring::rand::{SecureRandom, SystemRandom};
10//! use serde::{Deserialize, Serialize};
11//! use serde_crypt::{setup};
12//!
13//! #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
14//! struct Example {
15//!     #[serde(with = "serde_crypt")]
16//!     private: String,
17//!     public: String,
18//! }
19//!
20//! let mut key: [u8; 256] = [0; 256];
21//! let rand_gen = SystemRandom::new();
22//! rand_gen.fill(&mut key).unwrap();
23//!
24//! setup(key.to_vec());
25//! let data = Example {
26//!     private: "private data".to_string(),
27//!     public: "public data".to_string(),
28//! };
29//!
30//! let serialized = serde_json::to_string(&data).unwrap();
31//! let deserialized: Example = serde_json::from_str(&serialized).unwrap();
32//!
33//! assert_eq!(deserialized, data);
34//! ```
35//!
36
37use std::error::Error;
38use std::fmt::Display;
39use std::sync::Mutex;
40
41use base64::engine::general_purpose;
42use base64::Engine;
43use once_cell::sync::Lazy;
44use ring::aead::{
45    Aad, BoundKey, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey, AES_256_GCM, NONCE_LEN,
46};
47use ring::digest::{self, digest};
48use ring::error::{self, Unspecified};
49use ring::rand::{SecureRandom, SystemRandom};
50use serde::de::DeserializeOwned;
51use serde::{Deserialize, Serialize};
52use serde::{Deserializer, Serializer};
53
54static MASTER_KEY: Lazy<Mutex<Vec<u8>>> = Lazy::new(|| Mutex::new(vec![]));
55
56#[allow(dead_code)]
57pub fn serialize<S: Serializer, T: Serialize>(v: T, s: S) -> Result<S::Ok, S::Error> {
58    let base64 = e(v).map_err(serde::ser::Error::custom)?;
59    String::serialize(&base64, s)
60}
61
62#[allow(dead_code)]
63pub fn deserialize<'de, D: Deserializer<'de>, T: DeserializeOwned>(de: D) -> Result<T, D::Error> {
64    let base64 = String::deserialize(de)?;
65    d(base64).map_err(serde::de::Error::custom)
66}
67
68pub fn setup(master_key: Vec<u8>) {
69    *MASTER_KEY.lock().unwrap() = master_key;
70}
71
72pub fn e<T: Serialize>(source: T) -> Result<String, Box<dyn Error>> {
73    let nonce = generate_random_nonce();
74    let serialized = serde_json::to_string(&source).map(|t| t.as_bytes().to_vec())?;
75    let mut encrypted = encrypt(serialized, nonce)?;
76    let mut nonce_encrypted = nonce.to_vec();
77    nonce_encrypted.append(&mut encrypted);
78    Ok(general_purpose::URL_SAFE_NO_PAD.encode(nonce_encrypted))
79}
80
81pub fn d<T: DeserializeOwned>(source: String) -> Result<T, Box<dyn Error>> {
82    let decoded = general_purpose::URL_SAFE_NO_PAD.decode(source.as_bytes())?;
83    let nonce = decoded[..NONCE_LEN].try_into().unwrap();
84    let data = decoded[NONCE_LEN..].to_vec();
85    let decrypted = decrypt(data, nonce)?;
86    let decrypted = std::str::from_utf8(&decrypted)?;
87    Ok(serde_json::from_str(decrypted)?)
88}
89
90fn encrypt(mut data: Vec<u8>, nonce: [u8; NONCE_LEN]) -> Result<Vec<u8>, Box<dyn Error>> {
91    let key = MASTER_KEY.lock().unwrap();
92    let (key, nonce) = prepare_key(&key, nonce);
93    let mut encryption_key = SealingKey::new(key, nonce);
94    encryption_key
95        .seal_in_place_append_tag(Aad::empty(), &mut data)
96        .map_err(|e| CryptError::EncryptionError(e))?;
97
98    Ok(data)
99}
100
101fn decrypt(mut data: Vec<u8>, nonce: [u8; NONCE_LEN]) -> Result<Vec<u8>, Box<dyn Error>> {
102    let key = MASTER_KEY.lock().unwrap();
103    let (key, nonce) = prepare_key(&key, nonce);
104    let mut decryption_key = OpeningKey::new(key, nonce);
105    decryption_key
106        .open_in_place(Aad::empty(), &mut data)
107        .map_err(|e| CryptError::DecryptionError(e))?;
108    let length = data.len() - AES_256_GCM.tag_len();
109
110    Ok(data[..length].to_vec())
111}
112
113#[derive(Debug)]
114pub enum CryptError {
115    DecryptionError(Unspecified),
116    EncryptionError(Unspecified),
117}
118
119impl Display for CryptError {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        match self {
122            Self::DecryptionError(e) => e.fmt(f),
123            Self::EncryptionError(e) => e.fmt(f),
124        }
125    }
126}
127
128impl Error for CryptError {}
129
130struct INonceSequence(Option<Nonce>);
131
132impl INonceSequence {
133    fn new(nonce: Nonce) -> Self {
134        Self(Some(nonce))
135    }
136}
137
138impl NonceSequence for INonceSequence {
139    fn advance(&mut self) -> Result<Nonce, error::Unspecified> {
140        self.0.take().ok_or(error::Unspecified)
141    }
142}
143
144fn generate_random_nonce() -> [u8; NONCE_LEN] {
145    let rand_gen = SystemRandom::new();
146    let mut raw_nonce = [0u8; NONCE_LEN];
147    rand_gen.fill(&mut raw_nonce).unwrap();
148    raw_nonce
149}
150
151fn prepare_key(key: &Vec<u8>, nonce: [u8; NONCE_LEN]) -> (UnboundKey, INonceSequence) {
152    let digest = digest(&digest::SHA256, key.as_slice());
153    let key = digest.as_ref();
154    let nonce_sequence = INonceSequence::new(Nonce::assume_unique_for_key(nonce));
155    (UnboundKey::new(&AES_256_GCM, key).unwrap(), nonce_sequence)
156}
157
158#[cfg(test)]
159mod test {
160    use ring::rand::{SecureRandom, SystemRandom};
161    use serde::{Deserialize, Serialize};
162
163    use crate::setup;
164
165    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
166    struct Other {
167        #[serde(with = "crate")]
168        field: Vec<u8>,
169        plain: String,
170    }
171
172    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
173    struct Test {
174        #[serde(with = "crate")]
175        field: Vec<u8>,
176        #[serde(with = "crate")]
177        other: Other,
178        plain: String,
179    }
180
181    #[test]
182    fn flow() -> Result<(), serde_json::Error> {
183        let mut key: [u8; 256] = [0; 256];
184        let rand_gen = SystemRandom::new();
185        rand_gen.fill(&mut key).unwrap();
186
187        setup(key.to_vec());
188        let instance = Test {
189            field: "a secret message".as_bytes().to_vec(),
190            other: Other {
191                field: "another secret message".as_bytes().to_vec(),
192                plain: "this is a plain nested string".to_string(),
193            },
194            plain: "this is a plain string".to_string(),
195        };
196
197        let serialized = serde_json::to_string(&instance)?;
198        let deserialized: Test = serde_json::from_str(&serialized)?;
199
200        assert_eq!(deserialized, instance);
201        Ok(())
202    }
203
204    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
205    struct Example {
206        #[serde(with = "crate")]
207        private: String,
208        public: String,
209    }
210
211    #[test]
212    fn readme() -> Result<(), serde_json::Error> {
213        let mut key: [u8; 256] = [0; 256];
214        let rand_gen = SystemRandom::new();
215        rand_gen.fill(&mut key).unwrap();
216
217        setup(key.to_vec());
218        let data = Example {
219            private: "private data".to_string(),
220            public: "public data".to_string(),
221        };
222
223        let serialized = serde_json::to_string(&data)?;
224        let deserialized: Example = serde_json::from_str(&serialized)?;
225
226        assert_eq!(deserialized, data);
227        Ok(())
228    }
229}