secure_gate/traits/encoding/hex.rs
1//! Hexadecimal encoding trait.
2//!
3//! This trait provides secure, explicit encoding of byte data to lowercase
4//! (or uppercase) hexadecimal strings. It is intended for intentional export
5//! only (QR codes, audited logs, API responses).
6//!
7//! Requires the `encoding-hex` feature.
8//!
9//! # Security Notes
10//!
11//! - **Full secret exposure**: The resulting string contains the **entire** secret.
12//! Always treat output as sensitive; do not log or persist without protection.
13//! - **Audit visibility**: Direct calls (`key.to_hex()` / `key.to_hex_upper()`) do **not** appear in
14//! `grep expose_secret` / `grep with_secret` audit sweeps. For audit-first teams or
15//! multi-step operations, prefer `with_secret(|b| b.to_hex())` — the borrow checker
16//! enforces the reference cannot escape the closure.
17//! - **Treat all input as untrusted**: validate hex strings upstream before wrapping
18//! in secrets.
19//!
20//! # Example
21//!
22//! ```rust
23//! # #[cfg(feature = "encoding-hex")]
24//! use secure_gate::{Fixed, ToHex, RevealSecret};
25//! # #[cfg(feature = "encoding-hex")]
26//! {
27//! let secret = Fixed::new([0x0au8, 0x0bu8, 0x0cu8, 0x0du8]);
28//!
29//! // Blanket impl on the inner byte array (via with_secret):
30//! let hex = secret.with_secret(|s| s.to_hex());
31//! assert_eq!(hex, "0a0b0c0d");
32//!
33//! let hex_upper = secret.with_secret(|s| s.to_hex_upper());
34//! assert_eq!(hex_upper, "0A0B0C0D");
35//!
36//! // Wrapper method (Direct Fixed<[u8; N]> API — same result):
37//! assert_eq!(secret.to_hex(), "0a0b0c0d");
38//! }
39//! ```
40#[cfg(feature = "encoding-hex")]
41use ::hex as hex_crate;
42
43/// Extension trait for encoding byte data as hexadecimal strings.
44///
45/// *Requires feature `encoding-hex`.*
46///
47/// Blanket-implemented for all `AsRef<[u8]>` types (byte slices, arrays, `Vec<u8>`).
48/// To encode a secret wrapper, call the inherent `to_hex()` method directly (ergonomically
49/// safest for single operations — no reference in the caller's hands), or use
50/// `with_secret(|b| b.to_hex())` for multi-step operations or when audit-greppability matters.
51#[cfg(feature = "encoding-hex")]
52pub trait ToHex {
53 /// Encode bytes as lowercase hexadecimal.
54 fn to_hex(&self) -> alloc::string::String;
55
56 /// Encode bytes as uppercase hexadecimal.
57 fn to_hex_upper(&self) -> alloc::string::String;
58}
59
60// Blanket impl to cover any AsRef<[u8]> (e.g., &[u8], Vec<u8>, [u8; N], etc.)
61#[cfg(feature = "encoding-hex")]
62impl<T: AsRef<[u8]> + ?Sized> ToHex for T {
63 #[inline(always)]
64 fn to_hex(&self) -> alloc::string::String {
65 hex_crate::encode(self.as_ref())
66 }
67
68 #[inline(always)]
69 fn to_hex_upper(&self) -> alloc::string::String {
70 hex_crate::encode_upper(self.as_ref())
71 }
72}