Skip to main content

bitwarden_sensitive_value/
sensitive_slice.rs

1use crate::Sensitive;
2
3/// A zero-copy view over a borrowed slice of secret bytes. Wrapping a `&[u8]` borrows the
4/// underlying buffer instead of cloning it, so the wrapper is bound by the borrow's lifetime
5/// `'a` and cannot outlive the data it points at. `Debug`/`Display` are redacted via the inner
6/// [`Sensitive`].
7///
8/// For owned secret bytes (e.g. when deserializing, where borrowing is not possible) use
9/// `Sensitive<Vec<u8>>` instead.
10pub type SensitiveSlice<'a> = Sensitive<&'a [u8]>;
11
12impl<'a, const N: usize> From<&'a [u8; N]> for SensitiveSlice<'a> {
13    fn from(value: &'a [u8; N]) -> Self {
14        Sensitive::from(value.as_slice())
15    }
16}
17
18#[cfg(test)]
19mod tests {
20    use super::*;
21    use crate::ExposeSensitive;
22
23    #[test]
24    fn from_borrows_and_expose_returns_slice() {
25        let key_material = [0x42u8; 32];
26        let secret: SensitiveSlice<'_> = Sensitive::from(key_material.as_slice());
27
28        assert_eq!(*secret.expose(), key_material.as_slice());
29        assert_eq!(secret.expose_owned(), key_material.as_slice());
30        // The owner still holds the buffer; wrapping only borrowed it.
31        assert_eq!(key_material.len(), 32);
32    }
33
34    #[test]
35    fn partial_eq_compares_borrowed_bytes() {
36        let a = [1u8, 2, 3];
37        let b = [1u8, 2, 3];
38        let c = [9u8, 9, 9];
39
40        assert_eq!(Sensitive::from(a.as_slice()), Sensitive::from(b.as_slice()));
41        assert_ne!(Sensitive::from(a.as_slice()), Sensitive::from(c.as_slice()));
42    }
43
44    #[test]
45    fn from_array_ref_borrows_without_as_slice() {
46        let key_material = [0x42u8; 13];
47        let secret: SensitiveSlice<'_> = (&key_material).into();
48        assert_eq!(secret.expose_owned(), key_material.as_slice());
49    }
50
51    #[cfg(not(feature = "dangerous-crypto-debug"))]
52    #[test]
53    fn debug_is_redacted() {
54        let secret: SensitiveSlice<'_> = Sensitive::from([0x42u8; 4].as_slice());
55        assert_eq!(format!("{secret:?}"), "[REDACTED]");
56    }
57
58    #[test]
59    fn serde_json_serializes_as_byte_array() {
60        let bytes = [1u8, 2, 3];
61        let secret: SensitiveSlice<'_> = Sensitive::from(bytes.as_slice());
62
63        let serialized = serde_json::to_string(&secret).unwrap();
64        assert_eq!(serialized, "[1,2,3]");
65    }
66}