1use zeroize::{Zeroize, Zeroizing};
7
8pub type ZeroizingKey<const N: usize> = Zeroizing<[u8; N]>;
12
13pub fn zeroizing_key_32() -> ZeroizingKey<32> {
15 Zeroizing::new([0u8; 32])
16}
17
18pub fn zeroizing_nonce() -> ZeroizingKey<12> {
20 Zeroizing::new([0u8; 12])
21}
22
23#[inline]
27pub fn secure_zero(data: &mut [u8]) {
28 data.zeroize();
29}
30
31#[inline]
33pub fn secure_move(dest: &mut [u8], src: &mut [u8]) {
34 assert_eq!(
35 dest.len(),
36 src.len(),
37 "dest and src must have the same length"
38 );
39 dest.copy_from_slice(src);
40 src.zeroize();
41}
42
43#[derive(Clone, Zeroize)]
45#[zeroize(drop)]
46pub struct SecureBuffer {
47 data: Vec<u8>,
48}
49
50impl SecureBuffer {
51 pub fn new(capacity: usize) -> Self {
53 Self {
54 data: Vec::with_capacity(capacity),
55 }
56 }
57
58 pub fn from_bytes(bytes: Vec<u8>) -> Self {
60 Self { data: bytes }
61 }
62
63 pub fn from_slice(slice: &[u8]) -> Self {
65 Self {
66 data: slice.to_vec(),
67 }
68 }
69
70 pub fn as_bytes(&self) -> &[u8] {
72 &self.data
73 }
74
75 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
77 &mut self.data
78 }
79
80 pub fn len(&self) -> usize {
82 self.data.len()
83 }
84
85 pub fn is_empty(&self) -> bool {
87 self.data.is_empty()
88 }
89
90 pub fn push(&mut self, byte: u8) {
92 self.data.push(byte);
93 }
94
95 pub fn extend_from_slice(&mut self, slice: &[u8]) {
97 self.data.extend_from_slice(slice);
98 }
99
100 pub fn clear(&mut self) {
102 self.data.zeroize();
103 self.data.clear();
104 }
105
106 pub fn into_inner(mut self) -> Vec<u8> {
110 let mut data = Vec::new();
112 std::mem::swap(&mut data, &mut self.data);
113 std::mem::forget(self);
114 data
115 }
116
117 pub fn resize(&mut self, new_len: usize) {
119 self.data.resize(new_len, 0);
120 }
121}
122
123impl std::fmt::Debug for SecureBuffer {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 write!(f, "SecureBuffer([REDACTED; {} bytes])", self.data.len())
126 }
127}
128
129impl From<Vec<u8>> for SecureBuffer {
130 fn from(data: Vec<u8>) -> Self {
131 Self { data }
132 }
133}
134
135impl From<&[u8]> for SecureBuffer {
136 fn from(data: &[u8]) -> Self {
137 Self::from_slice(data)
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_secure_zero() {
147 let mut data = vec![1, 2, 3, 4, 5];
148 secure_zero(&mut data);
149 assert_eq!(data, vec![0, 0, 0, 0, 0]);
150 }
151
152 #[test]
153 fn test_secure_move() {
154 let mut src = vec![1, 2, 3, 4];
155 let mut dest = vec![0, 0, 0, 0];
156
157 secure_move(&mut dest, &mut src);
158
159 assert_eq!(dest, vec![1, 2, 3, 4]);
160 assert_eq!(src, vec![0, 0, 0, 0]);
161 }
162
163 #[test]
164 fn test_secure_buffer() {
165 let mut buffer = SecureBuffer::from_slice(&[1, 2, 3, 4]);
166
167 assert_eq!(buffer.len(), 4);
168 assert!(!buffer.is_empty());
169 assert_eq!(buffer.as_bytes(), &[1, 2, 3, 4]);
170
171 buffer.push(5);
172 assert_eq!(buffer.len(), 5);
173
174 buffer.clear();
175 assert_eq!(buffer.len(), 0);
176 assert!(buffer.is_empty());
177 }
178
179 #[test]
180 fn test_secure_buffer_debug() {
181 let buffer = SecureBuffer::from_slice(&[1, 2, 3, 4]);
182 let debug = format!("{:?}", buffer);
183 assert!(debug.contains("REDACTED"));
184 assert!(!debug.contains("1, 2, 3, 4"));
185 }
186
187 #[test]
188 fn test_zeroizing_key() {
189 let key = zeroizing_key_32();
190 assert_eq!(key.len(), 32);
191
192 let nonce = zeroizing_nonce();
193 assert_eq!(nonce.len(), 12);
194 }
195
196 #[test]
197 fn test_secure_buffer_drop_zeroizes() {
198 let data = vec![1u8, 2, 3, 4];
199
200 {
201 let _buffer = SecureBuffer::from_bytes(data);
202 }
204
205 }
208}