aboutsummaryrefslogtreecommitdiff
path: root/src/rust/external/crypto_digest.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rust/external/crypto_digest.rs')
-rw-r--r--src/rust/external/crypto_digest.rs454
1 files changed, 0 insertions, 454 deletions
diff --git a/src/rust/external/crypto_digest.rs b/src/rust/external/crypto_digest.rs
deleted file mode 100644
index 873f75e7a3..0000000000
--- a/src/rust/external/crypto_digest.rs
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Bindings to external digest and XOF functions which live within
-//! src/common/crypto_digest.[ch].
-//!
-//! We wrap our C implementations in src/common/crypto_digest.[ch] with more
-//! Rusty types and interfaces in src/rust/crypto/digest/.
-
-use std::process::abort;
-
-use libc::c_char;
-use libc::c_int;
-use libc::size_t;
-use libc::uint8_t;
-
-use smartlist::Stringlist;
-
-/// Length of the output of our message digest.
-pub const DIGEST_LEN: usize = 20;
-
-/// Length of the output of our second (improved) message digests. (For now
-/// this is just sha256, but it could be any other 256-bit digest.)
-pub const DIGEST256_LEN: usize = 32;
-
-/// Length of the output of our 64-bit optimized message digests (SHA512).
-pub const DIGEST512_LEN: usize = 64;
-
-/// Length of a sha1 message digest when encoded in base32 with trailing = signs
-/// removed.
-pub const BASE32_DIGEST_LEN: usize = 32;
-
-/// Length of a sha1 message digest when encoded in base64 with trailing = signs
-/// removed.
-pub const BASE64_DIGEST_LEN: usize = 27;
-
-/// Length of a sha256 message digest when encoded in base64 with trailing =
-/// signs removed.
-pub const BASE64_DIGEST256_LEN: usize = 43;
-
-/// Length of a sha512 message digest when encoded in base64 with trailing =
-/// signs removed.
-pub const BASE64_DIGEST512_LEN: usize = 86;
-
-/// Length of hex encoding of SHA1 digest, not including final NUL.
-pub const HEX_DIGEST_LEN: usize = 40;
-
-/// Length of hex encoding of SHA256 digest, not including final NUL.
-pub const HEX_DIGEST256_LEN: usize = 64;
-
-/// Length of hex encoding of SHA512 digest, not including final NUL.
-pub const HEX_DIGEST512_LEN: usize = 128;
-
-/// Our C code uses an enum to declare the digest algorithm types which we know
-/// about. However, because enums are implementation-defined in C, we can
-/// neither work with them directly nor translate them into Rust enums.
-/// Instead, we represent them as a u8 (under the assumption that we'll never
-/// support more than 256 hash functions).
-#[allow(non_camel_case_types)]
-type digest_algorithm_t = u8;
-
-const DIGEST_SHA1: digest_algorithm_t = 0;
-const DIGEST_SHA256: digest_algorithm_t = 1;
-const DIGEST_SHA512: digest_algorithm_t = 2;
-const DIGEST_SHA3_256: digest_algorithm_t = 3;
-const DIGEST_SHA3_512: digest_algorithm_t = 4;
-
-/// The number of hash digests we produce for a `common_digests_t`.
-///
-/// We can't access these from Rust, because their definitions in C require
-/// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have
-/// to redefine them here.
-const N_COMMON_DIGEST_ALGORITHMS: usize = DIGEST_SHA256 as usize + 1;
-
-/// A digest function.
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[allow(non_camel_case_types)]
-struct crypto_digest_t {
- // This private, zero-length field forces the struct to be treated the same
- // as its opaque C counterpart.
- _unused: [u8; 0],
-}
-
-/// An eXtendible Output Function (XOF).
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[allow(non_camel_case_types)]
-struct crypto_xof_t {
- // This private, zero-length field forces the struct to be treated the same
- // as its opaque C counterpart.
- _unused: [u8; 0],
-}
-
-/// A set of all the digests we commonly compute, taken on a single
-/// string. Any digests that are shorter than 512 bits are right-padded
-/// with 0 bits.
-///
-/// Note that this representation wastes 44 bytes for the SHA1 case, so
-/// don't use it for anything where we need to allocate a whole bunch at
-/// once.
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[allow(non_camel_case_types)]
-struct common_digests_t {
- pub d: [[c_char; N_COMMON_DIGEST_ALGORITHMS]; DIGEST256_LEN],
-}
-
-/// A `smartlist_t` is just an alias for the `#[repr(C)]` type `Stringlist`, to
-/// make it more clear that we're working with a smartlist which is owned by C.
-#[allow(non_camel_case_types)]
-// BINDGEN_GENERATED: This type isn't actually bindgen generated, but the code
-// below it which uses it is. As such, this comes up as "dead code" as well.
-#[allow(dead_code)]
-type smartlist_t = Stringlist;
-
-/// All of the external functions from `src/common/crypto_digest.h`.
-///
-/// These are kept private because they should be wrapped with Rust to make their usage safer.
-//
-// BINDGEN_GENERATED: These definitions were generated with bindgen and cleaned
-// up manually. As such, there are more bindings than are likely necessary or
-// which are in use.
-#[allow(dead_code)]
-extern "C" {
- fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int;
- fn crypto_digest256(
- digest: *mut c_char,
- m: *const c_char,
- len: size_t,
- algorithm: digest_algorithm_t,
- ) -> c_int;
- fn crypto_digest512(
- digest: *mut c_char,
- m: *const c_char,
- len: size_t,
- algorithm: digest_algorithm_t,
- ) -> c_int;
- fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t)
- -> c_int;
- fn crypto_digest_smartlist_prefix(
- digest_out: *mut c_char,
- len_out: size_t,
- prepend: *const c_char,
- lst: *const smartlist_t,
- append: *const c_char,
- alg: digest_algorithm_t,
- );
- fn crypto_digest_smartlist(
- digest_out: *mut c_char,
- len_out: size_t,
- lst: *const smartlist_t,
- append: *const c_char,
- alg: digest_algorithm_t,
- );
- fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char;
- fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t;
- fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int;
- fn crypto_digest_new() -> *mut crypto_digest_t;
- fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
- fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
- fn crypto_digest_free_(digest: *mut crypto_digest_t);
- fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t);
- fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t);
- fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t;
- fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t);
- fn crypto_hmac_sha256(
- hmac_out: *mut c_char,
- key: *const c_char,
- key_len: size_t,
- msg: *const c_char,
- msg_len: size_t,
- );
- fn crypto_mac_sha3_256(
- mac_out: *mut uint8_t,
- len_out: size_t,
- key: *const uint8_t,
- key_len: size_t,
- msg: *const uint8_t,
- msg_len: size_t,
- );
- fn crypto_xof_new() -> *mut crypto_xof_t;
- fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t);
- fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t);
- fn crypto_xof_free(xof: *mut crypto_xof_t);
-}
-
-/// A wrapper around a `digest_algorithm_t`.
-pub enum DigestAlgorithm {
- SHA2_256,
- SHA2_512,
- SHA3_256,
- SHA3_512,
-}
-
-impl From<DigestAlgorithm> for digest_algorithm_t {
- fn from(digest: DigestAlgorithm) -> digest_algorithm_t {
- match digest {
- DigestAlgorithm::SHA2_256 => DIGEST_SHA256,
- DigestAlgorithm::SHA2_512 => DIGEST_SHA512,
- DigestAlgorithm::SHA3_256 => DIGEST_SHA3_256,
- DigestAlgorithm::SHA3_512 => DIGEST_SHA3_512,
- }
- }
-}
-
-/// A wrapper around a mutable pointer to a `crypto_digest_t`.
-pub struct CryptoDigest(*mut crypto_digest_t);
-
-/// Explicitly copy the state of a `CryptoDigest` hash digest context.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_dup`
-impl Clone for CryptoDigest {
- fn clone(&self) -> CryptoDigest {
- let digest: *mut crypto_digest_t;
-
- unsafe {
- digest = crypto_digest_dup(self.0 as *const crypto_digest_t);
- }
-
- // See the note in the implementation of CryptoDigest for the
- // reasoning for `abort()` here.
- if digest.is_null() {
- abort();
- }
-
- CryptoDigest(digest)
- }
-}
-
-impl CryptoDigest {
- /// A wrapper to call one of the C functions `crypto_digest_new`,
- /// `crypto_digest256_new`, or `crypto_digest512_new`.
- ///
- /// # Warnings
- ///
- /// This function will `abort()` the entire process in an "abnormal" fashion,
- /// i.e. not unwinding this or any other thread's stack, running any
- /// destructors, or calling any panic/exit hooks) if `tor_malloc()` (called in
- /// `crypto_digest256_new()`) is unable to allocate memory.
- ///
- /// # Returns
- ///
- /// A new `CryptoDigest`, which is a wrapper around a opaque representation
- /// of a `crypto_digest_t`. The underlying `crypto_digest_t` _MUST_ only
- /// ever be handled via a raw pointer, and never introspected.
- ///
- /// # C_RUST_COUPLED
- ///
- /// * `crypto_digest_new`
- /// * `crypto_digest256_new`
- /// * `crypto_digest512_new`
- /// * `tor_malloc` (called by `crypto_digest256_new`, but we make
- /// assumptions about its behaviour and return values here)
- pub fn new(algorithm: Option<DigestAlgorithm>) -> CryptoDigest {
- let digest: *mut crypto_digest_t;
-
- if algorithm.is_none() {
- unsafe {
- digest = crypto_digest_new();
- }
- } else {
- let algo: digest_algorithm_t = algorithm.unwrap().into(); // can't fail because it's Some
-
- unsafe {
- // XXX This is a pretty awkward API to use from Rust...
- digest = match algo {
- DIGEST_SHA1 => crypto_digest_new(),
- DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256),
- DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256),
- DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512),
- DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512),
- _ => abort(),
- }
- }
- }
-
- // In our C code, `crypto_digest*_new()` allocates memory with
- // `tor_malloc()`. In `tor_malloc()`, if the underlying malloc
- // implementation fails to allocate the requested memory and returns a
- // NULL pointer, we call `exit(1)`. In the case that this `exit(1)` is
- // called within a worker, be that a process or a thread, the inline
- // comments within `tor_malloc()` mention "that's ok, since the parent
- // will run out of memory soon anyway". However, if it takes long
- // enough for the worker to die, and it manages to return a NULL pointer
- // to our Rust code, our Rust is now in an irreparably broken state and
- // may exhibit undefined behaviour. An even worse scenario, if/when we
- // have parent/child processes/threads controlled by Rust, would be that
- // the UB contagion in Rust manages to spread to other children before
- // the entire process (hopefully terminates).
- //
- // However, following the assumptions made in `tor_malloc()` that
- // calling `exit(1)` in a child is okay because the parent will
- // eventually run into the same errors, and also to stymie any UB
- // contagion in the meantime, we call abort!() here to terminate the
- // entire program immediately.
- if digest.is_null() {
- abort();
- }
-
- CryptoDigest(digest)
- }
-
- /// A wrapper to call the C function `crypto_digest_add_bytes`.
- ///
- /// # Inputs
- ///
- /// * `bytes`: a byte slice of bytes to be added into this digest.
- ///
- /// # C_RUST_COUPLED
- ///
- /// * `crypto_digest_add_bytes`
- pub fn add_bytes(&self, bytes: &[u8]) {
- unsafe {
- crypto_digest_add_bytes(
- self.0 as *mut crypto_digest_t,
- bytes.as_ptr() as *const c_char,
- bytes.len() as size_t,
- )
- }
- }
-}
-
-impl Drop for CryptoDigest {
- fn drop(&mut self) {
- unsafe {
- crypto_digest_free_(self.0 as *mut crypto_digest_t);
- }
- }
-}
-
-/// Get the 256-bit digest output of a `crypto_digest_t`.
-///
-/// # Inputs
-///
-/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA256` or a
-/// `DIGEST_SHA3_256`.
-///
-/// # Warning
-///
-/// Calling this function with a `CryptoDigest` which is neither SHA2-256 or
-/// SHA3-256 is a programming error. Since we cannot introspect the opaque
-/// struct from Rust, however, there is no way for us to check that the correct
-/// one is being passed in. That is up to you, dear programmer. If you mess
-/// up, you will get a incorrectly-sized hash digest in return, and it will be
-/// your fault. Don't do that.
-///
-/// # Returns
-///
-/// A 256-bit hash digest, as a `[u8; 32]`.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_get_digest`
-/// * `DIGEST256_LEN`
-//
-// FIXME: Once const generics land in Rust, we should genericise calling
-// crypto_digest_get_digest w.r.t. output array size.
-pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] {
- let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
-
- unsafe {
- crypto_digest_get_digest(
- digest.0,
- buffer.as_mut_ptr() as *mut c_char,
- DIGEST256_LEN as size_t,
- );
-
- if buffer.as_ptr().is_null() {
- abort();
- }
- }
- buffer
-}
-
-/// Get the 512-bit digest output of a `crypto_digest_t`.
-///
-/// # Inputs
-///
-/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA512` or a
-/// `DIGEST_SHA3_512`.
-///
-/// # Warning
-///
-/// Calling this function with a `CryptoDigest` which is neither SHA2-512 or
-/// SHA3-512 is a programming error. Since we cannot introspect the opaque
-/// struct from Rust, however, there is no way for us to check that the correct
-/// one is being passed in. That is up to you, dear programmer. If you mess
-/// up, you will get a incorrectly-sized hash digest in return, and it will be
-/// your fault. Don't do that.
-///
-/// # Returns
-///
-/// A 512-bit hash digest, as a `[u8; 64]`.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_get_digest`
-/// * `DIGEST512_LEN`
-//
-// FIXME: Once const generics land in Rust, we should genericise calling
-// crypto_digest_get_digest w.r.t. output array size.
-pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] {
- let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
-
- unsafe {
- crypto_digest_get_digest(
- digest.0,
- buffer.as_mut_ptr() as *mut c_char,
- DIGEST512_LEN as size_t,
- );
-
- if buffer.as_ptr().is_null() {
- abort();
- }
- }
- buffer
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn test_layout_common_digests_t() {
- assert_eq!(
- ::std::mem::size_of::<common_digests_t>(),
- 64usize,
- concat!("Size of: ", stringify!(common_digests_t))
- );
- assert_eq!(
- ::std::mem::align_of::<common_digests_t>(),
- 1usize,
- concat!("Alignment of ", stringify!(common_digests_t))
- );
- }
-
- #[test]
- fn test_layout_crypto_digest_t() {
- assert_eq!(
- ::std::mem::size_of::<crypto_digest_t>(),
- 0usize,
- concat!("Size of: ", stringify!(crypto_digest_t))
- );
- assert_eq!(
- ::std::mem::align_of::<crypto_digest_t>(),
- 1usize,
- concat!("Alignment of ", stringify!(crypto_digest_t))
- );
- }
-}