redact_crypto/nonce/
sodiumoxide.rs

1use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
2use sodiumoxide::crypto::{
3    box_::{self, Nonce as ExternalAsymmetricNonce, NONCEBYTES as EXTERNALASYMMETRICNONCEBYTES},
4    secretbox::{self, Nonce as ExternalSymmetricNonce, NONCEBYTES as EXTERNALSYMMETRICNONCEBYTES},
5};
6
7#[derive(Serialize, Deserialize, Debug, Clone)]
8pub struct SodiumOxideSymmetricNonce {
9    #[serde(
10        serialize_with = "symmetric_nonce_serialize",
11        deserialize_with = "symmetric_nonce_deserialize"
12    )]
13    pub nonce: ExternalSymmetricNonce,
14}
15
16/// Custom serialization function base64-encodes the bytes before storage
17fn symmetric_nonce_serialize<S>(nonce: &ExternalSymmetricNonce, s: S) -> Result<S::Ok, S::Error>
18where
19    S: Serializer,
20{
21    let b64_encoded = base64::encode(nonce.as_ref());
22    s.serialize_some(&Some(b64_encoded))
23}
24
25/// Custom deserialization function base64-decodes the bytes before passing them back
26fn symmetric_nonce_deserialize<'de, D>(deserializer: D) -> Result<ExternalSymmetricNonce, D::Error>
27where
28    D: Deserializer<'de>,
29{
30    let b64_encoded: String = de::Deserialize::deserialize(deserializer)?;
31    let decoded = base64::decode(b64_encoded).map_err(de::Error::custom)?;
32    let nonce = ExternalSymmetricNonce::from_slice(decoded.as_ref());
33    match nonce {
34        Some(n) => Ok(n),
35        None => Err(de::Error::custom(format!(
36            "deserialized nonce was {} bytes long, expected 24 bytes",
37            decoded.len()
38        ))),
39    }
40}
41
42impl SodiumOxideSymmetricNonce {
43    pub const NONCEBYTES: usize = EXTERNALSYMMETRICNONCEBYTES;
44
45    pub fn from_slice(bs: &[u8]) -> Option<Self> {
46        Some(SodiumOxideSymmetricNonce {
47            nonce: ExternalSymmetricNonce::from_slice(bs)?,
48        })
49    }
50
51    pub fn new() -> Self {
52        SodiumOxideSymmetricNonce {
53            nonce: secretbox::gen_nonce(),
54        }
55    }
56}
57
58#[derive(Serialize, Deserialize, Debug, Clone)]
59pub struct SodiumOxideAsymmetricNonce {
60    #[serde(
61        serialize_with = "asymmetric_nonce_serialize",
62        deserialize_with = "asymmetric_nonce_deserialize"
63    )]
64    pub nonce: ExternalAsymmetricNonce,
65}
66
67/// Custom serialization function base64-encodes the bytes before storage
68fn asymmetric_nonce_serialize<S>(nonce: &ExternalAsymmetricNonce, s: S) -> Result<S::Ok, S::Error>
69where
70    S: Serializer,
71{
72    let b64_encoded = base64::encode(nonce.as_ref());
73    s.serialize_some(&Some(b64_encoded))
74}
75
76/// Custom deserialization function base64-decodes the bytes before passing them back
77fn asymmetric_nonce_deserialize<'de, D>(
78    deserializer: D,
79) -> Result<ExternalAsymmetricNonce, D::Error>
80where
81    D: Deserializer<'de>,
82{
83    let b64_encoded: String = de::Deserialize::deserialize(deserializer)?;
84    let decoded = base64::decode(b64_encoded).map_err(de::Error::custom)?;
85    let nonce = ExternalAsymmetricNonce::from_slice(decoded.as_ref());
86    match nonce {
87        Some(n) => Ok(n),
88        None => Err(de::Error::custom(format!(
89            "deserialized nonce was {} bytes long, expected 24 bytes",
90            decoded.len()
91        ))),
92    }
93}
94
95impl SodiumOxideAsymmetricNonce {
96    pub const NONCEBYTES: usize = EXTERNALASYMMETRICNONCEBYTES;
97
98    pub fn from_slice(bs: &[u8]) -> Option<Self> {
99        Some(SodiumOxideAsymmetricNonce {
100            nonce: ExternalAsymmetricNonce::from_slice(bs)?,
101        })
102    }
103
104    pub fn new() -> Self {
105        SodiumOxideAsymmetricNonce {
106            nonce: box_::gen_nonce(),
107        }
108    }
109}