| /* Copyright (c) 2024, Google Inc. | |
| * | |
| * Permission to use, copy, modify, and/or distribute this software for any | |
| * purpose with or without fee is hereby granted, provided that the above | |
| * copyright notice and this permission notice appear in all copies. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| */ | |
| // Generates a hash function from init/update/final-style FFI functions. Rust | |
| // doesn't accept function pointers as a generic arguments so this is the only | |
| // mechanism to avoid duplicating the code. | |
| // | |
| // The name is prefixed with "unsafe_" because it contains unsafe blocks. | |
| // | |
| // Safety: see the "Safety" sections within about the requirements for the | |
| // functions named in the macro parameters. | |
| macro_rules! unsafe_iuf_algo { | |
| ($name:ident, $output_len:expr, $block_len:expr, $evp_md:ident, $one_shot:ident, $init:ident, $update:ident, $final_func:ident) => { | |
| impl Algorithm for $name { | |
| const OUTPUT_LEN: usize = $output_len as usize; | |
| const BLOCK_LEN: usize = $block_len as usize; | |
| fn get_md(_: sealed::Sealed) -> &'static MdRef { | |
| // Safety: | |
| // - this always returns a valid pointer to an EVP_MD. | |
| unsafe { MdRef::from_ptr(bssl_sys::$evp_md() as *mut _) } | |
| } | |
| fn hash_to_vec(input: &[u8]) -> Vec<u8> { | |
| Self::hash(input).as_slice().to_vec() | |
| } | |
| /// Create a new context for incremental hashing. | |
| fn new() -> Self { | |
| $name::new() | |
| } | |
| /// Hash the contents of `input`. | |
| fn update(&mut self, input: &[u8]) { | |
| self.update(input); | |
| } | |
| /// Finish the hashing and return the digest. | |
| fn digest_to_vec(self) -> alloc::vec::Vec<u8> { | |
| self.digest().to_vec() | |
| } | |
| } | |
| impl $name { | |
| /// Digest `input` in a single operation. | |
| pub fn hash(input: &[u8]) -> [u8; $output_len] { | |
| // Safety: it is assumed that `$one_shot` indeed writes | |
| // `$output_len` bytes. | |
| unsafe { | |
| crate::with_output_array(|out, _| { | |
| bssl_sys::$one_shot(input.as_ffi_ptr(), input.len(), out); | |
| }) | |
| } | |
| } | |
| /// Create a new context for incremental hashing. | |
| pub fn new() -> Self { | |
| unsafe { | |
| Self { | |
| ctx: crate::initialized_struct(|ctx| { | |
| // Safety: type checking will ensure that `ctx` is the | |
| // correct type for `$init` to write into. | |
| bssl_sys::$init(ctx); | |
| }), | |
| } | |
| } | |
| } | |
| /// Hash the contents of `input`. | |
| pub fn update(&mut self, input: &[u8]) { | |
| // Safety: arguments point to a valid buffer. | |
| unsafe { | |
| bssl_sys::$update(&mut self.ctx, input.as_ffi_void_ptr(), input.len()); | |
| } | |
| } | |
| /// Finish the hashing and return the digest. | |
| pub fn digest(mut self) -> [u8; $output_len] { | |
| // Safety: it is assumed that `$final_func` indeed writes | |
| // `$output_len` bytes. | |
| unsafe { | |
| crate::with_output_array(|out, _| { | |
| bssl_sys::$final_func(out, &mut self.ctx); | |
| }) | |
| } | |
| } | |
| } | |
| impl From<$name> for [u8; $output_len] { | |
| fn from(ctx: $name) -> [u8; $output_len] { | |
| ctx.digest() | |
| } | |
| } | |
| impl From<$name> for alloc::vec::Vec<u8> { | |
| fn from(ctx: $name) -> alloc::vec::Vec<u8> { | |
| ctx.digest_to_vec() | |
| } | |
| } | |
| #[cfg(feature = "std")] | |
| impl std::io::Write for $name { | |
| fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { | |
| self.update(buf); | |
| Ok(buf.len()) | |
| } | |
| fn flush(&mut self) -> std::io::Result<()> { | |
| Ok(()) | |
| } | |
| } | |
| }; | |
| } | |
| macro_rules! aead_algo { | |
| ($name:ident, $evp_md:ident, $key_len:expr, $nonce_len:expr, $tag_len:expr) => { | |
| impl $name { | |
| /// Create a new AEAD context for the given key. | |
| pub fn new(key: &[u8; $key_len]) -> Self { | |
| // Safety: $evp_md is assumed to return a valid `EVP_MD`. | |
| unsafe { $name(EvpAead::new(key, { bssl_sys::$evp_md() })) } | |
| } | |
| } | |
| impl Aead for $name { | |
| type Tag = [u8; $tag_len]; | |
| type Nonce = [u8; $nonce_len]; | |
| fn seal(&self, nonce: &Self::Nonce, plaintext: &[u8], ad: &[u8]) -> Vec<u8> { | |
| self.0.seal(nonce, plaintext, ad) | |
| } | |
| fn seal_in_place( | |
| &self, | |
| nonce: &Self::Nonce, | |
| plaintext: &mut [u8], | |
| ad: &[u8], | |
| ) -> Self::Tag { | |
| self.0.seal_in_place(nonce, plaintext, ad) | |
| } | |
| fn open(&self, nonce: &Self::Nonce, ciphertext: &[u8], ad: &[u8]) -> Option<Vec<u8>> { | |
| self.0.open(nonce, ciphertext, ad) | |
| } | |
| fn open_in_place( | |
| &self, | |
| nonce: &Self::Nonce, | |
| ciphertext: &mut [u8], | |
| tag: &Self::Tag, | |
| ad: &[u8], | |
| ) -> Result<(), InvalidCiphertext> { | |
| self.0.open_in_place(nonce, ciphertext, tag, ad) | |
| } | |
| } | |
| }; | |
| } |