make dist: only include files from practracker dir intentionally.
[tor.git] / src / rust / external / crypto_digest.rs
blob454f836badd5ac8d496207fb71e9d4d1432907be
1 // Copyright (c) 2018-2019, The Tor Project, Inc.
2 // Copyright (c) 2018, isis agora lovecruft
3 // See LICENSE for licensing information
5 //! Bindings to external digest and XOF functions which live within
6 //! src/common/crypto_digest.[ch].
7 //!
8 //! We wrap our C implementations in src/common/crypto_digest.[ch] with more
9 //! Rusty types and interfaces in src/rust/crypto/digest/.
11 use std::process::abort;
13 use libc::c_char;
14 use libc::c_int;
15 use libc::size_t;
16 use libc::uint8_t;
18 use smartlist::Stringlist;
20 /// Length of the output of our message digest.
21 pub const DIGEST_LEN: usize = 20;
23 /// Length of the output of our second (improved) message digests.  (For now
24 /// this is just sha256, but it could be any other 256-bit digest.)
25 pub const DIGEST256_LEN: usize = 32;
27 /// Length of the output of our 64-bit optimized message digests (SHA512).
28 pub const DIGEST512_LEN: usize = 64;
30 /// Length of a sha1 message digest when encoded in base32 with trailing = signs
31 /// removed.
32 pub const BASE32_DIGEST_LEN: usize = 32;
34 /// Length of a sha1 message digest when encoded in base64 with trailing = signs
35 /// removed.
36 pub const BASE64_DIGEST_LEN: usize = 27;
38 /// Length of a sha256 message digest when encoded in base64 with trailing =
39 /// signs removed.
40 pub const BASE64_DIGEST256_LEN: usize = 43;
42 /// Length of a sha512 message digest when encoded in base64 with trailing =
43 /// signs removed.
44 pub const BASE64_DIGEST512_LEN: usize = 86;
46 /// Length of hex encoding of SHA1 digest, not including final NUL.
47 pub const HEX_DIGEST_LEN: usize = 40;
49 /// Length of hex encoding of SHA256 digest, not including final NUL.
50 pub const HEX_DIGEST256_LEN: usize = 64;
52 /// Length of hex encoding of SHA512 digest, not including final NUL.
53 pub const HEX_DIGEST512_LEN: usize = 128;
55 /// Our C code uses an enum to declare the digest algorithm types which we know
56 /// about.  However, because enums are implementation-defined in C, we can
57 /// neither work with them directly nor translate them into Rust enums.
58 /// Instead, we represent them as a u8 (under the assumption that we'll never
59 /// support more than 256 hash functions).
60 #[allow(non_camel_case_types)]
61 type digest_algorithm_t = u8;
63 const DIGEST_SHA1: digest_algorithm_t = 0;
64 const DIGEST_SHA256: digest_algorithm_t = 1;
65 const DIGEST_SHA512: digest_algorithm_t = 2;
66 const DIGEST_SHA3_256: digest_algorithm_t = 3;
67 const DIGEST_SHA3_512: digest_algorithm_t = 4;
69 /// The number of hash digests we produce for a `common_digests_t`.
70 ///
71 /// We can't access these from Rust, because their definitions in C require
72 /// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have
73 /// to redefine them here.
74 const N_COMMON_DIGEST_ALGORITHMS: usize = DIGEST_SHA256 as usize + 1;
76 /// A digest function.
77 #[repr(C)]
78 #[derive(Debug, Copy, Clone)]
79 #[allow(non_camel_case_types)]
80 struct crypto_digest_t {
81     // This private, zero-length field forces the struct to be treated the same
82     // as its opaque C couterpart.
83     _unused: [u8; 0],
86 /// An eXtendible Output Function (XOF).
87 #[repr(C)]
88 #[derive(Debug, Copy, Clone)]
89 #[allow(non_camel_case_types)]
90 struct crypto_xof_t {
91     // This private, zero-length field forces the struct to be treated the same
92     // as its opaque C couterpart.
93     _unused: [u8; 0],
96 /// A set of all the digests we commonly compute, taken on a single
97 /// string.  Any digests that are shorter than 512 bits are right-padded
98 /// with 0 bits.
99 ///
100 /// Note that this representation wastes 44 bytes for the SHA1 case, so
101 /// don't use it for anything where we need to allocate a whole bunch at
102 /// once.
103 #[repr(C)]
104 #[derive(Debug, Copy, Clone)]
105 #[allow(non_camel_case_types)]
106 struct common_digests_t {
107     pub d: [[c_char; N_COMMON_DIGEST_ALGORITHMS]; DIGEST256_LEN],
110 /// A `smartlist_t` is just an alias for the `#[repr(C)]` type `Stringlist`, to
111 /// make it more clear that we're working with a smartlist which is owned by C.
112 #[allow(non_camel_case_types)]
113 // BINDGEN_GENERATED: This type isn't actually bindgen generated, but the code
114 // below it which uses it is.  As such, this comes up as "dead code" as well.
115 #[allow(dead_code)]
116 type smartlist_t = Stringlist;
118 /// All of the external functions from `src/common/crypto_digest.h`.
120 /// These are kept private because they should be wrapped with Rust to make their usage safer.
122 // BINDGEN_GENERATED: These definitions were generated with bindgen and cleaned
123 // up manually.  As such, there are more bindings than are likely necessary or
124 // which are in use.
125 #[allow(dead_code)]
126 extern "C" {
127     fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int;
128     fn crypto_digest256(
129         digest: *mut c_char,
130         m: *const c_char,
131         len: size_t,
132         algorithm: digest_algorithm_t,
133     ) -> c_int;
134     fn crypto_digest512(
135         digest: *mut c_char,
136         m: *const c_char,
137         len: size_t,
138         algorithm: digest_algorithm_t,
139     ) -> c_int;
140     fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t)
141         -> c_int;
142     fn crypto_digest_smartlist_prefix(
143         digest_out: *mut c_char,
144         len_out: size_t,
145         prepend: *const c_char,
146         lst: *const smartlist_t,
147         append: *const c_char,
148         alg: digest_algorithm_t,
149     );
150     fn crypto_digest_smartlist(
151         digest_out: *mut c_char,
152         len_out: size_t,
153         lst: *const smartlist_t,
154         append: *const c_char,
155         alg: digest_algorithm_t,
156     );
157     fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char;
158     fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t;
159     fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int;
160     fn crypto_digest_new() -> *mut crypto_digest_t;
161     fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
162     fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
163     fn crypto_digest_free_(digest: *mut crypto_digest_t);
164     fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t);
165     fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t);
166     fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t;
167     fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t);
168     fn crypto_hmac_sha256(
169         hmac_out: *mut c_char,
170         key: *const c_char,
171         key_len: size_t,
172         msg: *const c_char,
173         msg_len: size_t,
174     );
175     fn crypto_mac_sha3_256(
176         mac_out: *mut uint8_t,
177         len_out: size_t,
178         key: *const uint8_t,
179         key_len: size_t,
180         msg: *const uint8_t,
181         msg_len: size_t,
182     );
183     fn crypto_xof_new() -> *mut crypto_xof_t;
184     fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t);
185     fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t);
186     fn crypto_xof_free(xof: *mut crypto_xof_t);
189 /// A wrapper around a `digest_algorithm_t`.
190 pub enum DigestAlgorithm {
191     SHA2_256,
192     SHA2_512,
193     SHA3_256,
194     SHA3_512,
197 impl From<DigestAlgorithm> for digest_algorithm_t {
198     fn from(digest: DigestAlgorithm) -> digest_algorithm_t {
199         match digest {
200             DigestAlgorithm::SHA2_256 => DIGEST_SHA256,
201             DigestAlgorithm::SHA2_512 => DIGEST_SHA512,
202             DigestAlgorithm::SHA3_256 => DIGEST_SHA3_256,
203             DigestAlgorithm::SHA3_512 => DIGEST_SHA3_512,
204         }
205     }
208 /// A wrapper around a mutable pointer to a `crypto_digest_t`.
209 pub struct CryptoDigest(*mut crypto_digest_t);
211 /// Explicitly copy the state of a `CryptoDigest` hash digest context.
213 /// # C_RUST_COUPLED
215 /// * `crypto_digest_dup`
216 impl Clone for CryptoDigest {
217     fn clone(&self) -> CryptoDigest {
218         let digest: *mut crypto_digest_t;
220         unsafe {
221             digest = crypto_digest_dup(self.0 as *const crypto_digest_t);
222         }
224         // See the note in the implementation of CryptoDigest for the
225         // reasoning for `abort()` here.
226         if digest.is_null() {
227             abort();
228         }
230         CryptoDigest(digest)
231     }
234 impl CryptoDigest {
235     /// A wrapper to call one of the C functions `crypto_digest_new`,
236     /// `crypto_digest256_new`, or `crypto_digest512_new`.
237     ///
238     /// # Warnings
239     ///
240     /// This function will `abort()` the entire process in an "abnormal" fashion,
241     /// i.e. not unwinding this or any other thread's stack, running any
242     /// destructors, or calling any panic/exit hooks) if `tor_malloc()` (called in
243     /// `crypto_digest256_new()`) is unable to allocate memory.
244     ///
245     /// # Returns
246     ///
247     /// A new `CryptoDigest`, which is a wrapper around a opaque representation
248     /// of a `crypto_digest_t`.  The underlying `crypto_digest_t` _MUST_ only
249     /// ever be handled via a raw pointer, and never introspected.
250     ///
251     /// # C_RUST_COUPLED
252     ///
253     /// * `crypto_digest_new`
254     /// * `crypto_digest256_new`
255     /// * `crypto_digest512_new`
256     /// * `tor_malloc` (called by `crypto_digest256_new`, but we make
257     ///    assumptions about its behvaiour and return values here)
258     pub fn new(algorithm: Option<DigestAlgorithm>) -> CryptoDigest {
259         let digest: *mut crypto_digest_t;
261         if algorithm.is_none() {
262             unsafe {
263                 digest = crypto_digest_new();
264             }
265         } else {
266             let algo: digest_algorithm_t = algorithm.unwrap().into(); // can't fail because it's Some
268             unsafe {
269                 // XXX This is a pretty awkward API to use from Rust...
270                 digest = match algo {
271                     DIGEST_SHA1 => crypto_digest_new(),
272                     DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256),
273                     DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256),
274                     DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512),
275                     DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512),
276                     _ => abort(),
277                 }
278             }
279         }
281         // In our C code, `crypto_digest*_new()` allocates memory with
282         // `tor_malloc()`.  In `tor_malloc()`, if the underlying malloc
283         // implementation fails to allocate the requested memory and returns a
284         // NULL pointer, we call `exit(1)`.  In the case that this `exit(1)` is
285         // called within a worker, be that a process or a thread, the inline
286         // comments within `tor_malloc()` mention "that's ok, since the parent
287         // will run out of memory soon anyway".  However, if it takes long
288         // enough for the worker to die, and it manages to return a NULL pointer
289         // to our Rust code, our Rust is now in an irreparably broken state and
290         // may exhibit undefined behaviour.  An even worse scenario, if/when we
291         // have parent/child processes/threads controlled by Rust, would be that
292         // the UB contagion in Rust manages to spread to other children before
293         // the entire process (hopefully terminates).
294         //
295         // However, following the assumptions made in `tor_malloc()` that
296         // calling `exit(1)` in a child is okay because the parent will
297         // eventually run into the same errors, and also to stymie any UB
298         // contagion in the meantime, we call abort!() here to terminate the
299         // entire program immediately.
300         if digest.is_null() {
301             abort();
302         }
304         CryptoDigest(digest)
305     }
307     /// A wrapper to call the C function `crypto_digest_add_bytes`.
308     ///
309     /// # Inputs
310     ///
311     /// * `bytes`: a byte slice of bytes to be added into this digest.
312     ///
313     /// # C_RUST_COUPLED
314     ///
315     /// * `crypto_digest_add_bytes`
316     pub fn add_bytes(&self, bytes: &[u8]) {
317         unsafe {
318             crypto_digest_add_bytes(
319                 self.0 as *mut crypto_digest_t,
320                 bytes.as_ptr() as *const c_char,
321                 bytes.len() as size_t,
322             )
323         }
324     }
327 impl Drop for CryptoDigest {
328     fn drop(&mut self) {
329         unsafe {
330             crypto_digest_free_(self.0 as *mut crypto_digest_t);
331         }
332     }
335 /// Get the 256-bit digest output of a `crypto_digest_t`.
337 /// # Inputs
339 /// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA256` or a
340 ///   `DIGEST_SHA3_256`.
342 /// # Warning
344 /// Calling this function with a `CryptoDigest` which is neither SHA2-256 or
345 /// SHA3-256 is a programming error.  Since we cannot introspect the opaque
346 /// struct from Rust, however, there is no way for us to check that the correct
347 /// one is being passed in.  That is up to you, dear programmer.  If you mess
348 /// up, you will get a incorrectly-sized hash digest in return, and it will be
349 /// your fault.  Don't do that.
351 /// # Returns
353 /// A 256-bit hash digest, as a `[u8; 32]`.
355 /// # C_RUST_COUPLED
357 /// * `crypto_digest_get_digest`
358 /// * `DIGEST256_LEN`
360 // FIXME: Once const generics land in Rust, we should genericise calling
361 // crypto_digest_get_digest w.r.t. output array size.
362 pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] {
363     let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
365     unsafe {
366         crypto_digest_get_digest(
367             digest.0,
368             buffer.as_mut_ptr() as *mut c_char,
369             DIGEST256_LEN as size_t,
370         );
372         if buffer.as_ptr().is_null() {
373             abort();
374         }
375     }
376     buffer
379 /// Get the 512-bit digest output of a `crypto_digest_t`.
381 /// # Inputs
383 /// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA512` or a
384 ///   `DIGEST_SHA3_512`.
386 /// # Warning
388 /// Calling this function with a `CryptoDigest` which is neither SHA2-512 or
389 /// SHA3-512 is a programming error.  Since we cannot introspect the opaque
390 /// struct from Rust, however, there is no way for us to check that the correct
391 /// one is being passed in.  That is up to you, dear programmer.  If you mess
392 /// up, you will get a incorrectly-sized hash digest in return, and it will be
393 /// your fault.  Don't do that.
395 /// # Returns
397 /// A 512-bit hash digest, as a `[u8; 64]`.
399 /// # C_RUST_COUPLED
401 /// * `crypto_digest_get_digest`
402 /// * `DIGEST512_LEN`
404 // FIXME: Once const generics land in Rust, we should genericise calling
405 // crypto_digest_get_digest w.r.t. output array size.
406 pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] {
407     let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
409     unsafe {
410         crypto_digest_get_digest(
411             digest.0,
412             buffer.as_mut_ptr() as *mut c_char,
413             DIGEST512_LEN as size_t,
414         );
416         if buffer.as_ptr().is_null() {
417             abort();
418         }
419     }
420     buffer
423 #[cfg(test)]
424 mod test {
425     use super::*;
427     #[test]
428     fn test_layout_common_digests_t() {
429         assert_eq!(
430             ::std::mem::size_of::<common_digests_t>(),
431             64usize,
432             concat!("Size of: ", stringify!(common_digests_t))
433         );
434         assert_eq!(
435             ::std::mem::align_of::<common_digests_t>(),
436             1usize,
437             concat!("Alignment of ", stringify!(common_digests_t))
438         );
439     }
441     #[test]
442     fn test_layout_crypto_digest_t() {
443         assert_eq!(
444             ::std::mem::size_of::<crypto_digest_t>(),
445             0usize,
446             concat!("Size of: ", stringify!(crypto_digest_t))
447         );
448         assert_eq!(
449             ::std::mem::align_of::<crypto_digest_t>(),
450             1usize,
451             concat!("Alignment of ", stringify!(crypto_digest_t))
452         );
453     }