/* * Copyright (C) 2006-2026 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ /*! This module provides a Rust wrapper for the wolfCrypt library's BLAKE2 functionality. */ #![cfg(any(blake2b, blake2s))] use crate::sys; use core::mem::MaybeUninit; /// Context for BLAKE2b computation. #[cfg(blake2b)] pub struct BLAKE2b { wc_blake2b: sys::Blake2b, } #[cfg(blake2b)] impl BLAKE2b { /// Build a new BLAKE2b instance. /// /// # Parameters /// /// * `digest_size`: Length of the blake 2 digest to implement. /// /// # Returns /// /// Returns either Ok(blake2b) containing the BLAKE2b struct instance or /// Err(e) containing the wolfSSL library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2b; /// let blake2b = BLAKE2b::new(64).expect("Error with new()"); /// ``` pub fn new(digest_size: usize) -> Result { let digest_size = crate::buffer_len_to_u32(digest_size)?; let mut wc_blake2b: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_InitBlake2b(wc_blake2b.as_mut_ptr(), digest_size) }; if rc != 0 { return Err(rc); } let wc_blake2b = unsafe { wc_blake2b.assume_init() }; let blake2b = BLAKE2b { wc_blake2b }; Ok(blake2b) } /// Build a new BLAKE2b instance. /// /// # Parameters /// /// * `digest_size`: Length of the blake 2 digest to implement. /// * `key`: Key to use for BLAKE2b operation. /// /// # Returns /// /// Returns either Ok(blake2b) containing the BLAKE2b struct instance or /// Err(e) containing the wolfSSL library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2b; /// let key = [42u8; 32]; /// let blake2b = BLAKE2b::new_with_key(64, &key).expect("Error with new()"); /// ``` pub fn new_with_key(digest_size: usize, key: &[u8]) -> Result { let key_size = crate::buffer_len_to_u32(key.len())?; let digest_size = crate::buffer_len_to_u32(digest_size)?; let mut wc_blake2b: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_InitBlake2b_WithKey(wc_blake2b.as_mut_ptr(), digest_size, key.as_ptr(), key_size) }; if rc != 0 { return Err(rc); } let wc_blake2b = unsafe { wc_blake2b.assume_init() }; let blake2b = BLAKE2b { wc_blake2b }; Ok(blake2b) } /// Update the BLAKE2b hash with the input data. /// /// This method may be called several times and then the finalize() /// method should be called to retrieve the final hash. /// /// # Parameters /// /// * `data`: Input data to hash. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2b; /// let mut blake2b = BLAKE2b::new(64).expect("Error with new()"); /// blake2b.update(&[0u8; 16]).expect("Error with update()"); /// ``` pub fn update(&mut self, data: &[u8]) -> Result<(), i32> { let data_size = crate::buffer_len_to_u32(data.len())?; let rc = unsafe { sys::wc_Blake2bUpdate(&mut self.wc_blake2b, data.as_ptr(), data_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Compute and retrieve the final BLAKE2b hash value. /// /// # Parameters /// /// * `hash`: Output buffer in which to store the computed BLAKE2b hash /// value. It can be any length. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2b; /// let mut blake2b = BLAKE2b::new(64).expect("Error with new()"); /// blake2b.update(&[0u8; 16]).expect("Error with update()"); /// let mut hash = [0u8; 64]; /// blake2b.finalize(&mut hash).expect("Error with finalize()"); /// ``` pub fn finalize(&mut self, hash: &mut [u8]) -> Result<(), i32> { let hash_size = crate::buffer_len_to_u32(hash.len())?; if hash_size == 0 { // The C function uses the internal state configured digest size // if hash_size is passed in as 0. We do not want to allow a // buffer overrun, so do not allow an empty hash buffer here. return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); } let rc = unsafe { sys::wc_Blake2bFinal(&mut self.wc_blake2b, hash.as_mut_ptr(), hash_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(blake2b)] impl BLAKE2b { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.wc_blake2b); } } } #[cfg(blake2b)] impl Drop for BLAKE2b { fn drop(&mut self) { self.zeroize(); } } /// Context for HMAC-BLAKE2b computation. #[cfg(blake2b_hmac)] pub struct BLAKE2bHmac { wc_blake2b: sys::Blake2b, } #[cfg(blake2b_hmac)] impl BLAKE2bHmac { /// HMAC-BLAKE2b digest size. pub const DIGEST_SIZE: usize = sys::WC_BLAKE2B_DIGEST_SIZE as usize; /// Build a new BLAKE2bHmac instance. /// /// # Parameters /// /// * `key`: Key to use for HMAC-BLAKE2b computation. /// /// # Returns /// /// Returns either Ok(hmac_blake2b) or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2bHmac; /// let key = [42u8, 43, 44]; /// let hmac_blake2b = BLAKE2bHmac::new(&key).expect("Error with new()"); /// ``` pub fn new(key: &[u8]) -> Result { let mut wc_blake2b: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_Blake2bHmacInit(wc_blake2b.as_mut_ptr(), key.as_ptr(), key.len()) }; if rc != 0 { return Err(rc); } let wc_blake2b = unsafe { wc_blake2b.assume_init() }; let hmac_blake2b = BLAKE2bHmac { wc_blake2b }; Ok(hmac_blake2b) } /// Update the HMAC-BLAKE2b computation with the input data. /// /// This method may be called several times and then the finalize() /// method should be called to retrieve the final MAC. /// /// # Parameters /// /// * `data`: Input data to hash. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2bHmac; /// let key = [42u8, 43, 44]; /// let mut hmac_blake2b = BLAKE2bHmac::new(&key).expect("Error with new()"); /// let data = [33u8, 34, 35]; /// hmac_blake2b.update(&data).expect("Error with update()"); /// ``` pub fn update(&mut self, data: &[u8]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2bHmacUpdate(&mut self.wc_blake2b, data.as_ptr(), data.len()) }; if rc != 0 { return Err(rc); } Ok(()) } /// Compute and retrieve the final HMAC-BLAKE2b MAC. /// /// # Parameters /// /// * `key`: Key to use for HMAC-BLAKE2b computation. /// * `mac`: Output buffer in which to store the computed HMAC-BLAKE2b MAC. /// It must be 64 bytes long. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2bHmac; /// let key = [42u8, 43, 44]; /// let mut hmac_blake2b = BLAKE2bHmac::new(&key).expect("Error with new()"); /// let data = [33u8, 34, 35]; /// hmac_blake2b.update(&data).expect("Error with update()"); /// let mut mac = [0u8; 64]; /// hmac_blake2b.finalize(&key, &mut mac).expect("Error with finalize()"); /// ``` pub fn finalize(&mut self, key: &[u8], mac: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2bHmacFinal(&mut self.wc_blake2b, key.as_ptr(), key.len(), mac.as_mut_ptr(), mac.len()) }; if rc != 0 { return Err(rc); } Ok(()) } /// Compute the HMAC-BLAKE2b message authentication code of the given /// input data using the given key (one-shot API). /// /// # Parameters /// /// * `data`: Input data to create MAC from. /// * `key`: Key to use for MAC creation. /// * `out`: Buffer in which to store the computed MAC. It must be 64 bytes /// long. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2bHmac(data.as_ptr(), data.len(), key.as_ptr(), key.len(), out.as_mut_ptr(), out.len()) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(blake2b_hmac)] impl BLAKE2bHmac { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.wc_blake2b); } } } #[cfg(blake2b_hmac)] impl Drop for BLAKE2bHmac { fn drop(&mut self) { self.zeroize(); } } /// Context for BLAKE2s computation. #[cfg(blake2s)] pub struct BLAKE2s { wc_blake2s: sys::Blake2s, } #[cfg(blake2s)] impl BLAKE2s { /// Build a new BLAKE2s instance. /// /// # Parameters /// /// * `digest_size`: Length of the blake 2 digest to implement. /// /// # Returns /// /// Returns either Ok(blake2s) containing the BLAKE2s struct instance or /// Err(e) containing the wolfSSL library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2s; /// let blake2s = BLAKE2s::new(32).expect("Error with new()"); /// ``` pub fn new(digest_size: usize) -> Result { let digest_size = crate::buffer_len_to_u32(digest_size)?; let mut wc_blake2s: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_InitBlake2s(wc_blake2s.as_mut_ptr(), digest_size) }; if rc != 0 { return Err(rc); } let wc_blake2s = unsafe { wc_blake2s.assume_init() }; let blake2s = BLAKE2s { wc_blake2s }; Ok(blake2s) } /// Build a new BLAKE2s instance. /// /// # Parameters /// /// * `digest_size`: Length of the blake 2 digest to implement. /// * `key`: Key to use for BLAKE2s operation. /// /// # Returns /// /// Returns either Ok(blake2s) containing the BLAKE2s struct instance or /// Err(e) containing the wolfSSL library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2s; /// let key = [42u8; 32]; /// let blake2s = BLAKE2s::new_with_key(32, &key).expect("Error with new()"); /// ``` pub fn new_with_key(digest_size: usize, key: &[u8]) -> Result { let key_size = crate::buffer_len_to_u32(key.len())?; let digest_size = crate::buffer_len_to_u32(digest_size)?; let mut wc_blake2s: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_InitBlake2s_WithKey(wc_blake2s.as_mut_ptr(), digest_size, key.as_ptr(), key_size) }; if rc != 0 { return Err(rc); } let wc_blake2s = unsafe { wc_blake2s.assume_init() }; let blake2s = BLAKE2s { wc_blake2s }; Ok(blake2s) } /// Update the BLAKE2s hash with the input data. /// /// This method may be called several times and then the finalize() /// method should be called to retrieve the final hash. /// /// # Parameters /// /// * `data`: Input data to hash. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2s; /// let mut blake2s = BLAKE2s::new(32).expect("Error with new()"); /// blake2s.update(&[0u8; 16]).expect("Error with update()"); /// ``` pub fn update(&mut self, data: &[u8]) -> Result<(), i32> { let data_size = crate::buffer_len_to_u32(data.len())?; let rc = unsafe { sys::wc_Blake2sUpdate(&mut self.wc_blake2s, data.as_ptr(), data_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Compute and retrieve the final BLAKE2s hash value. /// /// # Parameters /// /// * `hash`: Output buffer in which to store the computed BLAKE2s hash /// value. It can be any length. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2s; /// let mut blake2s = BLAKE2s::new(32).expect("Error with new()"); /// blake2s.update(&[0u8; 16]).expect("Error with update()"); /// let mut hash = [0u8; 32]; /// blake2s.finalize(&mut hash).expect("Error with finalize()"); /// ``` pub fn finalize(&mut self, hash: &mut [u8]) -> Result<(), i32> { let hash_size = crate::buffer_len_to_u32(hash.len())?; if hash_size == 0 { // The C function uses the internal state configured digest size // if hash_size is passed in as 0. We do not want to allow a // buffer overrun, so do not allow an empty hash buffer here. return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); } let rc = unsafe { sys::wc_Blake2sFinal(&mut self.wc_blake2s, hash.as_mut_ptr(), hash_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(blake2s)] impl BLAKE2s { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.wc_blake2s); } } } #[cfg(blake2s)] impl Drop for BLAKE2s { fn drop(&mut self) { self.zeroize(); } } /// Context for HMAC-BLAKE2s computation. #[cfg(blake2s_hmac)] pub struct BLAKE2sHmac { wc_blake2s: sys::Blake2s, } #[cfg(blake2s_hmac)] impl BLAKE2sHmac { /// HMAC-BLAKE2s digest size. pub const DIGEST_SIZE: usize = sys::WC_BLAKE2S_DIGEST_SIZE as usize; /// Build a new BLAKE2sHmac instance. /// /// # Parameters /// /// * `key`: Key to use for HMAC-BLAKE2s computation. /// /// # Returns /// /// Returns either Ok(hmac_blake2s) or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2sHmac; /// let key = [42u8, 43, 44]; /// let hmac_blake2s = BLAKE2sHmac::new(&key).expect("Error with new()"); /// ``` pub fn new(key: &[u8]) -> Result { let mut wc_blake2s: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_Blake2sHmacInit(wc_blake2s.as_mut_ptr(), key.as_ptr(), key.len()) }; if rc != 0 { return Err(rc); } let wc_blake2s = unsafe { wc_blake2s.assume_init() }; let hmac_blake2s = BLAKE2sHmac { wc_blake2s }; Ok(hmac_blake2s) } /// Update the HMAC-BLAKE2s computation with the input data. /// /// This method may be called several times and then the finalize() /// method should be called to retrieve the final MAC. /// /// # Parameters /// /// * `data`: Input data to hash. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2sHmac; /// let key = [42u8, 43, 44]; /// let mut hmac_blake2s = BLAKE2sHmac::new(&key).expect("Error with new()"); /// let data = [33u8, 34, 35]; /// hmac_blake2s.update(&data).expect("Error with update()"); /// ``` pub fn update(&mut self, data: &[u8]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2sHmacUpdate(&mut self.wc_blake2s, data.as_ptr(), data.len()) }; if rc != 0 { return Err(rc); } Ok(()) } /// Compute and retrieve the final HMAC-BLAKE2s MAC. /// /// # Parameters /// /// * `key`: Key to use for HMAC-BLAKE2s computation. /// * `mac`: Output buffer in which to store the computed HMAC-BLAKE2s MAC. /// It must be 32 bytes long. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. /// /// # Example /// /// ```rust /// use wolfssl_wolfcrypt::blake2::BLAKE2sHmac; /// let key = [42u8, 43, 44]; /// let mut hmac_blake2s = BLAKE2sHmac::new(&key).expect("Error with new()"); /// let data = [33u8, 34, 35]; /// hmac_blake2s.update(&data).expect("Error with update()"); /// let mut mac = [0u8; 32]; /// hmac_blake2s.finalize(&key, &mut mac).expect("Error with finalize()"); /// ``` pub fn finalize(&mut self, key: &[u8], mac: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2sHmacFinal(&mut self.wc_blake2s, key.as_ptr(), key.len(), mac.as_mut_ptr(), mac.len()) }; if rc != 0 { return Err(rc); } Ok(()) } /// Compute the HMAC-BLAKE2s message authentication code of the given /// input data using the given key (one-shot API). /// /// # Parameters /// /// * `data`: Input data to create MAC from. /// * `key`: Key to use for MAC creation. /// * `out`: Buffer in which to store the computed MAC. It must be 32 bytes /// long. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2sHmac(data.as_ptr(), data.len(), key.as_ptr(), key.len(), out.as_mut_ptr(), out.len()) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(blake2s_hmac)] impl BLAKE2sHmac { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.wc_blake2s); } } } #[cfg(blake2s_hmac)] impl Drop for BLAKE2sHmac { fn drop(&mut self) { self.zeroize(); } }