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