secure_string/secure_types/
string.rs

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