Skip to content

Commit 57b7a8f

Browse files
author
Apache
committed
Merge branch 'release/0.1.2alpha' of git.bouncycastle.org:bc-rust into release/0.1.2alpha
2 parents 5cfc0b3 + 738ddaa commit 57b7a8f

38 files changed

Lines changed: 1093 additions & 778 deletions

alpha_0.1.2_release_notes.md

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,13 @@
22

33
[remove this section before publication]
44

5-
* ML-DSA & ML-KEM
6-
* Check the crate release checklist and run claude against the style guide (maybe Francis could cross-check me)
7-
* Run Crucible testing
8-
* Add factories for ML-DSA and ML-KEM (if we are keeping factories, see below)
9-
* After merging the Signer/Verifier, Encrypter/Decrypter split, check if the keygen_from_rng() is still on the right
10-
trait.
11-
* Split the Signature trait into a Signer and a Verifier so that, for example, we can implement the verifier for MTC in
12-
a different struct from the signer; or so that you can get FIPS compliance on old algorithms that are currently only
13-
FIPS-allowed for verification of existing signatures but not for creation of new ones.
14-
* Check out Megan's email May 13 about KeyMaterial: "I was wondering if there might be scope for a closure based
15-
approach that could guarantee encapsulation of the state change from safe to hazardous back to safe again."
16-
* Go back to previous algs and apply memory optimization tricks like internal functions. And add a docs section "Memory
17-
Usage" that measures with valgrind.
18-
* Ensure that all crates have `#![forbid(missing_docs)]`
19-
* Apply Secret trait consistently across the library --> study the `Zeroize` trait in RustCrypto
20-
* Change all "[u8;0]" to "[]" throughout the code and docs ... or better yet, change the APIs to take an Option<>
21-
* Change all `-> Vec<u8>` to `-> [u8; CONST_LEN]`, and the `output: &mut [u8]` to `output: &mut [u8; CONST_LEN]` where
22-
appropriate.
23-
* Probably it makes sense to leave Hex and Base64 as requiring std; ... or maybe add a no_std version that uses
24-
fixed-sized blocks?
25-
* Create a cargo feature #[cfg(feature='rng')] and put it around things like keygen that takes an rng so that the build
26-
dependency on bouncycastle_rng is optional.
27-
* Factories ... Are they worth it? Michael Richardson says Very Yes. If we are keeping them, then we need a serious
28-
re-engineering of them because I really dislike that currently they make it hard for the underlying primitive to have
29-
static one-shot APIs.
305
* Deal with as many of the inline TODOs as possible
316
* Close all open github issues and document them in this file.
7+
* Clean up `cargo doc --all` warnings
8+
* On release/0.1.2alpha, get Claude to make a cosmetic change to the docs for all crates to use [`Secret`] instead
9+
of [Secret] because this renders better.
3210
* After everything is merged, circle back to crucible, and make sure that the harness still works
33-
* Search for all the uses of .unwrap() in non-test code and replace each with either a comment or an expect with a
34-
meaningful error string.
11+
* Delete this file and stuff it into the Description of a github Release.
3512

3613
# 0.1.2 Features / Changelog
3714

@@ -47,16 +24,47 @@
4724
potentially across versions of the library. The intended use case is if you are processing a large input that depends
4825
on one or more network round-trips and you wish to suspend to a cache and potentially transfer to a new host while
4926
waiting for network IO.
27+
* dyn RNG: anywhere that consumes randomness (such as keygen and non-deterministic sign / encaps functions) can now be
28+
handed an instance of an object that impl's `bouncycastle-core::traits::RNG`.
29+
* Rework of the Secret system for protecting secret data against leakage via returning to the memory pool unzeroized,
30+
or being logged in debug messages, stack traces, and crash dumps. Now properly uses `core::mem::write_volatile` to
31+
prevent
32+
the compiler from eliding writes on drop, and introduced a new type system `Secret<T>` that is used across the library
33+
to give more fine-grained control over which objects (and which fields within objects) get this extra protection.
34+
Bonus: this is a public type that you can use to protect your application data as well!
5035

5136
## Minor features / bug fixes
5237

