mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-09-20 04:12:13 +02:00
rust: Add crypto crate and implement Rust wrappers for SHA2 code.
* FIXES #24659: https://bugs.torproject.org/24659
This commit is contained in:
parent
3df37d7b6b
commit
af182d4ab5
@ -306,7 +306,10 @@ fi
|
||||
AM_CONDITIONAL(USEPYTHON, [test "x$PYTHON" != "x"])
|
||||
|
||||
dnl List all external rust crates we depend on here. Include the version
|
||||
rust_crates="libc-0.2.39"
|
||||
rust_crates=" \
|
||||
digest-0.7.2 \
|
||||
libc-0.2.39 \
|
||||
"
|
||||
AC_SUBST(rust_crates)
|
||||
|
||||
ifdef([AC_C_FLEXIBLE_ARRAY_MEMBER], [
|
||||
|
@ -268,7 +268,11 @@ crypto_digest_new(void)
|
||||
}
|
||||
|
||||
/** Allocate and return a new digest object to compute 256-bit digests
|
||||
* using <b>algorithm</b>. */
|
||||
* using <b>algorithm</b>.
|
||||
*
|
||||
* C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new`
|
||||
* C_RUST_COUPLED: `crypto::digest::Sha256::default`
|
||||
*/
|
||||
crypto_digest_t *
|
||||
crypto_digest256_new(digest_algorithm_t algorithm)
|
||||
{
|
||||
@ -298,6 +302,9 @@ crypto_digest_free_(crypto_digest_t *digest)
|
||||
}
|
||||
|
||||
/** Add <b>len</b> bytes from <b>data</b> to the digest object.
|
||||
*
|
||||
* C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess`
|
||||
* C_RUST_COUPLED: `crypto::digest::Sha256::process`
|
||||
*/
|
||||
void
|
||||
crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
|
||||
@ -335,6 +342,9 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
|
||||
/** Compute the hash of the data that has been passed to the digest
|
||||
* object; write the first out_len bytes of the result to <b>out</b>.
|
||||
* <b>out_len</b> must be \<= DIGEST512_LEN.
|
||||
*
|
||||
* C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest`
|
||||
* C_RUST_COUPLED: `impl digest::FixedOutput for Sha256`
|
||||
*/
|
||||
void
|
||||
crypto_digest_get_digest(crypto_digest_t *digest,
|
||||
@ -383,6 +393,9 @@ crypto_digest_get_digest(crypto_digest_t *digest,
|
||||
|
||||
/** Allocate and return a new digest object with the same state as
|
||||
* <b>digest</b>
|
||||
*
|
||||
* C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup`
|
||||
* C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256`
|
||||
*/
|
||||
crypto_digest_t *
|
||||
crypto_digest_dup(const crypto_digest_t *digest)
|
||||
|
35
src/rust/Cargo.lock
generated
35
src/rust/Cargo.lock
generated
@ -1,8 +1,35 @@
|
||||
[[package]]
|
||||
name = "crypto"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"external 0.0.1",
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smartlist 0.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "external"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smartlist 0.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -87,7 +114,15 @@ dependencies = [
|
||||
"tor_log 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
|
||||
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
|
||||
"checksum rand 0.5.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7d7a7728c20bfd9fcc6e713e748e787c3d00e5ffd139b3ad1b5be92c5dfbaad5"
|
||||
"checksum rand_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0224284424a4b818387b58d59336c288f99b48f69681aa60cc681fe038bbca5d"
|
||||
"checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd"
|
||||
|
@ -1,7 +1,14 @@
|
||||
[workspace]
|
||||
members = ["tor_util", "protover", "smartlist", "external", "tor_allocate",
|
||||
"tor_rust", "tor_log",
|
||||
members = [
|
||||
"crypto",
|
||||
"external",
|
||||
"protover",
|
||||
"rand",
|
||||
"smartlist",
|
||||
"tor_allocate",
|
||||
"tor_log",
|
||||
"tor_rust",
|
||||
"tor_util",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
21
src/rust/crypto/Cargo.toml
Normal file
21
src/rust/crypto/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
authors = ["The Tor Project",
|
||||
"Isis Lovecruft <isis@torproject.org>"]
|
||||
name = "crypto"
|
||||
version = "0.0.1"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "crypto"
|
||||
path = "lib.rs"
|
||||
crate_type = ["rlib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
libc = "=0.2.39"
|
||||
digest = "=0.7.2"
|
||||
|
||||
[dependencies.external]
|
||||
path = "../external"
|
||||
|
||||
[dependencies.smartlist]
|
||||
path = "../smartlist"
|
7
src/rust/crypto/digests/mod.rs
Normal file
7
src/rust/crypto/digests/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2018, The Tor Project, Inc.
|
||||
// Copyright (c) 2018, isis agora lovecruft
|
||||
// See LICENSE for licensing information
|
||||
|
||||
//! Hash Digests and eXtendible Output Functions (XOFs)
|
||||
|
||||
pub mod sha2;
|
213
src/rust/crypto/digests/sha2.rs
Normal file
213
src/rust/crypto/digests/sha2.rs
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright (c) 2018, The Tor Project, Inc.
|
||||
// Copyright (c) 2018, isis agora lovecruft
|
||||
// See LICENSE for licensing information
|
||||
|
||||
//! Hash Digests and eXtendible Output Functions (XOFs)
|
||||
|
||||
pub use digest::Digest;
|
||||
|
||||
use digest::BlockInput;
|
||||
use digest::FixedOutput;
|
||||
use digest::Input;
|
||||
use digest::generic_array::GenericArray;
|
||||
use digest::generic_array::typenum::U32;
|
||||
use digest::generic_array::typenum::U64;
|
||||
|
||||
use external::crypto_digest::CryptoDigest;
|
||||
use external::crypto_digest::DigestAlgorithm;
|
||||
use external::crypto_digest::get_256_bit_digest;
|
||||
use external::crypto_digest::get_512_bit_digest;
|
||||
|
||||
pub use external::crypto_digest::DIGEST256_LEN;
|
||||
pub use external::crypto_digest::DIGEST512_LEN;
|
||||
|
||||
/// The block size for both SHA-256 and SHA-512 digests is 512 bits/64 bytes.
|
||||
///
|
||||
/// Unfortunately, we have to use the generic_array crate currently to express
|
||||
/// this at compile time. Later, in the future, when Rust implements const
|
||||
/// generics, we'll be able to remove this dependency (actually, it will get
|
||||
/// removed from the digest crate, which is currently `pub use`ing it).
|
||||
type BlockSize = U64;
|
||||
|
||||
/// A SHA2-256 digest.
|
||||
///
|
||||
/// # C_RUST_COUPLED
|
||||
///
|
||||
/// * `crypto_digest_dup`
|
||||
#[derive(Clone)]
|
||||
pub struct Sha256 {
|
||||
engine: CryptoDigest,
|
||||
}
|
||||
|
||||
/// Construct a new, default instance of a `Sha256` hash digest function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use crypto::digest::Sha256;
|
||||
///
|
||||
/// let hasher: Sha256 = Sha256::default();
|
||||
/// ```
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new `Sha256` digest.
|
||||
impl Default for Sha256 {
|
||||
fn default() -> Sha256 {
|
||||
Sha256{ engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_256)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for Sha256 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
/// Input `msg` into the digest.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use crypto::digest::Sha256;
|
||||
///
|
||||
/// let hasher: Sha256 = Sha256::default();
|
||||
///
|
||||
/// hasher.process(b"foo");
|
||||
/// hasher.process(b"bar");
|
||||
/// ```
|
||||
impl Input for Sha256 {
|
||||
fn process(&mut self, msg: &[u8]) {
|
||||
self.engine.add_bytes(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the output hash from everything which has been fed into this
|
||||
/// `Sha256` digest thus far.
|
||||
///
|
||||
//
|
||||
// FIXME: Once const generics land in Rust, we should genericise calling
|
||||
// crypto_digest_get_digest in external::crypto_digest.
|
||||
impl FixedOutput for Sha256 {
|
||||
type OutputSize = U32;
|
||||
|
||||
fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
|
||||
let buffer: [u8; DIGEST256_LEN] = get_256_bit_digest(self.engine);
|
||||
|
||||
GenericArray::from(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
/// A SHA2-512 digest.
|
||||
///
|
||||
/// # C_RUST_COUPLED
|
||||
///
|
||||
/// * `crypto_digest_dup`
|
||||
#[derive(Clone)]
|
||||
pub struct Sha512 {
|
||||
engine: CryptoDigest,
|
||||
}
|
||||
|
||||
/// Construct a new, default instance of a `Sha512` hash digest function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use crypto::digest::Sha512;
|
||||
///
|
||||
/// let hasher: Sha256 = Sha512::default();
|
||||
/// ```
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new `Sha512` digest.
|
||||
impl Default for Sha512 {
|
||||
fn default() -> Sha512 {
|
||||
Sha512{ engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_512)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for Sha512 {
|
||||
type BlockSize = BlockSize;
|
||||
}
|
||||
|
||||
/// Input `msg` into the digest.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use crypto::digest::Sha512;
|
||||
///
|
||||
/// let hasher: Sha512 = Sha512::default();
|
||||
///
|
||||
/// hasher.process(b"foo");
|
||||
/// hasher.process(b"bar");
|
||||
/// ```
|
||||
impl Input for Sha512 {
|
||||
fn process(&mut self, msg: &[u8]) {
|
||||
self.engine.add_bytes(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the output hash from everything which has been fed into this
|
||||
/// `Sha512` digest thus far.
|
||||
///
|
||||
//
|
||||
// FIXME: Once const generics land in Rust, we should genericise calling
|
||||
// crypto_digest_get_digest in external::crypto_digest.
|
||||
impl FixedOutput for Sha512 {
|
||||
type OutputSize = U32;
|
||||
|
||||
fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
|
||||
let buffer: [u8; DIGEST512_LEN] = get_512_bit_digest(self.engine);
|
||||
|
||||
GenericArray::clone_from_slice(&buffer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use digest::Digest;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sha256_default() {
|
||||
let _: Sha256 = Sha256::default();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha256_digest() {
|
||||
let mut h: Sha256 = Sha256::new();
|
||||
let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
|
||||
|
||||
h.input(b"foo");
|
||||
h.input(b"bar");
|
||||
h.input(b"baz");
|
||||
|
||||
result.copy_from_slice(h.fixed_result().as_slice());
|
||||
|
||||
println!("{:?}", &result[..]);
|
||||
|
||||
assert_eq!(&result[..], &b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha512_default() {
|
||||
let _: Sha512 = Sha512::default();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha512_digest() {
|
||||
let mut h: Sha512 = Sha512::new();
|
||||
let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
|
||||
|
||||
h.input(b"foo");
|
||||
h.input(b"bar");
|
||||
h.input(b"baz");
|
||||
|
||||
result.copy_from_slice(h.fixed_result().as_slice());
|
||||
|
||||
println!("{:?}", &result[..]);
|
||||
|
||||
assert_eq!(&result[..], &b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"[..]);
|
||||
}
|
||||
}
|
36
src/rust/crypto/lib.rs
Normal file
36
src/rust/crypto/lib.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2018, The Tor Project, Inc.
|
||||
// Copyright (c) 2018, isis agora lovecruft
|
||||
// See LICENSE for licensing information
|
||||
|
||||
//! Common cryptographic functions and utilities.
|
||||
//!
|
||||
//! # Hash Digests and eXtendable Output Functions (XOFs)
|
||||
//!
|
||||
//! The `digests` module contains submodules for specific hash digests
|
||||
//! and extendable output functions.
|
||||
//!
|
||||
//! ```
|
||||
//! use crypto::digests::sha256::Sha256;
|
||||
//!
|
||||
//! let hasher: Sha256 = Sha256::default();
|
||||
//! let mut result: [u8; 32] = [0u8; 32];
|
||||
//!
|
||||
//! hasher.input("foo");
|
||||
//! hasher.input("bar");
|
||||
//! hasher.input("baz");
|
||||
//!
|
||||
//! result.copy_from_slice(hasher.result().as_bytes());
|
||||
//!
|
||||
//! assert!(result == "XXX");
|
||||
//! ```
|
||||
|
||||
#[deny(missing_docs)]
|
||||
|
||||
// External crates from cargo or TOR_RUST_DEPENDENCIES.
|
||||
extern crate digest;
|
||||
extern crate libc;
|
||||
|
||||
// Our local crates.
|
||||
extern crate external;
|
||||
|
||||
mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate
|
3
src/rust/external/Cargo.toml
vendored
3
src/rust/external/Cargo.toml
vendored
@ -6,6 +6,9 @@ name = "external"
|
||||
[dependencies]
|
||||
libc = "=0.2.39"
|
||||
|
||||
[dependencies.smartlist]
|
||||
path = "../smartlist"
|
||||
|
||||
[lib]
|
||||
name = "external"
|
||||
path = "lib.rs"
|
||||
|
402
src/rust/external/crypto_digest.rs
vendored
Normal file
402
src/rust/external/crypto_digest.rs
vendored
Normal file
@ -0,0 +1,402 @@
|
||||
// Copyright (c) 2018, 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 total number of digest algorithms we currently support.
|
||||
///
|
||||
/// 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_DIGEST_ALGORITHMS: usize = DIGEST_SHA3_512 as usize + 1;
|
||||
|
||||
/// 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 couterpart.
|
||||
_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 couterpart.
|
||||
_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)]
|
||||
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 behvaiour 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)));
|
||||
}
|
||||
}
|
4
src/rust/external/lib.rs
vendored
4
src/rust/external/lib.rs
vendored
@ -9,8 +9,10 @@
|
||||
|
||||
extern crate libc;
|
||||
|
||||
extern crate smartlist;
|
||||
|
||||
pub mod crypto_digest;
|
||||
mod crypto_rand;
|
||||
mod external;
|
||||
|
||||
pub use crypto_rand::*;
|
||||
pub use external::*;
|
||||
|
@ -4,7 +4,12 @@ EXTRA_DIST +=\
|
||||
src/rust/Cargo.toml \
|
||||
src/rust/Cargo.lock \
|
||||
src/rust/.cargo/config.in \
|
||||
src/rust/crypto/Cargo.toml \
|
||||
src/rust/crypto/lib.rs \
|
||||
src/rust/crypto/digests/mod.rs \
|
||||
src/rust/crypto/digests/sha2.rs \
|
||||
src/rust/external/Cargo.toml \
|
||||
src/rust/external/crypto_digest.rs \
|
||||
src/rust/external/crypto_rand.rs \
|
||||
src/rust/external/external.rs \
|
||||
src/rust/external/lib.rs \
|
||||
|
Loading…
Reference in New Issue
Block a user