Skip to content

Commit 5b8115e

Browse files
Rust wrapper: add wolfssl::wolfcrypt::kdf, wolfssl::wolfcrypt::prf
1 parent 33b08ed commit 5b8115e

7 files changed

Lines changed: 418 additions & 2 deletions

File tree

doc/dox_comments/header_files/hmac.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,7 @@ int wc_Tls13_HKDF_Expand_Label_ex(
534534
\ingroup HMAC
535535
536536
\brief Expand data using HMAC, salt and label and info. TLS v1.3 defines
537-
this function for key derivation. This is the _ex version adding heap hint
538-
and device identifier.
537+
this function for key derivation.
539538
540539
\return 0 Returned upon successfully generating a key with the given inputs
541540
\return BAD_FUNC_ARG Returned if an invalid hash type is given (see type param)

wrapper/rust/include.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/dh.rs
2121
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/ecc.rs
2222
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/hkdf.rs
2323
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/hmac.rs
24+
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/kdf.rs
25+
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/prf.rs
2426
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/random.rs
2527
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/rsa.rs
2628
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/sha.rs
@@ -29,6 +31,8 @@ EXTRA_DIST += wrapper/rust/wolfssl/tests/test_dh.rs
2931
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_ecc.rs
3032
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_hkdf.rs
3133
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_hmac.rs
34+
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_kdf.rs
35+
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_prf.rs
3236
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_random.rs
3337
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_rsa.rs
3438
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_sha.rs

wrapper/rust/wolfssl/src/wolfcrypt.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub mod dh;
2323
pub mod ecc;
2424
pub mod hkdf;
2525
pub mod hmac;
26+
pub mod kdf;
27+
pub mod prf;
2628
pub mod random;
2729
pub mod rsa;
2830
pub mod sha;
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright (C) 2025 wolfSSL Inc.
3+
*
4+
* This file is part of wolfSSL.
5+
*
6+
* wolfSSL is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfSSL is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
19+
*/
20+
21+
/*!
22+
This module provides a Rust wrapper for the wolfCrypt library's Key Derivation
23+
Function (KDF) functionality.
24+
25+
It leverages the `wolfssl-sys` crate for low-level FFI bindings, encapsulating
26+
the raw C functions in a memory-safe and easy-to-use Rust API.
27+
*/
28+
29+
use crate::wolfcrypt::hmac::HMAC;
30+
use wolfssl_sys as ws;
31+
32+
/// Perform RFC 5869 HKDF-Extract operation for TLS v1.3 key derivation.
33+
///
34+
/// # Parameters
35+
///
36+
/// * `typ`: Hash type, one of `HMAC::TYPE_*`.
37+
/// * `salt`: Optional Salt value.
38+
/// * `key`: Optional Initial Key Material (IKM).
39+
/// * `out`: Output buffer to store TLS1.3 HKDF-Extract result (generated
40+
/// Pseudo-Random Key (PRK)). The size of this buffer must match
41+
/// `HMAC::get_hmac_size_by_type(typ)`.
42+
///
43+
/// # Returns
44+
///
45+
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
46+
/// library error code value.
47+
///
48+
/// # Example
49+
///
50+
/// ```rust
51+
/// use wolfssl::wolfcrypt::hmac::HMAC;
52+
/// use wolfssl::wolfcrypt::kdf::*;
53+
/// use wolfssl_sys as ws;
54+
/// let mut secret = [0u8; ws::WC_SHA256_DIGEST_SIZE as usize];
55+
/// tls13_hkdf_extract(HMAC::TYPE_SHA256, None, None, &mut secret).expect("Error with tls13_hkdf_extract()");
56+
/// ```
57+
pub fn tls13_hkdf_extract(typ: i32, salt: Option<&[u8]>, key: Option<&mut [u8]>, out: &mut [u8]) -> Result<(), i32> {
58+
let mut salt_ptr = core::ptr::null();
59+
let mut salt_size = 0u32;
60+
if let Some(salt) = salt {
61+
salt_ptr = salt.as_ptr();
62+
salt_size = salt.len() as u32;
63+
}
64+
let mut ikm_buf = [0u8; ws::WC_MAX_DIGEST_SIZE as usize];
65+
let mut ikm_ptr = ikm_buf.as_mut_ptr();
66+
let mut ikm_size = 0u32;
67+
if let Some(key) = key {
68+
if key.len() > 0 {
69+
ikm_ptr = key.as_mut_ptr();
70+
ikm_size = key.len() as u32;
71+
}
72+
}
73+
if out.len() != HMAC::get_hmac_size_by_type(typ)? {
74+
return Err(ws::wolfCrypt_ErrorCodes_BUFFER_E);
75+
}
76+
let rc = unsafe {
77+
ws::wc_Tls13_HKDF_Extract(out.as_mut_ptr(), salt_ptr, salt_size,
78+
ikm_ptr, ikm_size, typ)
79+
};
80+
if rc != 0 {
81+
return Err(rc);
82+
}
83+
Ok(())
84+
}
85+
86+
/// Perform RFC 5869 HKDF-Extract operation for TLS v1.3 key derivation.
87+
///
88+
/// This utilizes HMAC to convert `key`, `label`, and `info` into a
89+
/// derived key which is written to `out`.
90+
///
91+
/// # Parameters
92+
///
93+
/// * `typ`: Hash type, one of `HMAC::TYPE_*`.
94+
/// * `key`: Key to use for KDF (typically output of `tls13_hkdf_extract()`).
95+
/// * `protocol`: Buffer containing TLS protocol.
96+
/// * `label`: Buffer containing label.
97+
/// * `info`: Buffer containing additional info.
98+
/// * `out`: Output buffer to store TLS1.3 HKDF-Expand result. The buffer can be
99+
/// any size.
100+
///
101+
/// # Returns
102+
///
103+
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
104+
/// library error code value.
105+
///
106+
/// # Example
107+
///
108+
/// ```rust
109+
/// use wolfssl::wolfcrypt::hmac::HMAC;
110+
/// use wolfssl::wolfcrypt::kdf::*;
111+
/// use wolfssl_sys as ws;
112+
/// let hash_hello1 = [
113+
/// 0x63u8, 0x83, 0x58, 0xab, 0x36, 0xcd, 0x0c, 0xf3,
114+
/// 0x26, 0x07, 0xb5, 0x5f, 0x0b, 0x8b, 0x45, 0xd6,
115+
/// 0x7d, 0x5b, 0x42, 0xdc, 0xa8, 0xaa, 0x06, 0xfb,
116+
/// 0x20, 0xa5, 0xbb, 0x85, 0xdb, 0x54, 0xd8, 0x8b
117+
/// ];
118+
/// let client_early_traffic_secret = [
119+
/// 0x20u8, 0x18, 0x72, 0x7c, 0xde, 0x3a, 0x85, 0x17, 0x72, 0xdc, 0xd7, 0x72,
120+
/// 0xb0, 0xfc, 0x45, 0xd0, 0x62, 0xb9, 0xbb, 0x38, 0x69, 0x05, 0x7b, 0xb4,
121+
/// 0x5e, 0x58, 0x5d, 0xed, 0xcd, 0x0b, 0x96, 0xd3
122+
/// ];
123+
/// let mut secret = [0u8; ws::WC_SHA256_DIGEST_SIZE as usize];
124+
/// tls13_hkdf_extract(HMAC::TYPE_SHA256, None, None, &mut secret).expect("Error with tls13_hkdf_extract()");
125+
/// let protocol_label = b"tls13 ";
126+
/// let ce_traffic_label = b"c e traffic";
127+
/// let mut expand_out = [0u8; ws::WC_SHA256_DIGEST_SIZE as usize];
128+
/// tls13_hkdf_expand_label(HMAC::TYPE_SHA256, &secret,
129+
/// protocol_label, ce_traffic_label,
130+
/// &hash_hello1, &mut expand_out).expect("Error with tls13_hkdf_expand_label()");
131+
/// ```
132+
pub fn tls13_hkdf_expand_label(typ: i32, key: &[u8], protocol: &[u8], label: &[u8], info: &[u8], out: &mut [u8]) -> Result<(), i32> {
133+
let key_size = key.len() as u32;
134+
let protocol_size = protocol.len() as u32;
135+
let label_size = label.len() as u32;
136+
let info_size = info.len() as u32;
137+
let out_size = out.len() as u32;
138+
let rc = unsafe {
139+
ws::wc_Tls13_HKDF_Expand_Label(out.as_mut_ptr(), out_size,
140+
key.as_ptr(), key_size, protocol.as_ptr(), protocol_size,
141+
label.as_ptr(), label_size, info.as_ptr(), info_size, typ)
142+
};
143+
if rc != 0 {
144+
return Err(rc);
145+
}
146+
Ok(())
147+
}
148+
149+
/// Perform SSH KDF operation.
150+
///
151+
/// # Parameters
152+
///
153+
/// * `typ`: Hash type, one of `HMAC::TYPE_*`.
154+
/// * `key_id`: Key ID, typically 'A' through 'F'.
155+
/// * `k`: Initial key.
156+
/// * `h`: Exchange hash.
157+
/// * `session_id`: Unique identifier for the SSH session.
158+
/// * `key`: Output buffer.
159+
///
160+
/// # Returns
161+
///
162+
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
163+
/// library error code value.
164+
///
165+
/// # Example
166+
///
167+
/// ```rust
168+
/// use wolfssl::wolfcrypt::hmac::HMAC;
169+
/// use wolfssl::wolfcrypt::kdf::*;
170+
/// let k = [0x42u8; 256];
171+
/// let h = [0x43u8; 32];
172+
/// let sid = [0x44u8; 32];
173+
/// let mut out = [0u8; 16];
174+
/// ssh_kdf(HMAC::TYPE_SHA256, b'A', &k, &h, &sid, &mut out).expect("Error with ssh_kdf()");
175+
/// ```
176+
pub fn ssh_kdf(typ: i32, key_id: u8, k: &[u8], h: &[u8], session_id: &[u8], key: &mut [u8]) -> Result<(), i32> {
177+
let key_size = key.len() as u32;
178+
let k_size = k.len() as u32;
179+
let h_size = h.len() as u32;
180+
let session_size = session_id.len() as u32;
181+
let rc = unsafe {
182+
ws::wc_SSH_KDF(typ as u8, key_id,
183+
key.as_mut_ptr(), key_size,
184+
k.as_ptr(), k_size, h.as_ptr(), h_size,
185+
session_id.as_ptr(), session_size)
186+
};
187+
if rc != 0 {
188+
return Err(rc);
189+
}
190+
Ok(())
191+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (C) 2025 wolfSSL Inc.
3+
*
4+
* This file is part of wolfSSL.
5+
*
6+
* wolfSSL is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfSSL is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
19+
*/
20+
21+
/*!
22+
This module provides a Rust wrapper for the wolfCrypt library's Pseudo Random
23+
Function (PRF) functionality.
24+
25+
It leverages the `wolfssl-sys` crate for low-level FFI bindings, encapsulating
26+
the raw C functions in a memory-safe and easy-to-use Rust API.
27+
*/
28+
29+
use wolfssl_sys as ws;
30+
31+
pub const PRF_HASH_NONE: i32 = ws::wc_MACAlgorithm_no_mac as i32;
32+
pub const PRF_HASH_MD5: i32 = ws::wc_MACAlgorithm_md5_mac as i32;
33+
pub const PRF_HASH_SHA: i32 = ws::wc_MACAlgorithm_sha_mac as i32;
34+
pub const PRF_HASH_SHA224: i32 = ws::wc_MACAlgorithm_sha224_mac as i32;
35+
pub const PRF_HASH_SHA256: i32 = ws::wc_MACAlgorithm_sha256_mac as i32;
36+
pub const PRF_HASH_SHA384: i32 = ws::wc_MACAlgorithm_sha384_mac as i32;
37+
pub const PRF_HASH_SHA512: i32 = ws::wc_MACAlgorithm_sha512_mac as i32;
38+
pub const PRF_HASH_RMD: i32 = ws::wc_MACAlgorithm_rmd_mac as i32;
39+
pub const PRF_HASH_BLAKE2B: i32 = ws::wc_MACAlgorithm_blake2b_mac as i32;
40+
pub const PRF_HASH_SM3: i32 = ws::wc_MACAlgorithm_sm3_mac as i32;
41+
42+
/// Pseudo Random Function for MD5, SHA-1, SHA-256, SHA-384, or SHA-512
43+
///
44+
/// # Parameters
45+
///
46+
/// * `secret`: Secret key.
47+
/// * `seed`: Seed.
48+
/// * `hash_type`: PRF Hash type, one of `PRF_HASH_*`.
49+
/// * `heap`: Heap hint.
50+
/// * `dev_id` Device ID to use with crypto callbacks or async hardware.
51+
/// Set to INVALID_DEVID (-2) if not used.
52+
/// * `dout`: Output buffer.
53+
///
54+
/// # Returns
55+
///
56+
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
57+
/// library error code value.
58+
///
59+
/// # Example
60+
///
61+
/// ```rust
62+
/// use wolfssl::wolfcrypt::prf::*;
63+
/// use wolfssl_sys as ws;
64+
/// let secret = [0x10u8, 0xbc, 0xb4, 0xa2, 0xe8, 0xdc, 0xf1, 0x9b, 0x4c,
65+
/// 0x51, 0x9c, 0xed, 0x31, 0x1b, 0x51, 0x57, 0x02, 0x3f,
66+
/// 0xa1, 0x7d, 0xfb, 0x0e, 0xf3, 0x4e, 0x8f, 0x6f, 0x71,
67+
/// 0xa3, 0x67, 0x76, 0x6b, 0xfa, 0x5d, 0x46, 0x4a, 0xe8,
68+
/// 0x61, 0x18, 0x81, 0xc4, 0x66, 0xcc, 0x6f, 0x09, 0x99,
69+
/// 0x9d, 0xfc, 0x47];
70+
/// let seed = [0x73u8, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69,
71+
/// 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x0b, 0x46, 0xba,
72+
/// 0x56, 0xbf, 0x1f, 0x5d, 0x99, 0xff, 0xe9, 0xbb, 0x43,
73+
/// 0x01, 0xe7, 0xca, 0x2c, 0x00, 0xdf, 0x9a, 0x39, 0x6e,
74+
/// 0xcf, 0x6d, 0x15, 0x27, 0x4d, 0xf2, 0x93, 0x96, 0x4a,
75+
/// 0x91, 0xde, 0x5c, 0xc0, 0x47, 0x7c, 0xa8, 0xae, 0xcf,
76+
/// 0x5d, 0x93, 0x5f, 0x4c, 0x92, 0xcc, 0x98, 0x5b, 0x43];
77+
/// let mut out = [0u8; 12];
78+
/// prf(&secret, &seed, PRF_HASH_SHA384,
79+
/// core::ptr::null_mut(), ws::INVALID_DEVID,
80+
/// &mut out).expect("Error with prf()");
81+
/// ```
82+
pub fn prf(secret: &[u8], seed: &[u8], hash_type: i32, heap: *mut ::std::os::raw::c_void, dev_id: i32, dout: &mut [u8]) -> Result<(), i32> {
83+
let secret_size = secret.len() as u32;
84+
let seed_size = seed.len() as u32;
85+
let dout_size = dout.len() as u32;
86+
let rc = unsafe {
87+
ws::wc_PRF(dout.as_mut_ptr(), dout_size,
88+
secret.as_ptr(), secret_size,
89+
seed.as_ptr(), seed_size,
90+
hash_type, heap, dev_id)
91+
};
92+
if rc != 0 {
93+
return Err(rc);
94+
}
95+
Ok(())
96+
}

0 commit comments

Comments
 (0)