• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2024, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14  */
15 
16 // Generates a hash function from init/update/final-style FFI functions. Rust
17 // doesn't accept function pointers as a generic arguments so this is the only
18 // mechanism to avoid duplicating the code.
19 //
20 // The name is prefixed with "unsafe_" because it contains unsafe blocks.
21 //
22 // Safety: see the "Safety" sections within about the requirements for the
23 // functions named in the macro parameters.
24 macro_rules! unsafe_iuf_algo {
25     ($name:ident, $output_len:expr, $evp_md:ident, $one_shot:ident, $init:ident, $update:ident, $final_func:ident) => {
26         impl Algorithm for $name {
27             const OUTPUT_LEN: usize = $output_len as usize;
28 
29             fn get_md(_: sealed::Sealed) -> &'static MdRef {
30                 // Safety:
31                 // - this always returns a valid pointer to an EVP_MD.
32                 unsafe { MdRef::from_ptr(bssl_sys::$evp_md() as *mut _) }
33             }
34 
35             fn hash_to_vec(input: &[u8]) -> Vec<u8> {
36                 Self::hash(input).as_slice().to_vec()
37             }
38         }
39 
40         impl $name {
41             /// Digest `input` in a single operation.
42             pub fn hash(input: &[u8]) -> [u8; $output_len] {
43                 // Safety: it is assumed that `$one_shot` indeed writes
44                 // `$output_len` bytes.
45                 unsafe {
46                     crate::with_output_array(|out, _| {
47                         bssl_sys::$one_shot(input.as_ffi_ptr(), input.len(), out);
48                     })
49                 }
50             }
51 
52             /// Create a new context for incremental hashing.
53             pub fn new() -> Self {
54                 unsafe {
55                     Self {
56                         ctx: crate::initialized_struct(|ctx| {
57                             // Safety: type checking will ensure that `ctx` is the
58                             // correct type for `$init` to write into.
59                             bssl_sys::$init(ctx);
60                         }),
61                     }
62                 }
63             }
64 
65             /// Hash the contents of `input`.
66             pub fn update(&mut self, input: &[u8]) {
67                 // Safety: arguments point to a valid buffer.
68                 unsafe {
69                     bssl_sys::$update(&mut self.ctx, input.as_ffi_void_ptr(), input.len());
70                 }
71             }
72 
73             /// Finish the hashing and return the digest.
74             pub fn digest(mut self) -> [u8; $output_len] {
75                 // Safety: it is assumed that `$final_func` indeed writes
76                 // `$output_len` bytes.
77                 unsafe {
78                     crate::with_output_array(|out, _| {
79                         bssl_sys::$final_func(out, &mut self.ctx);
80                     })
81                 }
82             }
83         }
84 
85         impl From<$name> for [u8; $output_len] {
86             fn from(ctx: $name) -> [u8; $output_len] {
87                 ctx.digest()
88             }
89         }
90 
91         impl From<$name> for alloc::vec::Vec<u8> {
92             fn from(ctx: $name) -> alloc::vec::Vec<u8> {
93                 ctx.digest().into()
94             }
95         }
96 
97         #[cfg(feature = "std")]
98         impl std::io::Write for $name {
99             fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
100                 self.update(buf);
101                 Ok(buf.len())
102             }
103 
104             fn flush(&mut self) -> std::io::Result<()> {
105                 Ok(())
106             }
107         }
108     };
109 }
110 
111 macro_rules! aead_algo {
112     ($name:ident, $evp_md:ident, $key_len:expr, $nonce_len:expr, $tag_len:expr) => {
113         impl $name {
114             /// Create a new AEAD context for the given key.
115             pub fn new(key: &[u8; $key_len]) -> Self {
116                 // Safety: $evp_md is assumed to return a valid `EVP_MD`.
117                 unsafe { $name(EvpAead::new(key, { bssl_sys::$evp_md() })) }
118             }
119         }
120 
121         impl Aead for $name {
122             type Tag = [u8; $tag_len];
123             type Nonce = [u8; $nonce_len];
124 
125             fn seal(&self, nonce: &Self::Nonce, plaintext: &[u8], ad: &[u8]) -> Vec<u8> {
126                 self.0.seal(nonce, plaintext, ad)
127             }
128 
129             fn seal_in_place(
130                 &self,
131                 nonce: &Self::Nonce,
132                 plaintext: &mut [u8],
133                 ad: &[u8],
134             ) -> Self::Tag {
135                 self.0.seal_in_place(nonce, plaintext, ad)
136             }
137 
138             fn open(&self, nonce: &Self::Nonce, ciphertext: &[u8], ad: &[u8]) -> Option<Vec<u8>> {
139                 self.0.open(nonce, ciphertext, ad)
140             }
141 
142             fn open_in_place(
143                 &self,
144                 nonce: &Self::Nonce,
145                 ciphertext: &mut [u8],
146                 tag: &Self::Tag,
147                 ad: &[u8],
148             ) -> Result<(), InvalidCiphertext> {
149                 self.0.open_in_place(nonce, ciphertext, tag, ad)
150             }
151         }
152     };
153 }
154