Skip to main content

securer_string/secure_types/
string.rs

1use core::fmt;
2use std::str::FromStr;
3
4use crate::SecureVec;
5use crate::secure_utils::memlock;
6
7/// Wrapper for a vector that stores a valid UTF-8 string
8#[derive(Clone)]
9pub struct SecureString(SecureVec<u8>);
10
11impl SecureString {
12    /// Borrow the contents of the string.
13    #[must_use]
14    pub fn unsecure(&self) -> &str {
15        // SAFETY: SecureString can only be constructed from valid UTF-8 (String or
16        // &str), and the contents cannot be modified as non-UTF-8, so they
17        // remain valid UTF-8.
18        unsafe { std::str::from_utf8_unchecked(self.0.unsecure()) }
19    }
20
21    /// Mutably borrow the contents of the string.
22    #[must_use]
23    pub fn unsecure_mut(&mut self) -> &mut str {
24        // SAFETY: Same as `unsecure` - contents are always valid UTF-8.
25        unsafe { std::str::from_utf8_unchecked_mut(self.0.unsecure_mut()) }
26    }
27
28    /// Turn the string into a regular `String` again.
29    #[must_use]
30    pub fn into_unsecure(mut self) -> String {
31        if self.0.is_locked {
32            memlock::munlock(self.0.content.as_mut_ptr(), self.0.content.capacity());
33        }
34        let content = std::mem::take(&mut self.0.content);
35        std::mem::forget(self);
36        // SAFETY: Same as `unsecure` - contents are always valid UTF-8.
37        unsafe { String::from_utf8_unchecked(content) }
38    }
39
40    /// Overwrite the string with zeros. This is automatically called in the
41    /// destructor.
42    ///
43    /// This also sets the length to `0`.
44    pub fn zero_out(&mut self) {
45        self.0.zero_out();
46    }
47}
48
49impl PartialEq for SecureString {
50    fn eq(&self, other: &SecureString) -> bool {
51        // use constant-time implementation of SecureVec
52        self.0 == other.0
53    }
54}
55
56impl Eq for SecureString {}
57
58impl fmt::Debug for SecureString {
59    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60        f.debug_struct("SecureString").finish_non_exhaustive()
61    }
62}
63
64impl fmt::Display for SecureString {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        f.write_str("***SECRET***").map_err(|_| fmt::Error)
67    }
68}
69
70impl<U> From<U> for SecureString
71where
72    U: Into<String>,
73{
74    fn from(s: U) -> SecureString {
75        SecureString(SecureVec::new(s.into().into_bytes()))
76    }
77}
78
79impl FromStr for SecureString {
80    type Err = std::convert::Infallible;
81
82    fn from_str(s: &str) -> Result<Self, Self::Err> {
83        Ok(SecureString(SecureVec::new(s.into())))
84    }
85}
86
87#[cfg(feature = "serde")]
88impl serde::Serialize for SecureString {
89    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
90    where
91        S: serde::Serializer,
92    {
93        serializer.serialize_str(self.unsecure())
94    }
95}
96
97#[cfg(feature = "serde")]
98impl<'de> serde::Deserialize<'de> for SecureString {
99    fn deserialize<D>(deserializer: D) -> Result<SecureString, D::Error>
100    where
101        D: serde::Deserializer<'de>,
102    {
103        struct SecureStringVisitor;
104        impl serde::de::Visitor<'_> for SecureStringVisitor {
105            type Value = SecureString;
106            fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
107                write!(formatter, "an utf-8 encoded string")
108            }
109            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
110            where
111                E: serde::de::Error,
112            {
113                Ok(SecureString::from(v.to_string()))
114            }
115        }
116        deserializer.deserialize_string(SecureStringVisitor)
117    }
118}