mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-26 14:52:21 +01:00
Merge pull request #9352 from holtrop/rust-wc-cmac
Rust wrapper: add wolfssl::wolfcrypt::cmac module
This commit is contained in:
@@ -174,8 +174,8 @@ int wc_AesCmacGenerate(byte* out, word32* outSz,
|
||||
\ingroup CMAC
|
||||
\brief Single shot function for validating a CMAC
|
||||
\return 0 on success
|
||||
\param check pointer to return the result
|
||||
\param checkSz size of checkout buffer
|
||||
\param check CMAC value to verify
|
||||
\param checkSz size of check buffer
|
||||
\param in input data to process
|
||||
\param inSz size of input data
|
||||
\param key key pointer
|
||||
|
||||
@@ -17,6 +17,7 @@ EXTRA_DIST += wrapper/rust/wolfssl/build.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/lib.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/aes.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/cmac.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/dh.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/ecc.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/hkdf.rs
|
||||
@@ -27,6 +28,7 @@ EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/random.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/rsa.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/sha.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_aes.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_cmac.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_dh.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_ecc.rs
|
||||
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_hkdf.rs
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
pub mod aes;
|
||||
pub mod cmac;
|
||||
pub mod dh;
|
||||
pub mod ecc;
|
||||
pub mod hkdf;
|
||||
|
||||
252
wrapper/rust/wolfssl/src/wolfcrypt/cmac.rs
Normal file
252
wrapper/rust/wolfssl/src/wolfcrypt/cmac.rs
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* 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 Cipher-based
|
||||
Message Authentication Code (CMAC) functionality.
|
||||
|
||||
It leverages the `wolfssl-sys` crate for low-level FFI bindings, encapsulating
|
||||
the raw C functions in a memory-safe and easy-to-use Rust API.
|
||||
*/
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
use wolfssl_sys as ws;
|
||||
|
||||
/// The `CMAC` struct manages the lifecycle of a wolfSSL `Cmac` object.
|
||||
///
|
||||
/// It ensures proper initialization and deallocation.
|
||||
///
|
||||
/// An instance can be created with `new()`.
|
||||
pub struct CMAC {
|
||||
ws_cmac: ws::Cmac,
|
||||
}
|
||||
impl CMAC {
|
||||
/// One-shot CMAC generation function.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `key`: Key to use for CMAC generation.
|
||||
/// * `data`: CMAC input data.
|
||||
/// * `dout`: Output buffer where CMAC is written.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
|
||||
/// library error code value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use wolfssl::wolfcrypt::cmac::CMAC;
|
||||
/// let key = [
|
||||
/// 0x2bu8, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
/// 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
/// ];
|
||||
/// let message = [
|
||||
/// 0x6bu8, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
/// 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
/// ];
|
||||
/// let mut generate_out = [0u8; 16];
|
||||
/// CMAC::generate(&key, &message, &mut generate_out).expect("Error with generate()");
|
||||
/// ```
|
||||
pub fn generate(key: &[u8], data: &[u8], dout: &mut [u8]) -> Result<(), i32> {
|
||||
let key_size = key.len() as u32;
|
||||
let data_size = data.len() as u32;
|
||||
let mut dout_size = dout.len() as u32;
|
||||
let rc = unsafe {
|
||||
ws::wc_AesCmacGenerate(dout.as_mut_ptr(), &mut dout_size,
|
||||
data.as_ptr(), data_size,
|
||||
key.as_ptr(), key_size)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(rc);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a new CMAC object using the given key.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `key`: Key to use for CMAC generation.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns either Ok(cmac) containing the CMAC struct instance or Err(e)
|
||||
/// containing the wolfSSL library error code value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use wolfssl::wolfcrypt::cmac::CMAC;
|
||||
/// let key = [
|
||||
/// 0x2bu8, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
/// 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
/// ];
|
||||
/// let mut cmac = CMAC::new(&key).expect("Error with new()");
|
||||
/// ```
|
||||
pub fn new(key: &[u8]) -> Result<Self, i32> {
|
||||
let key_size = key.len() as u32;
|
||||
let mut ws_cmac: MaybeUninit<ws::Cmac> = MaybeUninit::uninit();
|
||||
let typ = ws::CmacType_WC_CMAC_AES as i32;
|
||||
let rc = unsafe {
|
||||
ws::wc_InitCmac(ws_cmac.as_mut_ptr(), key.as_ptr(), key_size,
|
||||
typ, core::ptr::null_mut())
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(rc);
|
||||
}
|
||||
let ws_cmac = unsafe { ws_cmac.assume_init() };
|
||||
let cmac = CMAC { ws_cmac };
|
||||
Ok(cmac)
|
||||
}
|
||||
|
||||
/// One-shot CMAC verification function.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `key`: Key to use for CMAC generation.
|
||||
/// * `data`: CMAC input data.
|
||||
/// * `check`: CMAC value to compare to.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns either Ok(valid) (with valid indicating if the CMAC passed in
|
||||
/// is correct or not) on success or Err(e) containing the wolfSSL library
|
||||
/// error code value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use wolfssl::wolfcrypt::cmac::CMAC;
|
||||
/// let key = [
|
||||
/// 0x2bu8, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
/// 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
/// ];
|
||||
/// let message = [
|
||||
/// 0x6bu8, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
/// 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
/// ];
|
||||
/// let mut generate_out = [0u8; 16];
|
||||
/// CMAC::generate(&key, &message, &mut generate_out).expect("Error with generate()");
|
||||
/// let valid = CMAC::verify(&key, &message, &generate_out).expect("Error with verify()");
|
||||
/// assert!(valid);
|
||||
/// ```
|
||||
pub fn verify(key: &[u8], data: &[u8], check: &[u8]) -> Result<bool, i32> {
|
||||
let key_size = key.len() as u32;
|
||||
let data_size = data.len() as u32;
|
||||
let check_size = check.len() as u32;
|
||||
let rc = unsafe {
|
||||
ws::wc_AesCmacVerify(check.as_ptr(), check_size,
|
||||
data.as_ptr(), data_size,
|
||||
key.as_ptr(), key_size)
|
||||
};
|
||||
if rc < 0 {
|
||||
return Err(rc);
|
||||
}
|
||||
Ok(rc == 0)
|
||||
}
|
||||
|
||||
/// Add CMAC input data.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `data`: CMAC input data.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
|
||||
/// library error code value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use wolfssl::wolfcrypt::cmac::CMAC;
|
||||
/// let key = [
|
||||
/// 0x2bu8, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
/// 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
/// ];
|
||||
/// let message = [
|
||||
/// 0x6bu8, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
/// 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
/// ];
|
||||
/// let mut cmac = CMAC::new(&key).expect("Error with new()");
|
||||
/// cmac.update(&message).expect("Error with update()");
|
||||
/// ```
|
||||
pub fn update(&mut self, data: &[u8]) -> Result<(), i32> {
|
||||
let data_size = data.len() as u32;
|
||||
let rc = unsafe {
|
||||
ws::wc_CmacUpdate(&mut self.ws_cmac, data.as_ptr(), data_size)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(rc);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generate the final Cipher-based Message Authentication Code result.
|
||||
///
|
||||
/// This function consumes the `CMAC` object since no further operations
|
||||
/// can be performed with it.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `dout`: Output buffer where CMAC is written.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
|
||||
/// library error code value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use wolfssl::wolfcrypt::cmac::CMAC;
|
||||
/// let key = [
|
||||
/// 0x2bu8, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
/// 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
/// ];
|
||||
/// let message = [
|
||||
/// 0x6bu8, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
/// 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
/// ];
|
||||
/// let mut cmac = CMAC::new(&key).expect("Error with new()");
|
||||
/// cmac.update(&message).expect("Error with update()");
|
||||
/// let mut finalize_out = [0u8; 16];
|
||||
/// cmac.finalize(&mut finalize_out).expect("Error with finalize()");
|
||||
/// ```
|
||||
pub fn finalize(mut self, dout: &mut [u8]) -> Result<(), i32> {
|
||||
let mut dout_size = dout.len() as u32;
|
||||
let rc = unsafe {
|
||||
ws::wc_CmacFinalNoFree(&mut self.ws_cmac,
|
||||
dout.as_mut_ptr(), &mut dout_size)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(rc);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for CMAC {
|
||||
/// Safely free the wolfSSL resources.
|
||||
fn drop(&mut self) {
|
||||
unsafe { ws::wc_CmacFree(&mut self.ws_cmac); }
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ pub fn tls13_hkdf_extract(typ: i32, salt: Option<&[u8]>, key: Option<&mut [u8]>,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Perform RFC 5869 HKDF-Extract operation for TLS v1.3 key derivation.
|
||||
/// Perform RFC 5869 HKDF-Expand operation for TLS v1.3 key derivation.
|
||||
///
|
||||
/// This utilizes HMAC to convert `key`, `label`, and `info` into a
|
||||
/// derived key which is written to `out`.
|
||||
|
||||
28
wrapper/rust/wolfssl/tests/test_cmac.rs
Normal file
28
wrapper/rust/wolfssl/tests/test_cmac.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use wolfssl::wolfcrypt::cmac::CMAC;
|
||||
|
||||
#[test]
|
||||
fn test_cmac() {
|
||||
let key = [
|
||||
0x2bu8, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
];
|
||||
let message = [
|
||||
0x6bu8, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
];
|
||||
let expected_cmac = [
|
||||
0x07u8, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
|
||||
0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c
|
||||
];
|
||||
let mut cmac = CMAC::new(&key).expect("Error with new()");
|
||||
cmac.update(&message).expect("Error with update()");
|
||||
let mut finalize_out = [0u8; 16];
|
||||
cmac.finalize(&mut finalize_out).expect("Error with finalize()");
|
||||
assert_eq!(finalize_out, expected_cmac);
|
||||
|
||||
let mut generate_out = [0u8; 16];
|
||||
CMAC::generate(&key, &message, &mut generate_out).expect("Error with generate()");
|
||||
assert_eq!(generate_out, finalize_out);
|
||||
let valid = CMAC::verify(&key, &message, &generate_out).expect("Error with verify()");
|
||||
assert!(valid);
|
||||
}
|
||||
Reference in New Issue
Block a user