encrypted_json_kv/
crypto.rs1use serde::{
19 de::{self, Deserialize, Deserializer, Visitor},
20 ser::{Serialize, Serializer},
21};
22use serde_json::Value;
23
24use sodiumoxide::crypto::{pwhash, secretbox};
25
26use thiserror::Error;
27
28use std::fmt;
29
30pub(crate) fn derive_key(passphrase: &[u8], salt: pwhash::Salt) -> secretbox::Key {
33 let mut key = secretbox::Key([0; secretbox::KEYBYTES]);
34 {
35 let secretbox::Key(ref mut key_bytes) = key;
36 pwhash::derive_key(
37 key_bytes,
38 passphrase,
39 &salt,
40 pwhash::OPSLIMIT_INTERACTIVE,
41 pwhash::MEMLIMIT_INTERACTIVE,
42 )
43 .unwrap();
44 }
45 key
46}
47
48#[derive(Debug, Clone)]
49pub struct EncryptedValue {
52 nonce: secretbox::Nonce,
53 ciphertext: Vec<u8>,
54}
55
56impl Serialize for EncryptedValue {
57 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58 where
59 S: Serializer,
60 {
61 serializer.serialize_str(&format!(
62 "{}_{}",
63 base64::encode(self.nonce.as_ref()),
64 base64::encode(&self.ciphertext)
65 ))
66 }
67}
68struct EncryptedValueVisitor;
69
70impl<'de> Visitor<'de> for EncryptedValueVisitor {
71 type Value = EncryptedValue;
72
73 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74 formatter.write_str("a string with two base64 encoded values separated with an underscore")
75 }
76
77 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
78 where
79 E: de::Error,
80 {
81 let parts: Vec<&str> = s.split("_").collect();
82 if parts.len() != 2 {
83 return Err(E::custom(format!(
84 "expected two base64 encoded values separated with an underscore, got {}",
85 parts.len()
86 )));
87 }
88 let (nonce, ciphertext) = match (base64::decode(parts[0]), base64::decode(parts[1])) {
89 (Ok(nonce), Ok(ciphertext)) => {
90 let nonce = secretbox::Nonce::from_slice(&nonce)
91 .ok_or_else(|| E::custom(format!("nonce part was not 24 bits long")))?;
92 (nonce, ciphertext)
93 }
94 _ => Err(E::custom(format!("couldn't decode one of the bas64 parts")))?,
95 };
96 Ok(EncryptedValue { nonce, ciphertext })
97 }
98}
99
100impl<'de> Deserialize<'de> for EncryptedValue {
101 fn deserialize<D>(deserializer: D) -> Result<EncryptedValue, D::Error>
102 where
103 D: Deserializer<'de>,
104 {
105 deserializer.deserialize_str(EncryptedValueVisitor)
106 }
107}
108
109impl EncryptedValue {
110 pub fn encrypt(value: &Value, key: &secretbox::Key) -> Self {
113 let plaintext = serde_json::to_vec(value).unwrap();
117 let nonce = secretbox::gen_nonce();
118 Self {
119 nonce,
120 ciphertext: secretbox::seal(&plaintext, &nonce, key),
121 }
122 }
123
124 pub fn decrypt(&self, key: &secretbox::Key) -> Result<Value, EncryptionError> {
126 let plaintext = secretbox::open(&self.ciphertext, &self.nonce, key)
127 .map_err(|_| EncryptionError::WrongKey)?;
128 Ok(serde_json::from_slice(&plaintext)?)
129 }
130}
131
132#[derive(Error, Debug)]
133pub enum EncryptionError {
134 #[error("can't decrypt the ciphertext with the given key")]
135 WrongKey,
136 #[error("couldn't deserialize the value")]
137 Serde(#[from] serde_json::Error),
138}
139