Skip to content

Commit 8fb72de

Browse files
Merge pull request #10402 from holtrop-wolfssl/rust-crate-updates-2026-05-05
Rust wrapper: ensure memory safety for C RNG struct
2 parents fc12de0 + 8c11a8e commit 8fb72de

30 files changed

Lines changed: 1542 additions & 531 deletions

wrapper/rust/wolfssl-wolfcrypt/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ categories = ["cryptography", "security", "api-bindings"]
1111
readme = "README.md"
1212

1313
[features]
14-
std = []
14+
alloc = []
1515
rand_core = ["dep:rand_core"]
1616
aead = ["dep:aead"]
1717
cipher = ["dep:cipher"]

wrapper/rust/wolfssl-wolfcrypt/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FEATURES := rand_core,aead,cipher,digest,mac,signature,password-hash,kem
1+
FEATURES := alloc,rand_core,aead,cipher,digest,mac,signature,password-hash,kem
22
CARGO_FEATURE_FLAGS := --features $(FEATURES)
33

44
.PHONY: all

wrapper/rust/wolfssl-wolfcrypt/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
The `wolfssl-wolfcrypt` crate is a Rust wrapper for the wolfCrypt cryptographic
44
algorithms portion of the wolfSSL C library.
55

6+
This crate requires wolfSSL version 5.9.0 or newer.
7+
68
## Installation
79

810
The `wolfssl` C library must be installed to be used by the Rust crate.

wrapper/rust/wolfssl-wolfcrypt/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ fn scan_cfg() -> Result<()> {
371371
check_cfg(&binding, "wc_Dh_ffdhe6144_Get", "dh_ffdhe_6144");
372372
check_cfg(&binding, "wc_Dh_ffdhe8192_Get", "dh_ffdhe_8192");
373373

374+
/* crypto callback */
375+
check_cfg(&binding, "wc_CryptoCb_RegisterDevice", "wolf_crypto_cb");
376+
374377
/* ecc */
375378
check_cfg(&binding, "wc_ecc_init", "ecc");
376379
check_cfg(&binding, "wc_ecc_export_point_der_compressed", "ecc_comp_key");

wrapper/rust/wolfssl-wolfcrypt/src/aes.rs

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,10 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
3333
use aead::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
3434

3535
#[cfg(feature = "aead")]
36-
use aead::generic_array::typenum::{U0, U12, U16, U32};
36+
use aead::generic_array::typenum::{U0, U12, U16, U24, U32};
3737

3838
#[cfg(all(feature = "cipher", not(feature = "aead")))]
39-
use cipher::typenum::consts::{U16, U32};
40-
41-
#[cfg(feature = "cipher")]
42-
use cipher::typenum::consts::U24;
39+
use cipher::typenum::consts::{U16, U24, U32};
4340

4441
#[cfg(feature = "cipher")]
4542
use cipher::{
@@ -557,6 +554,58 @@ impl AeadInPlace for Aes128Ccm {
557554
}
558555
}
559556

557+
/// AES-192-CCM authenticated encryption (12-byte nonce, 16-byte tag).
558+
#[cfg(all(aes_ccm, feature = "aead"))]
559+
#[derive(Zeroize, ZeroizeOnDrop)]
560+
pub struct Aes192Ccm {
561+
key: [u8; 24],
562+
}
563+
564+
#[cfg(all(aes_ccm, feature = "aead"))]
565+
impl KeySizeUser for Aes192Ccm {
566+
type KeySize = U24;
567+
}
568+
569+
#[cfg(all(aes_ccm, feature = "aead"))]
570+
impl AeadCore for Aes192Ccm {
571+
type NonceSize = U12;
572+
type TagSize = U16;
573+
type CiphertextOverhead = U0;
574+
}
575+
576+
#[cfg(all(aes_ccm, feature = "aead"))]
577+
impl KeyInit for Aes192Ccm {
578+
fn new(key: &aead::Key<Self>) -> Self {
579+
let mut k = [0u8; 24];
580+
k.copy_from_slice(key.as_ref());
581+
Aes192Ccm { key: k }
582+
}
583+
}
584+
585+
#[cfg(all(aes_ccm, feature = "aead"))]
586+
impl AeadInPlace for Aes192Ccm {
587+
fn encrypt_in_place_detached(
588+
&self,
589+
nonce: &aead::Nonce<Self>,
590+
associated_data: &[u8],
591+
buffer: &mut [u8],
592+
) -> Result<aead::Tag<Self>, aead::Error> {
593+
let mut tag = aead::Tag::<Self>::default();
594+
ccm_encrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_mut())?;
595+
Ok(tag)
596+
}
597+
598+
fn decrypt_in_place_detached(
599+
&self,
600+
nonce: &aead::Nonce<Self>,
601+
associated_data: &[u8],
602+
buffer: &mut [u8],
603+
tag: &aead::Tag<Self>,
604+
) -> Result<(), aead::Error> {
605+
ccm_decrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_ref())
606+
}
607+
}
608+
560609
/// AES-256-CCM authenticated encryption (12-byte nonce, 16-byte tag).
561610
#[cfg(all(aes_ccm, feature = "aead"))]
562611
#[derive(Zeroize, ZeroizeOnDrop)]
@@ -1713,6 +1762,58 @@ impl AeadInPlace for Aes128Gcm {
17131762
}
17141763
}
17151764

