Merge pull request #9586 from holtrop-wolfssl/rust-blake2

Rust wrapper: add wolfssl_wolfcrypt::blake2 module
This commit is contained in:
David Garske
2025-12-29 09:55:58 -08:00
committed by GitHub
5 changed files with 401 additions and 0 deletions

View File

@@ -4,6 +4,7 @@
EXTRA_DIST += wrapper/rust/Makefile
EXTRA_DIST += wrapper/rust/README.md
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/Cargo.lock
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/Cargo.toml
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/Makefile
@@ -11,6 +12,7 @@ EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/README.md
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/build.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/headers.h
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/aes.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/dh.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs
@@ -26,6 +28,7 @@ EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/sha.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/sys.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs
EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_ecc.rs

View File

@@ -126,6 +126,10 @@ fn scan_cfg() -> Result<()> {
check_cfg(&binding, "wc_AesXtsInit", "aes_xts");
check_cfg(&binding, "wc_AesXtsEncryptInit", "aes_xts_stream");
/* blake2 */
check_cfg(&binding, "wc_InitBlake2b", "blake2b");
check_cfg(&binding, "wc_InitBlake2s", "blake2s");
/* cmac */
check_cfg(&binding, "wc_InitCmac", "cmac");

View File

@@ -0,0 +1,305 @@
/*
* Copyright (C) 2025 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.
*/
use crate::sys;
use std::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<Self, i32> {
let digest_size = digest_size as u32;
let mut wc_blake2b: MaybeUninit<sys::Blake2b> = 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<Self, i32> {
let digest_size = digest_size as u32;
let mut wc_blake2b: MaybeUninit<sys::Blake2b> = MaybeUninit::uninit();
let key_size = key.len() as u32;
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 = data.len() as u32;
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 = hash.len() as u32;
let rc = unsafe {
sys::wc_Blake2bFinal(&mut self.wc_blake2b, hash.as_mut_ptr(), hash_size)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
}
/// 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<Self, i32> {
let digest_size = digest_size as u32;
let mut wc_blake2s: MaybeUninit<sys::Blake2s> = 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<Self, i32> {
let digest_size = digest_size as u32;
let mut wc_blake2s: MaybeUninit<sys::Blake2s> = MaybeUninit::uninit();
let key_size = key.len() as u32;
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 = data.len() as u32;
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; 64];
/// blake2s.finalize(&mut hash).expect("Error with finalize()");
/// ```
pub fn finalize(&mut self, hash: &mut [u8]) -> Result<(), i32> {
let hash_size = hash.len() as u32;
let rc = unsafe {
sys::wc_Blake2sFinal(&mut self.wc_blake2s, hash.as_mut_ptr(), hash_size)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
}

View File

@@ -22,6 +22,7 @@
pub mod sys;
pub mod aes;
pub mod blake2;
pub mod cmac;
pub mod dh;
pub mod ecc;

View File

@@ -0,0 +1,88 @@
#[cfg(any(blake2b, blake2s))]
use wolfssl_wolfcrypt::blake2::*;
#[test]
#[cfg(blake2b)]
fn test_blake2b() {
let expected_hashes: [&[u8]; 3] = [
&[
0x78, 0x6A, 0x02, 0xF7, 0x42, 0x01, 0x59, 0x03,
0xC6, 0xC6, 0xFD, 0x85, 0x25, 0x52, 0xD2, 0x72,
0x91, 0x2F, 0x47, 0x40, 0xE1, 0x58, 0x47, 0x61,
0x8A, 0x86, 0xE2, 0x17, 0xF7, 0x1F, 0x54, 0x19,
0xD2, 0x5E, 0x10, 0x31, 0xAF, 0xEE, 0x58, 0x53,
0x13, 0x89, 0x64, 0x44, 0x93, 0x4E, 0xB0, 0x4B,
0x90, 0x3A, 0x68, 0x5B, 0x14, 0x48, 0xB7, 0x55,
0xD5, 0x6F, 0x70, 0x1A, 0xFE, 0x9B, 0xE2, 0xCE
],
&[
0x2F, 0xA3, 0xF6, 0x86, 0xDF, 0x87, 0x69, 0x95,
0x16, 0x7E, 0x7C, 0x2E, 0x5D, 0x74, 0xC4, 0xC7,
0xB6, 0xE4, 0x8F, 0x80, 0x68, 0xFE, 0x0E, 0x44,
0x20, 0x83, 0x44, 0xD4, 0x80, 0xF7, 0x90, 0x4C,
0x36, 0x96, 0x3E, 0x44, 0x11, 0x5F, 0xE3, 0xEB,
0x2A, 0x3A, 0xC8, 0x69, 0x4C, 0x28, 0xBC, 0xB4,
0xF5, 0xA0, 0xF3, 0x27, 0x6F, 0x2E, 0x79, 0x48,
0x7D, 0x82, 0x19, 0x05, 0x7A, 0x50, 0x6E, 0x4B
],
&[
0x1C, 0x08, 0x79, 0x8D, 0xC6, 0x41, 0xAB, 0xA9,
0xDE, 0xE4, 0x35, 0xE2, 0x25, 0x19, 0xA4, 0x72,
0x9A, 0x09, 0xB2, 0xBF, 0xE0, 0xFF, 0x00, 0xEF,
0x2D, 0xCD, 0x8E, 0xD6, 0xF8, 0xA0, 0x7D, 0x15,
0xEA, 0xF4, 0xAE, 0xE5, 0x2B, 0xBF, 0x18, 0xAB,
0x56, 0x08, 0xA6, 0x19, 0x0F, 0x70, 0xB9, 0x04,
0x86, 0xC8, 0xA7, 0xD4, 0x87, 0x37, 0x10, 0xB1,
0x11, 0x5D, 0x3D, 0xEB, 0xBB, 0x43, 0x27, 0xB5
],
];
for (i, expected_hash) in expected_hashes.iter().enumerate() {
let mut blake2b = BLAKE2b::new(expected_hash.len()).expect("Error with new()");
let mut input = vec![0u8; i];
for idx in 0..input.len() {
input[idx] = idx as u8;
}
blake2b.update(&input).expect("Error with update()");
let mut hash = [0u8; 64];
blake2b.finalize(&mut hash).expect("error with finalize()");
assert_eq!(hash, *expected_hash);
}
}
#[test]
#[cfg(blake2s)]
fn test_blake2s() {
let expected_hashes: [&[u8]; 3] = [
&[
0x69, 0x21, 0x7a, 0x30, 0x79, 0x90, 0x80, 0x94,
0xe1, 0x11, 0x21, 0xd0, 0x42, 0x35, 0x4a, 0x7c,
0x1f, 0x55, 0xb6, 0x48, 0x2c, 0xa1, 0xa5, 0x1e,
0x1b, 0x25, 0x0d, 0xfd, 0x1e, 0xd0, 0xee, 0xf9,
],
&[
0xe3, 0x4d, 0x74, 0xdb, 0xaf, 0x4f, 0xf4, 0xc6,
0xab, 0xd8, 0x71, 0xcc, 0x22, 0x04, 0x51, 0xd2,
0xea, 0x26, 0x48, 0x84, 0x6c, 0x77, 0x57, 0xfb,
0xaa, 0xc8, 0x2f, 0xe5, 0x1a, 0xd6, 0x4b, 0xea,
],
&[
0xdd, 0xad, 0x9a, 0xb1, 0x5d, 0xac, 0x45, 0x49,
0xba, 0x42, 0xf4, 0x9d, 0x26, 0x24, 0x96, 0xbe,
0xf6, 0xc0, 0xba, 0xe1, 0xdd, 0x34, 0x2a, 0x88,
0x08, 0xf8, 0xea, 0x26, 0x7c, 0x6e, 0x21, 0x0c,
],
];
for (i, expected_hash) in expected_hashes.iter().enumerate() {
let mut blake2s = BLAKE2s::new(expected_hash.len()).expect("Error with new()");
let mut input = vec![0u8; i];
for idx in 0..input.len() {
input[idx] = idx as u8;
}
blake2s.update(&input).expect("Error with update()");
let mut hash = [0u8; 32];
blake2s.finalize(&mut hash).expect("error with finalize()");
assert_eq!(hash, *expected_hash);
}
}