secure_gate/encoding/
mod.rs

1// ==========================================================================
2// src/encoding/mod.rs
3// ==========================================================================
4
5// Allow unsafe_code when zeroize is enabled (not needed here, but consistent)
6// but forbid it when neither encoding feature is enabled
7#![cfg_attr(
8    not(any(feature = "encoding-hex", feature = "encoding-base64")),
9    forbid(unsafe_code)
10)]
11
12#[cfg(feature = "encoding-hex")]
13pub mod hex;
14
15#[cfg(feature = "encoding-hex")]
16use ::hex as hex_crate;
17
18#[cfg(feature = "encoding-base64")]
19use ::base64 as base64_crate;
20#[cfg(feature = "encoding-base64")]
21use base64_crate::Engine;
22#[cfg(feature = "encoding-base64")]
23pub mod base64;
24
25/// Extension trait for safe, explicit encoding of secret byte data to strings.
26///
27/// All methods require the caller to first call `.expose_secret()` (or similar).
28/// This makes every secret access loud, grep-able, and auditable.
29///
30/// # Example
31///
32/// ```
33/// # #[cfg(feature = "encoding")]
34/// # {
35/// # use secure_gate::{fixed_alias, encoding::SecureEncodingExt};
36/// # fixed_alias!(Aes256Key, 32);
37/// # let key = Aes256Key::from([0x42u8; 32]);
38/// # let hex = key.expose_secret().to_hex();         // → "424242..."
39/// # let b64 = key.expose_secret().to_base64url();   // URL-safe, no padding
40/// # assert_eq!(hex, "4242424242424242424242424242424242424242424242424242424242424242");
41/// # }
42/// ```
43// Trait is available when any encoding feature is enabled
44#[cfg(any(feature = "encoding-hex", feature = "encoding-base64"))]
45pub trait SecureEncodingExt {
46    /// Encode secret bytes as lowercase hexadecimal.
47    #[cfg(feature = "encoding-hex")]
48    fn to_hex(&self) -> alloc::string::String;
49
50    /// Encode secret bytes as uppercase hexadecimal.
51    #[cfg(feature = "encoding-hex")]
52    fn to_hex_upper(&self) -> alloc::string::String;
53
54    /// Encode secret bytes as URL-safe base64 (no padding).
55    #[cfg(feature = "encoding-base64")]
56    fn to_base64url(&self) -> alloc::string::String;
57}
58
59#[cfg(feature = "encoding-hex")]
60impl SecureEncodingExt for [u8] {
61    #[cfg(feature = "encoding-hex")]
62    #[inline(always)]
63    fn to_hex(&self) -> alloc::string::String {
64        hex_crate::encode(self)
65    }
66    #[cfg(feature = "encoding-hex")]
67    #[inline(always)]
68    fn to_hex_upper(&self) -> alloc::string::String {
69        hex_crate::encode_upper(self)
70    }
71    #[cfg(feature = "encoding-base64")]
72    #[inline(always)]
73    fn to_base64url(&self) -> alloc::string::String {
74        use ::base64::engine::general_purpose::URL_SAFE_NO_PAD;
75        URL_SAFE_NO_PAD.encode(self)
76    }
77}
78
79#[cfg(feature = "encoding-hex")]
80impl<const N: usize> SecureEncodingExt for [u8; N] {
81    #[cfg(feature = "encoding-hex")]
82    #[inline(always)]
83    fn to_hex(&self) -> alloc::string::String {
84        hex_crate::encode(self)
85    }
86
87    #[cfg(feature = "encoding-hex")]
88    #[inline(always)]
89    fn to_hex_upper(&self) -> alloc::string::String {
90        hex_crate::encode_upper(self)
91    }
92
93    #[cfg(feature = "encoding-base64")]
94    #[inline(always)]
95    fn to_base64url(&self) -> alloc::string::String {
96        use ::base64::engine::general_purpose::URL_SAFE_NO_PAD;
97        URL_SAFE_NO_PAD.encode(self)
98    }
99}