1765+
/// AES-192-GCM authenticated encryption (12-byte nonce, 16-byte tag).
1766+
#[cfg(all(aes_gcm, feature = "aead"))]
1767+
#[derive(Zeroize, ZeroizeOnDrop)]
1768+
pub struct Aes192Gcm {
1769+
key: [u8; 24],
1770+
}
1771+
1772+
#[cfg(all(aes_gcm, feature = "aead"))]
1773+
impl KeySizeUser for Aes192Gcm {
1774+
type KeySize = U24;
1775+
}
1776+
1777+
#[cfg(all(aes_gcm, feature = "aead"))]
1778+
impl AeadCore for Aes192Gcm {
1779+
type NonceSize = U12;
1780+
type TagSize = U16;
1781+
type CiphertextOverhead = U0;
1782+
}
1783+
1784+
#[cfg(all(aes_gcm, feature = "aead"))]
1785+
impl KeyInit for Aes192Gcm {
1786+
fn new(key: &aead::Key<Self>) -> Self {
1787+
let mut k = [0u8; 24];
1788+
k.copy_from_slice(key.as_ref());
1789+
Aes192Gcm { key: k }
1790+
}
1791+
}
1792+
1793+
#[cfg(all(aes_gcm, feature = "aead"))]
1794+
impl AeadInPlace for Aes192Gcm {
1795+
fn encrypt_in_place_detached(
1796+
&self,
1797+
nonce: &aead::Nonce<Self>,
1798+
associated_data: &[u8],
1799+
buffer: &mut [u8],
1800+
) -> Result<aead::Tag<Self>, aead::Error> {
1801+
let mut tag = aead::Tag::<Self>::default();
1802+
gcm_encrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_mut())?;
1803+
Ok(tag)
1804+
}
1805+
1806+
fn decrypt_in_place_detached(
1807+
&self,
1808+
nonce: &aead::Nonce<Self>,
1809+
associated_data: &[u8],
1810+
buffer: &mut [u8],
1811+
tag: &aead::Tag<Self>,
1812+
) -> Result<(), aead::Error> {
1813+
gcm_decrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_ref())
1814+
}
1815+
}
1816+
17161817
/// AES-256-GCM authenticated encryption (12-byte nonce, 16-byte tag).
17171818
#[cfg(all(aes_gcm, feature = "aead"))]
17181819
#[derive(Zeroize, ZeroizeOnDrop)]
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright (C) 2006-2026 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+
RustCrypto `digest` trait implementations for the wolfCrypt BLAKE2 hash
23+
types.
24+
25+
Because BLAKE2b and BLAKE2s have variable digest sizes, this module exposes
26+
typed wrappers that pin the digest size of an underlying [`crate::blake2`]
27+
instance to a specific value, matching the typed aliases provided by the
28+
RustCrypto `blake2` crate (`Blake2b512`, `Blake2b256`, `Blake2s256`, etc.).
29+
30+
Each typed wrapper implements the traits from the `digest` crate
31+
(`HashMarker`, `OutputSizeUser`, `BlockSizeUser`, `Update`, `Reset`,
32+
`FixedOutput`, and `FixedOutputReset`). With these implementations the
33+
`digest::Digest` trait becomes available via its blanket implementation,
34+
allowing these hashers to be used anywhere a RustCrypto `Digest` is
35+
accepted.
36+
37+
Any failure returned by the underlying wolfCrypt call in a trait method
38+
will result in a panic, matching the infallible signatures required by the
39+
RustCrypto traits.
40+
*/
41+
42+
use digest::consts::{U16, U24, U32, U48, U64, U128};
43+
44+
macro_rules! impl_blake2_digest {
45+
(
46+
$(#[$attr:meta])*
47+
$name:ident,
48+
wc_ty = $wc_ty:path,
49+
digest_size = $digest_size:literal,
50+
out = $out_size:ty,
51+
block = $block_size:ty
52+
) => {
53+
$(#[$attr])*
54+
pub struct $name {
55+
blake2: $wc_ty,
56+
}
57+
58+
$(#[$attr])*
59+
impl Default for $name {
60+
fn default() -> Self {
61+
Self {
62+
blake2: <$wc_ty>::new($digest_size)
63+
.expect("wolfCrypt BLAKE2 init failed"),
64+
}
65+
}
66+
}
67+
68+
$(#[$attr])*
69+
impl digest::HashMarker for $name {}
70+
71+
$(#[$attr])*
72+
impl digest::OutputSizeUser for $name {
73+
type OutputSize = $out_size;
74+
}
75+
76+
$(#[$attr])*
77+
impl digest::block_api::BlockSizeUser for $name {
78+
type BlockSize = $block_size;
79+
}
80+
81+
$(#[$attr])*
82+
impl digest::Update for $name {
83+
fn update(&mut self, data: &[u8]) {
84+
<$wc_ty>::update(&mut self.blake2, data)
85+
.expect("wolfCrypt BLAKE2 update failed");
86+
}
87+
}
88+
89+
$(#[$attr])*
90+
impl digest::Reset for $name {
91+
fn reset(&mut self) {
92+
self.blake2 = <$wc_ty>::new($digest_size)
93+
.expect("wolfCrypt BLAKE2 init failed");
94+
}
95+
}
96+
97+
$(#[$attr])*
98+
impl digest::FixedOutput for $name {
99+
fn finalize_into(mut self, out: &mut digest::Output<Self>) {
100+
<$wc_ty>::finalize(&mut self.blake2, out.as_mut_slice())
101+
.expect("wolfCrypt BLAKE2 finalize failed");
102+
}
103+
}
104+
105+
$(#[$attr])*
106+
impl digest::FixedOutputReset for $name {
107+
fn finalize_into_reset(&mut self, out: &mut digest::Output<Self>) {
108+
<$wc_ty>::finalize(&mut self.blake2, out.as_mut_slice())
109+
.expect("wolfCrypt BLAKE2 finalize failed");
110+
self.blake2 = <$wc_ty>::new($digest_size)
111+
.expect("wolfCrypt BLAKE2 init failed");
112+
}
113+
}
114+
};
115+
}
116+
117+
impl_blake2_digest! {
118+
#[cfg(blake2b)]
119+
Blake2b256,
120+
wc_ty = crate::blake2::BLAKE2b,
121+
digest_size = 32,
122+
out = U32,
123+
block = U128
124+
}
125+
126+
impl_blake2_digest! {
127+
#[cfg(blake2b)]
128+
Blake2b384,
129+
wc_ty = crate::blake2::BLAKE2b,
130+
digest_size = 48,
131+
out = U48,
132+
block = U128
133+
}
134+
135+
impl_blake2_digest! {
136+
#[cfg(blake2b)]
137+
Blake2b512,
138+
wc_ty = crate::blake2::BLAKE2b,
139+
digest_size = 64,
140+
out = U64,
141+
block = U128
142+
}
143+
144+
impl_blake2_digest! {
145+
#[cfg(blake2s)]
146+
Blake2s128,
147+
wc_ty = crate::blake2::BLAKE2s,
148+
digest_size = 16,
149+
out = U16,
150+
block = U64
151+
}
152+
153+
impl_blake2_digest! {
154+
#[cfg(blake2s)]
155+
Blake2s192,
156+
wc_ty = crate::blake2::BLAKE2s,
157+
digest_size = 24,
158+
out = U24,
159+
block = U64
160+
}
161+
162+
impl_blake2_digest! {
163+
#[cfg(blake2s)]
164+
Blake2s256,
165+
wc_ty = crate::blake2::BLAKE2s,
166+
digest_size = 32,
167+
out = U32,
168+
block = U64
169+
}

0 commit comments

Comments
 (0)