envelope_cli/crypto/
secure_memory.rs1use std::fmt;
7use std::ops::Deref;
8
9pub struct SecureString {
13 inner: String,
14}
15
16impl SecureString {
17 pub fn new(s: impl Into<String>) -> Self {
19 Self { inner: s.into() }
20 }
21
22 pub fn as_str(&self) -> &str {
24 &self.inner
25 }
26
27 pub fn len(&self) -> usize {
29 self.inner.len()
30 }
31
32 pub fn is_empty(&self) -> bool {
34 self.inner.is_empty()
35 }
36}
37
38impl Drop for SecureString {
39 fn drop(&mut self) {
40 unsafe {
44 let bytes = self.inner.as_bytes_mut();
45 for byte in bytes.iter_mut() {
46 std::ptr::write_volatile(byte, 0);
47 }
48 }
49 self.inner.clear();
52 }
53}
54
55impl Deref for SecureString {
56 type Target = str;
57
58 fn deref(&self) -> &Self::Target {
59 &self.inner
60 }
61}
62
63impl AsRef<str> for SecureString {
64 fn as_ref(&self) -> &str {
65 &self.inner
66 }
67}
68
69impl From<String> for SecureString {
70 fn from(s: String) -> Self {
71 Self::new(s)
72 }
73}
74
75impl From<&str> for SecureString {
76 fn from(s: &str) -> Self {
77 Self::new(s)
78 }
79}
80
81impl fmt::Debug for SecureString {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 f.debug_struct("SecureString")
85 .field("len", &self.inner.len())
86 .finish()
87 }
88}
89
90impl fmt::Display for SecureString {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(f, "[REDACTED {} bytes]", self.inner.len())
94 }
95}
96
97pub struct SecureBytes {
101 inner: Vec<u8>,
102}
103
104impl SecureBytes {
105 pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
107 Self {
108 inner: bytes.into(),
109 }
110 }
111
112 pub fn with_capacity(capacity: usize) -> Self {
114 Self {
115 inner: Vec::with_capacity(capacity),
116 }
117 }
118
119 pub fn as_bytes(&self) -> &[u8] {
121 &self.inner
122 }
123
124 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
126 &mut self.inner
127 }
128
129 pub fn len(&self) -> usize {
131 self.inner.len()
132 }
133
134 pub fn is_empty(&self) -> bool {
136 self.inner.is_empty()
137 }
138}
139
140impl Drop for SecureBytes {
141 fn drop(&mut self) {
142 for byte in self.inner.iter_mut() {
144 unsafe {
145 std::ptr::write_volatile(byte, 0);
146 }
147 }
148 self.inner.clear();
149 }
150}
151
152impl Deref for SecureBytes {
153 type Target = [u8];
154
155 fn deref(&self) -> &Self::Target {
156 &self.inner
157 }
158}
159
160impl AsRef<[u8]> for SecureBytes {
161 fn as_ref(&self) -> &[u8] {
162 &self.inner
163 }
164}
165
166impl From<Vec<u8>> for SecureBytes {
167 fn from(bytes: Vec<u8>) -> Self {
168 Self::new(bytes)
169 }
170}
171
172impl From<&[u8]> for SecureBytes {
173 fn from(bytes: &[u8]) -> Self {
174 Self::new(bytes.to_vec())
175 }
176}
177
178impl fmt::Debug for SecureBytes {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 f.debug_struct("SecureBytes")
182 .field("len", &self.inner.len())
183 .finish()
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_secure_string_creation() {
193 let s = SecureString::new("test");
194 assert_eq!(s.as_str(), "test");
195 assert_eq!(s.len(), 4);
196 }
197
198 #[test]
199 fn test_secure_string_from_string() {
200 let s: SecureString = String::from("test").into();
201 assert_eq!(s.as_str(), "test");
202 }
203
204 #[test]
205 fn test_secure_string_from_str() {
206 let s: SecureString = "test".into();
207 assert_eq!(s.as_str(), "test");
208 }
209
210 #[test]
211 fn test_secure_string_deref() {
212 let s = SecureString::new("test");
213 let len = s.len(); assert_eq!(len, 4);
215 }
216
217 #[test]
218 fn test_secure_string_debug() {
219 let s = SecureString::new("secret");
220 let debug = format!("{:?}", s);
221 assert!(!debug.contains("secret"));
222 assert!(debug.contains("SecureString"));
223 }
224
225 #[test]
226 fn test_secure_string_display() {
227 let s = SecureString::new("secret");
228 let display = format!("{}", s);
229 assert!(!display.contains("secret"));
230 assert!(display.contains("REDACTED"));
231 }
232
233 #[test]
234 fn test_secure_bytes_creation() {
235 let b = SecureBytes::new(vec![1, 2, 3]);
236 assert_eq!(b.as_bytes(), &[1, 2, 3]);
237 assert_eq!(b.len(), 3);
238 }
239
240 #[test]
241 fn test_secure_bytes_from_vec() {
242 let b: SecureBytes = vec![1, 2, 3].into();
243 assert_eq!(b.as_bytes(), &[1, 2, 3]);
244 }
245
246 #[test]
247 fn test_secure_bytes_from_slice() {
248 let b: SecureBytes = (&[1u8, 2, 3][..]).into();
249 assert_eq!(b.as_bytes(), &[1, 2, 3]);
250 }
251
252 #[test]
253 fn test_secure_bytes_debug() {
254 let b = SecureBytes::new(vec![1, 2, 3, 4, 5]);
255 let debug = format!("{:?}", b);
256 assert!(debug.contains("SecureBytes"));
257 assert!(debug.contains("5")); }
259}