Skip to main content

wireguard_conf/keys/
preshared.rs

1use core::fmt;
2
3use base64::prelude::*;
4use rand::Rng;
5use zeroize::{Zeroize, ZeroizeOnDrop};
6
7use crate::WireguardError;
8
9/// Preshared key.
10///
11/// Wrapper around `[u8; 32]`.
12///
13/// # Implements
14///
15/// - Implements [`Zeroize`] and [`ZeroizeOnDrop`] for clearing secrets from memory.
16/// - Implements [`TryFrom<&str>`] or [`TryFrom<String>`] for importing key from Base64 format.
17/// - Implements [`fmt::Display`] for exporting key in Wireguard's format.
18/// - Implements [`fmt::Debug`].
19///
20/// # Examples
21///
22/// ```
23/// # use wireguard_conf::prelude::*;
24/// # fn main() -> WireguardResult<()> {
25/// // generate new preshared key:
26/// let preshared_key = PresharedKey::random();
27///
28/// // import key:
29/// let imported_key = PresharedKey::try_from("MA4zR0tvQpZ4CQ7gs/KcAVMNMGIFBtDcfpjBr+0GwHY=")?;
30///
31/// // export key via `fmt::Display` trait:
32/// let exported_key = imported_key.to_string();
33///
34/// assert_eq!(exported_key, "MA4zR0tvQpZ4CQ7gs/KcAVMNMGIFBtDcfpjBr+0GwHY=".to_string());
35/// # Ok(())
36/// # }
37/// ```
38#[derive(Clone, PartialEq, Zeroize, ZeroizeOnDrop)]
39pub struct PresharedKey([u8; 32]);
40
41impl PresharedKey {
42    /// Generate random [`PresharedKey`].
43    #[must_use]
44    pub fn random() -> Self {
45        let mut key = [0u8; 32];
46        rand::rng().fill_bytes(&mut key);
47        Self(key)
48    }
49}
50
51impl PresharedKey {
52    /// Convert [`PresharedKey`] into byte array.
53    #[inline]
54    #[must_use]
55    pub fn to_bytes(&self) -> [u8; 32] {
56        self.0
57    }
58
59    /// Get [`PresharedKey`] as reference to bytes.
60    #[inline]
61    #[must_use]
62    pub fn as_bytes(&self) -> &[u8; 32] {
63        &self.0
64    }
65}
66
67impl fmt::Debug for PresharedKey {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        f.debug_tuple("PresharedKey")
70            .field(&self.to_string())
71            .finish()
72    }
73}
74
75/// Export [`PresharedKey`] as base64 format for Wireguard.
76impl fmt::Display for PresharedKey {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "{}", BASE64_STANDARD.encode(self.as_bytes()))
79    }
80}
81
82impl From<[u8; 32]> for PresharedKey {
83    fn from(value: [u8; 32]) -> Self {
84        Self(value)
85    }
86}
87
88impl TryFrom<&str> for PresharedKey {
89    type Error = WireguardError;
90
91    fn try_from(value: &str) -> Result<Self, Self::Error> {
92        let bytes: [u8; 32] = BASE64_STANDARD
93            .decode(value)
94            .map_err(|_| WireguardError::InvalidPresharedKey)?
95            .try_into()
96            .map_err(|_| WireguardError::InvalidPresharedKey)?;
97
98        Ok(Self(bytes))
99    }
100}
101
102impl TryFrom<String> for PresharedKey {
103    type Error = WireguardError;
104
105    fn try_from(value: String) -> Result<Self, Self::Error> {
106        Self::try_from(value.as_str())
107    }
108}
109
110#[cfg(feature = "serde")]
111mod serde_impl {
112    use super::PresharedKey;
113    use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
114
115    impl Serialize for PresharedKey {
116        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117        where
118            S: Serializer,
119        {
120            if serializer.is_human_readable() {
121                serializer.serialize_str(&self.to_string())
122            } else {
123                serializer.serialize_bytes(self.as_bytes())
124            }
125        }
126    }
127
128    impl<'de> Deserialize<'de> for PresharedKey {
129        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130        where
131            D: Deserializer<'de>,
132        {
133            if deserializer.is_human_readable() {
134                let data = String::deserialize(deserializer)?;
135
136                PresharedKey::try_from(data.as_str()).map_err(|_| {
137                    de::Error::invalid_value(de::Unexpected::Str(&data), &"a preshared key")
138                })
139            } else {
140                let bytes = <[u8; 32]>::deserialize(deserializer)?;
141
142                Ok(PresharedKey::from(bytes))
143            }
144        }
145    }
146}