subtle_encoding/
hex.rs

1//! Hex encoding/decoding with data-independent constant time(-ish) operation.
2//!
3//! Adapted from this C++ implementation:
4//!
5//! <https://github.com/Sc00bz/ConstTimeEncoding/blob/master/hex.cpp>
6//!
7//! Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
8//! Derived code is dual licensed MIT + Apache 2.0 (with permission from @Sc00bz)
9//!
10//! ## Usage
11//!
12//! The main API acts as a drop-in replacement for the `hex` crate
13//!
14//! ### Encoding
15//!
16//! Use the [hex::encode] method:
17//!
18//! ```
19//! use subtle_encoding::hex;
20//!
21//! let encoded = hex::encode([0, 1, 2, 3, 4, 5]);
22//!
23//! // Prints the hex encoded version: "000102030405"
24//! println!("hex encoded: {}", String::from_utf8(encoded).unwrap());
25//! ```
26//!
27//! By default hex is encoded in lower-case. To encode upper-case hex, use the
28//! [hex::encode_upper] method.
29//!
30//! ### Decoding
31//!
32//! Use the [hex::decode] method, or [hex::decode_upper] for upper-case hex.
33//!
34//! [hex::encode]: https://docs.rs/subtle-encoding/latest/subtle_encoding/hex/fn.encode.html
35//! [hex::encode_upper]: https://docs.rs/subtle-encoding/latest/subtle_encoding/hex/fn.encode_upper.html
36//! [hex::decode]: https://docs.rs/subtle-encoding/latest/subtle_encoding/hex/fn.decode.html
37//! [hex::decode_upper]: https://docs.rs/subtle-encoding/latest/subtle_encoding/hex/fn.decode_upper.html
38
39use super::{
40    Encoding,
41    Error::{self, *},
42};
43#[cfg(feature = "alloc")]
44use alloc::vec::Vec;
45
46/// Encode the given data as lower-case hexadecimal, returning a `Vec<u8>`
47#[cfg(feature = "alloc")]
48pub fn encode<B: AsRef<[u8]>>(bytes: B) -> Vec<u8> {
49    Hex::lower_case().encode(bytes)
50}
51
52/// Decode the given data from lower-case hexadecimal, returning a `Vec<u8>`
53/// of the decoded data on success, or an `Error`.
54#[cfg(feature = "alloc")]
55pub fn decode<B: AsRef<[u8]>>(encoded_bytes: B) -> Result<Vec<u8>, Error> {
56    Hex::lower_case().decode(encoded_bytes)
57}
58
59/// Encode the given data as upper-case hexadecimal, returning a `Vec<u8>`
60#[cfg(feature = "alloc")]
61pub fn encode_upper<B: AsRef<[u8]>>(bytes: B) -> Vec<u8> {
62    Hex::upper_case().encode(bytes)
63}
64
65/// Decode the given data from upper-case hexadecimal, returning a `Vec<u8>`
66/// of the decoded data on success, or an `Error`.
67#[cfg(feature = "alloc")]
68pub fn decode_upper<B: AsRef<[u8]>>(encoded_bytes: B) -> Result<Vec<u8>, Error> {
69    Hex::upper_case().decode(encoded_bytes)
70}
71
72/// Hexadecimal `Encoding` (a.k.a. Base16)
73#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
74pub struct Hex {
75    /// Upper or lower case
76    case: Case,
77}
78
79impl Hex {
80    /// Lower case hex: 0-9 a-f
81    pub fn lower_case() -> Hex {
82        Hex { case: Case::Lower }
83    }
84
85    /// Upper case hex: 0-9 A-F
86    pub fn upper_case() -> Hex {
87        Hex { case: Case::Upper }
88    }
89}
90
91impl Encoding for Hex {
92    fn encode_to_slice(&self, src: &[u8], dst: &mut [u8]) -> Result<usize, Error> {
93        if self.encoded_len(src) > dst.len() {
94            return Err(LengthInvalid);
95        }
96
97        for (i, src_byte) in src.iter().enumerate() {
98            let offset = i * 2;
99            dst[offset] = self.case.encode_nibble(src_byte >> 4);
100            dst[offset + 1] = self.case.encode_nibble(src_byte & 0x0f);
101        }
102
103        Ok(src.len() * 2)
104    }
105
106    fn encoded_len(&self, bytes: &[u8]) -> usize {
107        bytes.len() * 2
108    }
109
110    fn decode_to_slice(&self, src: &[u8], dst: &mut [u8]) -> Result<usize, Error> {
111        // TODO: constant-time whitespace tolerance
112        if !src.is_empty() && char::from(src[src.len() - 1]).is_whitespace() {
113            return Err(TrailingWhitespace);
114        }
115
116        let dst_length = self.decoded_len(src)?;
117        ensure!(dst_length <= dst.len(), LengthInvalid);
118
119        let mut err: usize = 0;
120
121        for (i, dst_byte) in dst.iter_mut().enumerate().take(dst_length) {
122            let src_offset = i * 2;
123            let byte = (self.case.decode_nibble(src[src_offset]) << 4)
124                | self.case.decode_nibble(src[src_offset + 1]);
125            err |= byte >> 8;
126            *dst_byte = byte as u8;
127        }
128
129        if err == 0 {
130            Ok(dst_length)
131        } else {
132            Err(EncodingInvalid)
133        }
134    }
135
136    fn decoded_len(&self, bytes: &[u8]) -> Result<usize, Error> {
137        if bytes.len() & 1 == 0 {
138            Ok(bytes.len() >> 1)
139        } else {
140            Err(LengthInvalid)
141        }
142    }
143}
144
145/// Lower or upper case encoders
146#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
147enum Case {
148    Lower,
149    Upper,
150}
151
152impl Case {
153    /// Decode a single nibble of hex (lower or upper case)
154    #[inline]
155    fn decode_nibble(self, src: u8) -> usize {
156        // 0-9  0x30-0x39
157        // A-F  0x41-0x46 or a-f  0x61-0x66
158        let byte = src as isize;
159        let mut ret: isize = -1;
160
161        // 0-9  0x30-0x39
162        // if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47
163        ret += (((0x2fisize - byte) & (byte - 0x3a)) >> 8) & (byte - 47);
164
165        ret += match self {
166            Case::Lower => {
167                // a-f  0x61-0x66
168                // if (byte > 0x60 && byte < 0x67) ret += byte - 0x61 + 10 + 1; // -86
169                (((0x60isize - byte) & (byte - 0x67)) >> 8) & (byte - 86)
170            }
171            Case::Upper => {
172                // A-F  0x41-0x46
173                // if (byte > 0x40 && byte < 0x47) ret += byte - 0x41 + 10 + 1; // -54
174                (((0x40isize - byte) & (byte - 0x47)) >> 8) & (byte - 54)
175            }
176        };
177
178        ret as usize
179    }
180
181    /// Encode a single nibble of hex
182    #[inline]
183    fn encode_nibble(self, src: u8) -> u8 {
184        let mut ret = src as isize + 0x30;
185
186        ret += match self {
187            Case::Lower => {
188                // 0-9  0x30-0x39
189                // a-f  0x61-0x66
190                ((0x39isize - ret) >> 8) & (0x61isize - 0x3a)
191            }
192            Case::Upper => {
193                // 0-9  0x30-0x39
194                // A-F  0x41-0x46
195                ((0x39isize - ret) >> 8) & (0x41isize - 0x3a)
196            }
197        };
198
199        ret as u8
200    }
201}
202
203impl Default for Case {
204    /// Default: lower case
205    fn default() -> Case {
206        Case::Lower
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213    use crate::error::Error::*;
214
215    /// Hexadecimal test vectors
216    struct HexVector {
217        /// Raw bytes
218        raw: &'static [u8],
219
220        /// Hex encoded
221        hex: &'static [u8],
222    }
223
224    const HEX_TEST_VECTORS: &[HexVector] = &[
225        HexVector { raw: b"", hex: b"" },
226        HexVector {
227            raw: b"\0",
228            hex: b"00",
229        },
230        HexVector {
231            raw: b"***",
232            hex: b"2a2a2a",
233        },
234        HexVector {
235            raw: b"\x01\x02\x03\x04",
236            hex: b"01020304",
237        },
238        HexVector {
239            raw: b"\xAD\xAD\xAD\xAD\xAD",
240            hex: b"adadadadad",
241        },
242        HexVector {
243            raw: b"\xFF\xFF\xFF\xFF\xFF",
244            hex: b"ffffffffff",
245        },
246    ];
247
248    #[test]
249    fn encode_test_vectors() {
250        for vector in HEX_TEST_VECTORS {
251            // 10 is the size of the largest encoded test vector
252            let mut out = [0u8; 10];
253            let out_len = Hex::lower_case()
254                .encode_to_slice(vector.raw, &mut out)
255                .unwrap();
256
257            assert_eq!(vector.hex, &out[..out_len]);
258        }
259    }
260
261    #[test]
262    fn decode_test_vectors() {
263        for vector in HEX_TEST_VECTORS {
264            // 5 is the size of the largest decoded test vector
265            let mut out = [0u8; 5];
266            let out_len = Hex::lower_case()
267                .decode_to_slice(vector.hex, &mut out)
268                .unwrap();
269
270            assert_eq!(vector.raw, &out[..out_len]);
271        }
272    }
273
274    #[test]
275    fn reject_odd_size_input() {
276        let mut out = [0u8; 3];
277        assert_eq!(
278            LengthInvalid,
279            Hex::lower_case()
280                .decode_to_slice(b"12345", &mut out)
281                .err()
282                .unwrap(),
283        )
284    }
285
286    #[test]
287    fn encode_and_decode_various_lengths() {
288        let data = [b'X'; 64];
289
290        for i in 0..data.len() {
291            let encoded = Hex::lower_case().encode(&data[..i]);
292
293            // Make sure it round trips
294            let decoded = Hex::lower_case().decode(encoded).unwrap();
295
296            assert_eq!(decoded.as_slice(), &data[..i]);
297        }
298    }
299}