secure_string/secure_types/
boxed.rs1use core::fmt;
2use std::{
3 borrow::{Borrow, BorrowMut},
4 mem::MaybeUninit,
5};
6
7use zeroize::Zeroize;
8
9use crate::secure_utils::memlock;
10
11#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
21pub struct SecureBox<T>
22where
23 T: Copy,
24{
25 content: Option<Box<T>>,
28}
29
30impl<T> SecureBox<T>
31where
32 T: Copy,
33{
34 pub fn new(mut cont: Box<T>) -> Self {
35 memlock::mlock(&mut cont, 1);
36 SecureBox { content: Some(cont) }
37 }
38
39 pub fn unsecure(&self) -> &T {
41 self.content.as_ref().unwrap()
42 }
43
44 pub fn unsecure_mut(&mut self) -> &mut T {
46 self.content.as_mut().unwrap()
47 }
48}
49
50impl<T: Copy> Clone for SecureBox<T> {
51 fn clone(&self) -> Self {
52 Self::new(self.content.clone().unwrap())
53 }
54}
55
56impl<T, U> std::ops::Index<U> for SecureBox<T>
58where
59 T: std::ops::Index<U> + Copy,
60{
61 type Output = <T as std::ops::Index<U>>::Output;
62
63 fn index(&self, index: U) -> &Self::Output {
64 std::ops::Index::index(self.content.as_ref().unwrap().as_ref(), index)
65 }
66}
67
68impl<T> Borrow<T> for SecureBox<T>
70where
71 T: Copy,
72{
73 fn borrow(&self) -> &T {
74 self.content.as_ref().unwrap()
75 }
76}
77impl<T> BorrowMut<T> for SecureBox<T>
78where
79 T: Copy,
80{
81 fn borrow_mut(&mut self) -> &mut T {
82 self.content.as_mut().unwrap()
83 }
84}
85
86impl<T> Drop for SecureBox<T>
88where
89 T: Copy,
90{
91 #[cfg_attr(feature = "pre", pre::pre)]
92 fn drop(&mut self) {
93 let ptr = Box::into_raw(self.content.take().unwrap());
98
99 unsafe {
103 std::slice::from_raw_parts_mut::<MaybeUninit<u8>>(ptr as *mut MaybeUninit<u8>, std::mem::size_of::<T>()).zeroize();
104 }
105
106 memlock::munlock(ptr, 1);
107
108 if std::mem::size_of::<T>() != 0 {
110 unsafe { std::alloc::dealloc(ptr as *mut u8, std::alloc::Layout::new::<T>()) };
115 }
116 }
117}
118
119impl<T> fmt::Debug for SecureBox<T>
121where
122 T: Copy,
123{
124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125 f.write_str("***SECRET***").map_err(|_| fmt::Error)
126 }
127}
128
129impl<T> fmt::Display for SecureBox<T>
130where
131 T: Copy,
132{
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 f.write_str("***SECRET***").map_err(|_| fmt::Error)
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use std::mem::MaybeUninit;
141
142 use zeroize::Zeroize;
143
144 use super::SecureBox;
145
146 const PRIVATE_KEY_1: [u8; 32] = [
147 0xb0, 0x3b, 0x34, 0xc3, 0x3a, 0x1c, 0x44, 0xf2, 0x25, 0xb6, 0x62, 0xd2, 0xbf, 0x48, 0x59, 0xb8, 0x13, 0x54, 0x11, 0xfa,
148 0x7b, 0x03, 0x86, 0xd4, 0x5f, 0xb7, 0x5d, 0xc5, 0xb9, 0x1b, 0x44, 0x66,
149 ];
150
151 const PRIVATE_KEY_2: [u8; 32] = [
152 0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, 0x88, 0x8d, 0x58, 0xab, 0x40, 0x6b,
153 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, 0x6b, 0xb4, 0xbf, 0x59,
154 ];
155
156 #[cfg_attr(feature = "pre", pre::pre("an all-zero byte-pattern is a valid value of `T`"))]
162 pub(crate) unsafe fn zero_out_secure_box<T>(secure_box: &mut SecureBox<T>)
163 where
164 T: Copy,
165 {
166 std::slice::from_raw_parts_mut::<MaybeUninit<u8>>(
167 &mut **secure_box.content.as_mut().unwrap() as *mut T as *mut MaybeUninit<u8>,
168 std::mem::size_of::<T>(),
169 )
170 .zeroize();
171 }
172
173 #[test]
174 #[cfg_attr(feature = "pre", pre::pre)]
175 fn test_secure_box() {
176 let key_1 = SecureBox::new(Box::new(PRIVATE_KEY_1));
177 let key_2 = SecureBox::new(Box::new(PRIVATE_KEY_2));
178 let key_3 = SecureBox::new(Box::new(PRIVATE_KEY_1));
179 assert!(key_1 == key_1);
180 assert!(key_1 != key_2);
181 assert!(key_2 != key_3);
182 assert!(key_1 == key_3);
183
184 let mut final_key = key_1.clone();
185 #[cfg_attr(
186 feature = "pre",
187 assure(
188 "an all-zero byte-pattern is a valid value of `T`",
189 reason = "`T` is `i32`, for which an all-zero byte-pattern is valid"
190 )
191 )]
192 unsafe {
193 zero_out_secure_box(&mut final_key)
194 };
195 assert_eq!(final_key.unsecure(), &[0; 32]);
196 }
197}