1use core::convert::{AsMut, AsRef};
8use core::fmt;
9use core::ops::{Deref, DerefMut};
10use zeroize::{Zeroize, ZeroizeOnDrop};
11
12#[cfg(all(feature = "alloc", not(feature = "std")))]
14extern crate alloc;
15
16#[cfg(all(feature = "alloc", not(feature = "std")))]
17use alloc::vec::Vec;
18
19#[cfg(feature = "std")]
20use std::vec::Vec;
21
22pub trait SecureZeroingType: Zeroize + Clone {
24 fn zeroed() -> Self;
26
27 fn secure_clone(&self) -> Self {
32 self.clone() }
34}
35
36#[derive(Clone, Zeroize, ZeroizeOnDrop)]
43pub struct SecretBuffer<const N: usize> {
44 data: [u8; N],
45}
46
47impl<const N: usize> SecretBuffer<N> {
48 pub fn new(data: [u8; N]) -> Self {
50 Self { data }
51 }
52
53 pub fn zeroed() -> Self {
55 Self { data: [0u8; N] }
56 }
57
58 pub fn len(&self) -> usize {
60 N
61 }
62
63 pub fn is_empty(&self) -> bool {
65 N == 0
66 }
67
68 pub fn as_slice(&self) -> &[u8] {
70 &self.data
71 }
72
73 pub fn as_mut_slice(&mut self) -> &mut [u8] {
75 &mut self.data
76 }
77}
78
79impl<const N: usize> SecureZeroingType for SecretBuffer<N> {
80 fn zeroed() -> Self {
81 Self::zeroed()
82 }
83
84 fn secure_clone(&self) -> Self {
85 Self::new(self.data) }
87}
88
89impl<const N: usize> AsRef<[u8]> for SecretBuffer<N> {
90 fn as_ref(&self) -> &[u8] {
91 &self.data
92 }
93}
94
95impl<const N: usize> AsMut<[u8]> for SecretBuffer<N> {
96 fn as_mut(&mut self) -> &mut [u8] {
97 &mut self.data
98 }
99}
100
101impl<const N: usize> fmt::Debug for SecretBuffer<N> {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "SecretBuffer<{}>([REDACTED])", N)
104 }
105}
106
107#[cfg(feature = "alloc")]
114#[derive(Zeroize, ZeroizeOnDrop)]
115pub struct SecretVec {
116 data: Vec<u8>,
117}
118
119#[cfg(feature = "alloc")]
120impl SecretVec {
121 pub fn new(mut data: Vec<u8>) -> Self {
127 Self::zeroize_spare_capacity(&mut data);
130 Self { data }
131 }
132
133 pub fn from_slice(slice: &[u8]) -> Self {
135 Self::new(slice.to_vec())
136 }
137
138 pub fn empty() -> Self {
140 Self { data: Vec::new() }
141 }
142
143 pub fn with_capacity(capacity: usize) -> Self {
145 let mut data = Vec::with_capacity(capacity);
146 Self::zeroize_spare_capacity(&mut data);
147 Self { data }
148 }
149
150 pub fn len(&self) -> usize {
152 self.data.len()
153 }
154
155 pub fn is_empty(&self) -> bool {
157 self.data.is_empty()
158 }
159
160 pub fn as_slice(&self) -> &[u8] {
162 &self.data
163 }
164
165 pub fn as_mut_slice(&mut self) -> &mut [u8] {
167 &mut self.data
168 }
169
170 pub fn capacity(&self) -> usize {
172 self.data.capacity()
173 }
174
175 pub fn extend_from_slice(&mut self, slice: &[u8]) {
177 self.ensure_additional_capacity(slice.len());
178 self.data.extend_from_slice(slice);
179 }
180
181 pub fn resize(&mut self, new_len: usize, value: u8) {
183 if new_len <= self.data.len() {
184 self.truncate(new_len);
185 return;
186 }
187
188 self.ensure_additional_capacity(new_len - self.data.len());
189 self.data.resize(new_len, value);
190 }
191
192 pub fn truncate(&mut self, len: usize) {
194 if len >= self.data.len() {
195 return;
196 }
197
198 self.data[len..].zeroize();
199 self.data.truncate(len);
200 }
201
202 pub fn clear(&mut self) {
204 self.data.zeroize();
205 }
206
207 pub fn push(&mut self, value: u8) {
209 self.ensure_additional_capacity(1);
210 self.data.push(value);
211 }
212
213 pub fn pop(&mut self) -> Option<u8> {
215 let value = self.data.last().copied()?;
216 let new_len = self.data.len() - 1;
217 self.data[new_len].zeroize();
218 self.data.truncate(new_len);
219 Some(value)
220 }
221
222 pub fn reserve(&mut self, additional: usize) {
228 self.ensure_additional_capacity(additional);
229 }
230
231 pub fn shrink_to_fit(&mut self) {
233 if self.data.capacity() > self.data.len() {
234 self.secure_reallocate(self.data.len());
235 }
236 }
237
238 fn ensure_additional_capacity(&mut self, additional: usize) {
239 let required = self
240 .data
241 .len()
242 .checked_add(additional)
243 .expect("SecretVec capacity overflow");
244
245 if required > self.data.capacity() {
246 self.secure_reallocate(required);
247 }
248 }
249
250 fn secure_reallocate(&mut self, capacity: usize) {
251 debug_assert!(capacity >= self.data.len());
252
253 let mut replacement = Vec::with_capacity(capacity);
254 replacement.extend_from_slice(&self.data);
255 Self::zeroize_spare_capacity(&mut replacement);
256
257 self.data.zeroize();
260 #[cfg(test)]
261 assert!(Self::allocation_is_zeroed(&self.data));
262 self.data = replacement;
263 }
264
265 fn zeroize_spare_capacity(data: &mut Vec<u8>) {
266 data.spare_capacity_mut().zeroize();
267 }
268
269 #[cfg(test)]
270 fn allocation_is_zeroed(data: &Vec<u8>) -> bool {
271 let allocation = unsafe { core::slice::from_raw_parts(data.as_ptr(), data.capacity()) };
274 allocation.iter().all(|byte| *byte == 0)
275 }
276}
277
278#[cfg(feature = "alloc")]
279impl Clone for SecretVec {
280 fn clone(&self) -> Self {
281 Self::from_slice(&self.data)
282 }
283}
284
285#[cfg(feature = "alloc")]
286impl SecureZeroingType for SecretVec {
287 fn zeroed() -> Self {
288 Self::empty()
289 }
290
291 fn secure_clone(&self) -> Self {
292 self.clone()
293 }
294}
295
296#[cfg(feature = "alloc")]
297impl AsRef<[u8]> for SecretVec {
298 fn as_ref(&self) -> &[u8] {
299 &self.data
300 }
301}
302
303#[cfg(feature = "alloc")]
304impl AsMut<[u8]> for SecretVec {
305 fn as_mut(&mut self) -> &mut [u8] {
306 &mut self.data
307 }
308}
309
310#[cfg(feature = "alloc")]
311impl From<Vec<u8>> for SecretVec {
312 fn from(data: Vec<u8>) -> Self {
313 Self::new(data)
314 }
315}
316
317#[cfg(feature = "alloc")]
318impl fmt::Debug for SecretVec {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320 write!(f, "SecretVec(len={}, [REDACTED])", self.data.len())
321 }
322}
323
324pub struct EphemeralSecret<T: Zeroize> {
329 inner: T,
330}
331
332impl<T: Zeroize> EphemeralSecret<T> {
333 pub fn new(value: T) -> Self {
335 Self { inner: value }
336 }
337
338 pub fn into_inner(self) -> T {
343 let this = core::mem::ManuallyDrop::new(self);
344 unsafe { core::ptr::read(&this.inner) }
345 }
346}
347
348impl<T: Zeroize> AsRef<T> for EphemeralSecret<T> {
350 fn as_ref(&self) -> &T {
351 &self.inner
352 }
353}
354
355impl<T: Zeroize> AsMut<T> for EphemeralSecret<T> {
356 fn as_mut(&mut self) -> &mut T {
357 &mut self.inner
358 }
359}
360
361impl<T: Zeroize> Drop for EphemeralSecret<T> {
362 fn drop(&mut self) {
363 self.inner.zeroize();
364 }
365}
366
367impl<T: Zeroize + Clone> Clone for EphemeralSecret<T> {
368 fn clone(&self) -> Self {
369 Self::new(self.inner.clone())
370 }
371}
372
373impl<T: Zeroize + Default> Default for EphemeralSecret<T> {
374 fn default() -> Self {
375 Self::new(T::default())
376 }
377}
378
379impl<T: Zeroize> Deref for EphemeralSecret<T> {
380 type Target = T;
381
382 fn deref(&self) -> &Self::Target {
383 &self.inner
384 }
385}
386
387impl<T: Zeroize> DerefMut for EphemeralSecret<T> {
388 fn deref_mut(&mut self) -> &mut Self::Target {
389 &mut self.inner
390 }
391}
392
393impl<T: Zeroize + fmt::Debug> fmt::Debug for EphemeralSecret<T> {
394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395 write!(f, "EphemeralSecret([REDACTED])")
396 }
397}
398
399pub struct ZeroizeGuard<'a, T: Zeroize> {
404 value: &'a mut T,
405}
406
407impl<'a, T: Zeroize> ZeroizeGuard<'a, T> {
408 pub fn new(value: &'a mut T) -> Self {
410 Self { value }
411 }
412}
413
414impl<T: Zeroize> Drop for ZeroizeGuard<'_, T> {
416 fn drop(&mut self) {
417 self.value.zeroize();
418 }
419}
420
421impl<T: Zeroize> Deref for ZeroizeGuard<'_, T> {
422 type Target = T;
423
424 fn deref(&self) -> &Self::Target {
425 self.value
426 }
427}
428
429impl<T: Zeroize> DerefMut for ZeroizeGuard<'_, T> {
430 fn deref_mut(&mut self) -> &mut Self::Target {
431 self.value
432 }
433}
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[cfg(all(not(feature = "std"), feature = "alloc"))]
440 use alloc::vec;
441
442 #[test]
443 fn test_secret_buffer_basic() {
444 let mut buffer = SecretBuffer::<32>::new([42u8; 32]);
445 assert_eq!(buffer.len(), 32);
446 assert_eq!(buffer.as_slice()[0], 42);
447
448 buffer.as_mut_slice()[0] = 1;
450 assert_eq!(buffer.as_slice()[0], 1);
451 }
452
453 #[test]
454 fn test_secret_buffer_secure_clone() {
455 let buffer = SecretBuffer::<16>::new([0xAA; 16]);
456 let cloned = buffer.secure_clone();
457 assert_eq!(cloned.as_slice(), buffer.as_slice());
458 }
459
460 #[test]
461 fn test_secret_buffer_zeroed() {
462 let zeroed = SecretBuffer::<32>::zeroed();
463 assert_eq!(zeroed.as_slice(), &[0u8; 32]);
464 }
465
466 #[cfg(feature = "alloc")]
467 #[test]
468 fn test_secret_vec_operations() {
469 let mut vec = SecretVec::from_slice(&[1, 2, 3, 4]);
470 assert_eq!(vec.len(), 4);
471 assert_eq!(vec.as_slice(), &[1, 2, 3, 4]);
472
473 vec.extend_from_slice(&[5, 6]);
475 assert_eq!(vec.as_slice(), &[1, 2, 3, 4, 5, 6]);
476
477 vec.truncate(3);
479 assert_eq!(vec.as_slice(), &[1, 2, 3]);
480
481 vec.resize(5, 0xFF);
483 assert_eq!(vec.as_slice(), &[1, 2, 3, 0xFF, 0xFF]);
484 }
485
486 #[cfg(feature = "alloc")]
487 fn assert_secret_vec_spare_capacity_is_zero(vec: &SecretVec) {
488 let spare = unsafe {
491 core::slice::from_raw_parts(
492 vec.data.as_ptr().add(vec.data.len()),
493 vec.data.capacity() - vec.data.len(),
494 )
495 };
496 assert!(spare.iter().all(|byte| *byte == 0));
497 }
498
499 #[cfg(feature = "alloc")]
500 #[test]
501 fn secret_vec_wipes_preexisting_unused_capacity() {
502 let mut raw = vec![0xA5; 64];
503 raw.truncate(4);
504 let secret = SecretVec::new(raw);
505
506 assert_eq!(secret.as_slice(), &[0xA5; 4]);
507 assert_secret_vec_spare_capacity_is_zero(&secret);
508 }
509
510 #[cfg(feature = "alloc")]
511 #[test]
512 fn secret_vec_wipes_bytes_removed_by_truncate_resize_clear_and_pop() {
513 let mut secret = SecretVec::from_slice(&[1, 2, 3, 4, 5, 6]);
514
515 secret.truncate(4);
516 assert_eq!(secret.as_slice(), &[1, 2, 3, 4]);
517 assert_secret_vec_spare_capacity_is_zero(&secret);
518
519 secret.resize(2, 0xFF);
520 assert_eq!(secret.as_slice(), &[1, 2]);
521 assert_secret_vec_spare_capacity_is_zero(&secret);
522
523 assert_eq!(secret.pop(), Some(2));
524 assert_eq!(secret.as_slice(), &[1]);
525 assert_secret_vec_spare_capacity_is_zero(&secret);
526
527 secret.clear();
528 assert!(secret.is_empty());
529 assert_secret_vec_spare_capacity_is_zero(&secret);
530 }
531
532 #[cfg(feature = "alloc")]
533 #[test]
534 fn secret_vec_growth_and_shrink_replace_allocations_securely() {
535 let mut raw = Vec::with_capacity(4);
536 raw.extend_from_slice(&[0x11; 4]);
537 let mut secret = SecretVec::new(raw);
538 let initial_capacity = secret.capacity();
539
540 secret.extend_from_slice(&[0x22, 0x33]);
543 assert!(secret.capacity() > initial_capacity);
544 assert_eq!(secret.as_slice(), &[0x11, 0x11, 0x11, 0x11, 0x22, 0x33]);
545 assert_secret_vec_spare_capacity_is_zero(&secret);
546
547 secret.reserve(32);
548 assert!(secret.capacity() >= secret.len() + 32);
549 assert_secret_vec_spare_capacity_is_zero(&secret);
550
551 secret.shrink_to_fit();
552 assert_eq!(secret.capacity(), secret.len());
553 assert_eq!(secret.as_slice(), &[0x11, 0x11, 0x11, 0x11, 0x22, 0x33]);
554 }
555
556 #[test]
557 fn test_ephemeral_secret() {
558 #[derive(Clone, Zeroize)]
559 struct TestSecret(u64);
560
561 let secret = EphemeralSecret::new(TestSecret(42));
562 assert_eq!(secret.0, 42);
563
564 let value = secret.0;
566 assert_eq!(value, 42);
567
568 let cloned = secret.clone();
570 assert_eq!(cloned.0, 42);
571
572 let inner = secret.into_inner();
574 assert_eq!(inner.0, 42);
575 }
576
577 #[test]
578 fn test_zeroize_guard() {
579 let mut value = vec![1u8, 2, 3, 4];
580 {
581 let guard = ZeroizeGuard::new(&mut value);
582 assert_eq!(&**guard, &[1, 2, 3, 4]);
584 }
585 assert!(value.is_empty());
587 }
588}