crypto_digest.rs 15 KB

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