Skip to main content

secure_gate/traits/decoding/
hex.rs

1//! Hexadecimal decoding trait.
2//!
3//! This trait provides secure, explicit decoding of hexadecimal strings
4//! to byte vectors. It is designed for handling untrusted input in
5//! cryptographic contexts, such as decoding hex-encoded keys or nonces.
6//!
7//! Requires the `encoding-hex` feature.
8//!
9//! # Security Notes
10//!
11//! - Treat all input as untrusted**: validate hex strings upstream before wrapping in secrets. Invalid input fails immediately.
12//!   in secrets. Invalid hex may indicate tampering or injection attempts.
13//! - **Heap allocation**: Returns `Vec<u8>` — wrap in [`Fixed`](crate::Fixed) or
14//!   [`Dynamic`](crate::Dynamic) to store as a secret.
15//! - **Case-insensitive**: Accepts both uppercase and lowercase hex digits.
16//!
17//! # Example
18//!
19//! ```rust
20//! # #[cfg(feature = "encoding-hex")]
21//! use secure_gate::{FromHexStr, Fixed};
22//! # #[cfg(feature = "encoding-hex")]
23//! {
24//! let bytes = "01234567".try_from_hex().unwrap();
25//! assert_eq!(bytes, vec![0x01, 0x23, 0x45, 0x67]);
26//!
27//! // Wrap result in a secret immediately
28//! let secret: Fixed<[u8; 4]> = Fixed::try_from_hex("deadbeef").unwrap();
29//!
30//! // Error on invalid input
31//! assert!("xyz!".try_from_hex().is_err());
32//! }
33//! ```
34#[cfg(feature = "encoding-hex")]
35use ::hex as hex_crate;
36
37#[cfg(feature = "encoding-hex")]
38use crate::error::HexError;
39
40/// Extension trait for decoding hexadecimal strings into byte vectors.
41///
42/// *Requires feature `encoding-hex`.*
43///
44/// Blanket-implemented for all `AsRef<str>` types. Treat all input as untrusted;
45/// validate lengths and content upstream before wrapping decoded bytes in secrets.
46#[cfg(feature = "encoding-hex")]
47pub trait FromHexStr {
48    /// Decodes a hexadecimal string into a byte vector.
49    ///
50    /// Case-insensitive; rejects odd-length strings and invalid characters.
51    ///
52    /// # Errors
53    ///
54    /// - [`HexError::InvalidHex`] — non-hex characters or odd-length input.
55    ///
56    /// # Examples
57    ///
58    /// ```rust
59    /// use secure_gate::FromHexStr;
60    ///
61    /// let bytes = "deadbeef".try_from_hex()?;
62    /// assert_eq!(bytes, [0xde, 0xad, 0xbe, 0xef]);
63    ///
64    /// assert!("xyz!".try_from_hex().is_err()); // invalid chars
65    /// assert!("a".try_from_hex().is_err());    // odd length
66    /// # Ok::<(), secure_gate::HexError>(())
67    /// ```
68    fn try_from_hex(&self) -> Result<Vec<u8>, HexError>;
69}
70
71// Blanket impl to cover any AsRef<str> (e.g., &str, String, etc.)
72#[cfg(feature = "encoding-hex")]
73impl<T: AsRef<str> + ?Sized> FromHexStr for T {
74    fn try_from_hex(&self) -> Result<Vec<u8>, HexError> {
75        hex_crate::decode(self.as_ref()).map_err(|_| HexError::InvalidHex)
76    }
77}