53-
* All public `*_out(.., out: &mut [u8])` functions now begin by zeroizing the entire output buffer with `.fill(0)`,
54-
preventing exposure of stale data in oversized output buffers or on early error returns.
38+
Trait system:
39+
40+
* Split the Signature trait into a Signer and a Verifier trait. This is for two reasons: 1) some of the future signature
41+
algorithms (like hash-based signatures) the verifier code is substantially lighter than the signer code, or we may not
42+
even want to implement a signer in software, and 2) NIST likes to soft-deprecate algorithms by disallowing generation
43+
of new signatures, but still allowing verification of existing signatures.
44+
* Added traits for symmetric ciphers in the block cipher, stream cipher, and AEAD families. We don't have any of these
45+
algorithms implemented yet, but they're coming!
46+
47+
The KeyMaterial object:
48+
5549
* Reworked the way KeyMaterial hazardous operations work; instead of a stateful .allow_hazardous_operations() /
5650
.drop_hazardous_operations(), it now uses a closure-based do_hazardous_operations(). Github issue #39.
5751
* Renamed KeyMaterial::KeyType's and deleted KeyMaterial::concatenate in order to give a better intuition and
5852
FIPS-alignment.
59-
* Removed the dependence on nightly / experimental compiler features; the library now buildds on stable.
60-
* Github issues resolved:
61-
* #6: https://github.com/bcgit/bc-rust/issues/6, thanks to Q. T. Felix (github: @Quant-TheodoreFelix)
62-
* #10: https://github.com/bcgit/bc-rust/issues/10, thanks to Nicola Tuveri (github: @romen)
53+
* Tightened up the entropy-tracking behaviour of the KeyMaterial object, thanks to Q. T. Felix (github:
54+
@Quant-TheodoreFelix, github issue #6)
55+
56+
Docs:
57+
58+
* All crypto algorithm crates now have Memory Usage docs that list the stack memory usage of the implementation.
59+
* All crypto algorithm crates now have `#![forbid(missing_docs)]` to ensure that they have a fully-documented public
60+
API.
61+
62+
* Other miscellaneous Github issues resolved:
63+
* #10: https://github.com/bcgit/bc-rust/issues/10, thanks to Nicola Tuveri (github: @romen)
64+
* #18: All public `*_out(.., out: &mut [u8])` functions now begin by zeroizing the entire provided output buffer
65+
with `.fill(0)`,
66+
preventing exposure of stale data in oversized output buffers or on early error returns. Thanks to Q. T. Felix (
67+
github: @Quant-TheodoreFelix)
68+
* #27: "SHAKE absorb-after-squeeze": clarified and hardened the behaviour of SHAKE with respect to absorbing more
69+
input after having been squeezed.
70+
* #28: Removed the dependence on nightly / experimental compiler features; the library now builds on stable.

crypto/core/src/key_material.rs

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
//! See [do_hazardous_operations] for documentation and sample code.
5252
5353
use crate::errors::{KeyMaterialError, SuspendableError};
54-
use crate::traits::{RNG, Secret, SecurityStrength};
55-
use bouncycastle_utils::{ct, min};
54+
use crate::traits::{RNG, SecurityStrength};
55+
use bouncycastle_utils::{ct, min, secret::Secret};
5656

5757
use core::cmp::{Ordering, PartialOrd};
5858
use core::fmt;
@@ -215,15 +215,13 @@ pub trait KeyMaterialTrait: KeyMaterialInternalTrait {
215215
/// The capacity of the internal buffer can be set at compile-time via the <KEY_LEN> param.
216216
#[derive(Clone)]
217217
pub struct KeyMaterial<const KEY_LEN: usize> {
218-
buf: [u8; KEY_LEN],
219-
key_len: usize,
218+
buf: Secret<[u8; KEY_LEN]>,
219+
key_len: Secret<usize>,
220220
key_type: KeyType,
221221
security_strength: SecurityStrength,
222222
allow_hazardous_operations: bool,
223223
}
224224

225-
impl<const KEY_LEN: usize> Secret for KeyMaterial<KEY_LEN> {}
226-
227225
// The explicit `#[repr(u8)]` discriminants are the stable on-the-wire encoding used by
228226
// `SerializableState` implementations (see the `TryFrom<u8>` impl below). Pin each value to its
229227
// variant name: reordering variants is fine, but never reuse or renumber an existing discriminant,
@@ -287,8 +285,8 @@ impl<const KEY_LEN: usize> KeyMaterial<KEY_LEN> {
287285
/// If you want a properly populated instance, use [KeyMaterial::from_rng].
288286
pub fn new() -> Self {
289287
Self {
290-
buf: [0u8; KEY_LEN],
291-
key_len: 0,
288+
buf: Secret::new(),
289+
key_len: Secret::new(),
292290
key_type: KeyType::Zeroized,
293291
security_strength: SecurityStrength::None,
294292
allow_hazardous_operations: false,
@@ -305,7 +303,7 @@ impl<const KEY_LEN: usize> KeyMaterial<KEY_LEN> {
305303
Ok(())
306304
})?;
307305

308-
key.key_len = KEY_LEN;
306+
*key.key_len = KEY_LEN;
309307
key.key_type = KeyType::CryptographicRandom;
310308
key.security_strength = rng.security_strength();
311309
Ok(key)
@@ -347,14 +345,11 @@ impl<const KEY_LEN: usize> KeyMaterial<KEY_LEN> {
347345
return Err(KeyMaterialError::InputDataLongerThanKeyCapacity);
348346
}
349347

350-
let mut key = Self {
351-
buf: [0u8; KEY_LEN],
352-
key_len: other.key_len(),
353-
key_type: other.key_type(),
354-
security_strength: SecurityStrength::None,
355-
allow_hazardous_operations: false,
356-
};
348+
let mut key = Self::new();
357349
key.buf[..other.key_len()].copy_from_slice(other.ref_to_bytes());
350+
*key.key_len = other.key_len();
351+
key.key_type = other.key_type();
352+
key.security_strength = other.security_strength();
358353
Ok(key)
359354
}
360355
}
@@ -378,7 +373,7 @@ impl<const KEY_LEN: usize> KeyMaterialTrait for KeyMaterial<KEY_LEN> {
378373
};
379374

380375
self.buf[..source.len()].copy_from_slice(source);
381-
self.key_len = source.len();
376+
*self.key_len = source.len();
382377
self.key_type = new_key_type;
383378

384379
do_hazardous_operations(self, |s| {
@@ -399,22 +394,22 @@ impl<const KEY_LEN: usize> KeyMaterialTrait for KeyMaterial<KEY_LEN> {
399394
}
400395

401396
fn ref_to_bytes(&self) -> &[u8] {
402-
&self.buf[..self.key_len]
397+
&self.buf[..*self.key_len]
403398
}
404399

405400
fn ref_to_bytes_mut(&mut self) -> Result<&mut [u8], KeyMaterialError> {
406401
if !self.allow_hazardous_operations {
407402
return Err(KeyMaterialError::HazardousOperationNotPermitted);
408403
}
409-
Ok(&mut self.buf)
404+
Ok(self.buf.as_mut())
410405
}
411406

412407
fn capacity(&self) -> usize {
413408
KEY_LEN
414409
}
415410

416411
fn key_len(&self) -> usize {
417-
self.key_len
412+
*self.key_len
418413
}
419414

420415
fn set_key_len(&mut self, key_len: usize) -> Result<(), KeyMaterialError> {
@@ -423,7 +418,7 @@ impl<const KEY_LEN: usize> KeyMaterialTrait for KeyMaterial<KEY_LEN> {
423418
}
424419

425420
// are we extending the key length, or truncating?
426-
if key_len <= self.key_len {
421+
if key_len <= *self.key_len {
427422
// truncation is always allowed (not hazardous)
428423

429424
self.security_strength =
@@ -433,14 +428,14 @@ impl<const KEY_LEN: usize> KeyMaterialTrait for KeyMaterial<KEY_LEN> {
433428
self.key_type = KeyType::Zeroized;
434429
}
435430

436-
self.key_len = key_len;
431+
*self.key_len = key_len;
437432

438433
Ok(())
439434
} else {
440435
if !self.allow_hazardous_operations {
441436
return Err(KeyMaterialError::HazardousOperationNotPermitted);
442437
}
443-
self.key_len = key_len;
438+
*self.key_len = key_len;
444439
Ok(())
445440
}
446441
}
@@ -557,8 +552,8 @@ impl<const KEY_LEN: usize> KeyMaterialTrait for KeyMaterial<KEY_LEN> {
557552
}
558553

559554
fn zeroize(&mut self) {
560-
self.buf.fill(0u8);
561-
self.key_len = 0;
555+
self.buf.zeroize();
556+
self.key_len.zeroize();
562557
self.key_type = KeyType::Zeroized;
563558
}
564559

@@ -579,7 +574,7 @@ impl<const KEY_LEN: usize> PartialEq for KeyMaterial<KEY_LEN> {
579574
if self.key_len != other.key_len {
580575
return false;
581576
}
582-
ct::ct_eq_bytes(&self.buf[..self.key_len], &other.buf[..self.key_len])
577+
ct::ct_eq_bytes(&self.buf[..*self.key_len], &other.buf[..*self.key_len])
583578
}
584579
}
585580
impl<const KEY_LEN: usize> Eq for KeyMaterial<KEY_LEN> {}
@@ -618,32 +613,27 @@ impl PartialOrd for KeyType {
618613
/// Block accidental logging of the internal key material buffer.
619614
impl<const KEY_LEN: usize> fmt::Display for KeyMaterial<KEY_LEN> {
620615
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616+
// deref the key_len explicitly so that Secret doesn't render it as "<redacted>"
621617
write!(
622618
f,
623-
"KeyMaterial {{ len: {}, key_type: {:?}, security_strength: {:?} }}",
624-
self.key_len, self.key_type, self.security_strength
619+
"KeyMaterial<{}>{{ len: {}, key_type: {:?}, security_strength: {:?} }}",
620+
KEY_LEN, *self.key_len, self.key_type, self.security_strength
625621
)
626622
}
627623
}
628624

629625
/// Block accidental logging of the internal key material buffer.
630626
impl<const KEY_LEN: usize> fmt::Debug for KeyMaterial<KEY_LEN> {
631627
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
628+
// deref the key_len explicitly so that Secret doesn't render it as "<redacted>"
632629
write!(
633630
f,
634-
"KeyMaterial {{ len: {}, key_type: {:?}, security_strength: {:?} }}",
635-
self.key_len, self.key_type, self.security_strength
631+
"KeyMaterial<{}>{{ len: {}, key_type: {:?}, security_strength: {:?} }}",
632+
KEY_LEN, *self.key_len, self.key_type, self.security_strength
636633
)
637634
}
638635
}
639636

640-
/// Zeroize the key material on drop.
641-
impl<const KEY_LEN: usize> Drop for KeyMaterial<KEY_LEN> {
642-
fn drop(&mut self) {
643-
self.zeroize()
644-
}
645-
}
646-
647637
/* Hazardous Operations Runner */
648638

649639
/// Internal-use trait holding the low-level hazardous-operations guard toggle.

crypto/core/src/traits.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ pub trait AlgorithmOID {
3636
/// ciphertexts that are incompatible with other implementations as ciphers in more complex modes, such
3737
/// as AEADs or stream ciphers may need to stick extra data either at the beginning or end of the ciphertext.
3838
/// See the documentation of the underlying implementation for more details.
39-
pub trait SymmetricCipher<const KEY_LEN: usize, const INIT_DATA_LEN: usize>:
40-
Algorithm + Secret
41-
{
39+
pub trait SymmetricCipher<const KEY_LEN: usize, const INIT_DATA_LEN: usize>: Algorithm {
4240
#[cfg(feature = "std")]
4341
/// A one-shot API to encrypt some plaintext with the given key.
4442
/// This function returns the ciphertext as a Vec<u8>, and therefore is only available when compiling with std.
@@ -522,7 +520,7 @@ pub trait KEMPublicKey<const PK_LEN: usize>:
522520
}
523521

524522
/// A private key for a KEM algorithm, often denoted "sk" (for "secret key").
525-
pub trait KEMPrivateKey<const SK_LEN: usize>: PartialEq + Eq + Clone + Secret + Sized {
523+
pub trait KEMPrivateKey<const SK_LEN: usize>: PartialEq + Eq + Clone + Sized {
526524
/// Write it out to bytes in its standard encoding.
527525
fn encode(&self) -> [u8; SK_LEN];
528526
/// Write it out to bytes in its standard encoding.
@@ -768,14 +766,6 @@ pub trait RNG {
768766
fn security_strength(&self) -> SecurityStrength;
769767
}
770768

771-
/// A trait that forces an object to implement a zeroizing Drop() as well as Debug and Display that
772-
/// will not log the sensitive contents, even in error or crash-dump scenarios.
773-
// Since rust auto-implements Drop, there's a lint that explicitly bounding on Drop is useless.
774-
// I disagree because I want to force things that are secrets to manually implement Drop that zeroizes the data.
775-
// So I'm turning off this lint.
776-
#[allow(drop_bounds)]
777-
pub trait Secret: Drop + Debug + Display {}
778-
779769
/// Allows a stateful object to suspend its operation by serializing its state into a byte array
780770
///so that it can be resumed later, potentially from a different host.
781771
///
@@ -925,9 +915,7 @@ pub trait SignaturePublicKey<const PK_LEN: usize>:
925915
}
926916

927917
/// A private key for a signature algorithm, often denoted "sk" (for "secret key").
928-
pub trait SignaturePrivateKey<const SK_LEN: usize>:
929-
PartialEq + Eq + Clone + Secret + Sized
930-
{
918+
pub trait SignaturePrivateKey<const SK_LEN: usize>: PartialEq + Eq + Clone + Sized {
931919
/// Write it out to bytes in its standard encoding.
932920
fn encode(&self) -> [u8; SK_LEN];
933921
/// Write it out to bytes in its standard encoding.

0 commit comments

Comments
 (0)