diff --git a/Cargo.toml b/Cargo.toml index 82b379fe..a6ef2801 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,18 +10,18 @@ version = "0.1.3" # *** Internal Dependencies *** bouncycastle = { path = "./" } bouncycastle-base64 = { path = "./crypto/base64" } -bouncycastle-core = { path = "crypto/core" } -bouncycastle-core-test-framework = { path = "./crypto/core-test-framework" } +bouncycastle-core = { path = "crypto/core", default-features = false } +bouncycastle-core-test-framework = { path = "./crypto/core-test-framework", default-features = false } bouncycastle-factory = { path = "./crypto/factory" } bouncycastle-hex = { path = "./crypto/hex" } -bouncycastle-hkdf = { path = "./crypto/hkdf" } -bouncycastle-hmac = { path = "./crypto/hmac" } +bouncycastle-hkdf = { path = "./crypto/hkdf", default-features = false } +bouncycastle-hmac = { path = "./crypto/hmac", default-features = false } bouncycastle-mlkem = { path = "./crypto/mlkem" } bouncycastle-mlkem-lowmemory = { path = "./crypto/mlkem-lowmemory" } bouncycastle-mldsa = { path = "./crypto/mldsa" } bouncycastle-mldsa-lowmemory = { path = "./crypto/mldsa-lowmemory" } -bouncycastle-rng = { path = "./crypto/rng" } -bouncycastle-sha2 = { path = "./crypto/sha2" } +bouncycastle-rng = { path = "./crypto/rng", default-features = false } +bouncycastle-sha2 = { path = "./crypto/sha2", default-features = false } bouncycastle-sha3 = { path = "./crypto/sha3" } bouncycastle-utils = { path = "./crypto/utils" } diff --git a/crypto/core-test-framework/Cargo.toml b/crypto/core-test-framework/Cargo.toml index 69447b69..82c6a73e 100644 --- a/crypto/core-test-framework/Cargo.toml +++ b/crypto/core-test-framework/Cargo.toml @@ -3,7 +3,16 @@ name = "bouncycastle-core-test-framework" version.workspace = true edition.workspace = true +# core-test-framework only needs to build for std/alloc environments +# However it must appropriately enable or disable `alloc` feature +# for all dependencies +[features] +default = ["alloc"] +alloc = [ + "bouncycastle-core/alloc", +] + [dependencies] -bouncycastle-core.workspace = true +bouncycastle-core = { workspace = true, default-features = false } [dev-dependencies] diff --git a/crypto/core-test-framework/src/fixed_seed_rng.rs b/crypto/core-test-framework/src/fixed_seed_rng.rs index 584ad6fb..32225bd4 100644 --- a/crypto/core-test-framework/src/fixed_seed_rng.rs +++ b/crypto/core-test-framework/src/fixed_seed_rng.rs @@ -57,6 +57,7 @@ impl RNG for FixedSeedRNG { Ok(u32::from_le_bytes(buf)) } + #[cfg(feature = "alloc")] fn next_bytes(&mut self, len: usize) -> Result, RNGError> { let mut out = vec![0u8; len]; for slot in out.iter_mut() { diff --git a/crypto/core-test-framework/src/hash.rs b/crypto/core-test-framework/src/hash.rs index 6c880ba9..6745f2a9 100644 --- a/crypto/core-test-framework/src/hash.rs +++ b/crypto/core-test-framework/src/hash.rs @@ -1,6 +1,10 @@ //! Generic behaviour tests for anything that implements [`Hash`]. +// Imports needed for alloc +#[allow(unused_imports)] use bouncycastle_core::errors::HashError; +// end of imports needed for alloc + use bouncycastle_core::traits::{Hash, HashAlgParams}; /// Instance of the test framework. @@ -28,44 +32,68 @@ impl TestFrameworkHash { /*** fn result_len() -> usize ***/ assert_eq!(H::default().output_len(), H::OUTPUT_LEN); - /*** fn hash(self, data: &[u8]) -> Vec **/ - let output_vec = H::default().hash(input); - assert_eq!(output_vec, expected_output); + #[cfg(feature = "alloc")] + { + /*** fn hash(self, data: &[u8]) -> Vec **/ + let output_vec = H::default().hash(input); + assert_eq!(output_vec, expected_output); + } /*** fn hash_out(self, data: &[u8], output: &mut [u8]) -> Result ***/ let mut output_buf = vec![0_u8; H::OUTPUT_LEN]; H::default().hash_out(input, &mut output_buf); assert_eq!(output_buf, expected_output); - /*** fn do_update(&mut self, data: &[u8]) -> Result<(), HashError> ***/ - /*** fn do_final(self) -> Result, HashError> **/ + /*** fn hash_array(self, data: &[u8]) -> [u8; N] (no_std alternative) ***/ + // Use N = 64, the maximum output length across all hashes; hash_array zero-pads the tail + // beyond output_len, so the digest lands in the first OUTPUT_LEN bytes. + let arr: [u8; 64] = H::default().hash_array(input); + assert_eq!(&arr[..H::OUTPUT_LEN], expected_output, "hash_array digest mismatch"); + assert!(arr[H::OUTPUT_LEN..].iter().all(|&b| b == 0), "hash_array tail not zero-padded"); + /*** fn do_final_array(self) -> [u8; N] (no_std alternative) ***/ let mut message_digest = H::default(); message_digest.do_update(input); - let output_buf = message_digest.do_final(); - assert_eq!(expected_output, output_buf, "Incorrect output for input (update_bytes)"); - - for length in 1..output_buf.len() { - let mut truncated = vec![0_u8; length]; + let arr: [u8; 64] = message_digest.do_final_array(); + assert_eq!(&arr[..H::OUTPUT_LEN], expected_output, "do_final_array digest mismatch"); + assert!( + arr[H::OUTPUT_LEN..].iter().all(|&b| b == 0), + "do_final_array tail not zero-padded" + ); + + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + /*** fn do_update(&mut self, data: &[u8]) -> Result<(), HashError> ***/ + /*** fn do_final(self) -> Result, HashError> **/ let mut message_digest = H::default(); message_digest.do_update(input); - message_digest.do_final_out(&mut truncated); + let output_buf = message_digest.do_final(); + assert_eq!(expected_output, output_buf, "Incorrect output for input (update_bytes)"); - assert_eq!( - &expected_output[0..length], - &truncated, - "Incorrect output for input (update_byte) / truncated: {length}" - ); - } + for length in 1..output_buf.len() { + let mut truncated = vec![0_u8; length]; - /*** Test breaking the message into multiple do_update's ***/ - let mut message_digest = H::default(); - for chunk in input.chunks(16) { - message_digest.do_update(chunk); + let mut message_digest = H::default(); + message_digest.do_update(input); + message_digest.do_final_out(&mut truncated); + + assert_eq!( + &expected_output[0..length], + &truncated, + "Incorrect output for input (update_byte) / truncated: {length}" + ); + } + + /*** Test breaking the message into multiple do_update's ***/ + let mut message_digest = H::default(); + for chunk in input.chunks(16) { + message_digest.do_update(chunk); + } + let output_buf = message_digest.do_final(); + assert_eq!(expected_output, output_buf, "Incorrect output for input (update_bytes)"); } - let output_buf = message_digest.do_final(); - assert_eq!(expected_output, output_buf, "Incorrect output for input (update_bytes)"); /*** fn do_update(&mut self, data: &[u8]) -> Result<(), HashError> ***/ /*** fn do_final_out(self, output: &mut [u8]) -> Result ***/ @@ -93,6 +121,8 @@ impl TestFrameworkHash { ); } + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] if self.enable_partial_byte_tests { /*** Testing: ***/ /*** fn do_final_partial_bits(self, partial_byte: u8, num_bits: usize)-> Result, HashError>; ***/ diff --git a/crypto/core-test-framework/src/kdf.rs b/crypto/core-test-framework/src/kdf.rs index 679ef598..8419d82a 100644 --- a/crypto/core-test-framework/src/kdf.rs +++ b/crypto/core-test-framework/src/kdf.rs @@ -1,9 +1,13 @@ //! Generic behaviour tests for anything that implements [`KDF`]. +// Imports needed for alloc +#[allow(unused_imports)] use bouncycastle_core::key_material::{ KeyMaterial, KeyMaterial256, KeyMaterial512, KeyMaterialTrait, KeyType, }; +#[allow(unused_imports)] use bouncycastle_core::traits::{KDF, SecurityStrength}; +// emd imports needed for alloc /// Instance of the test framework. pub struct TestFrameworkKDF { @@ -22,12 +26,15 @@ impl TestFrameworkKDF { additional_input: &[u8], expected_output: &impl KeyMaterialTrait, ) { - /*** Test derive_key() ***/ - let kdf = H::default(); - let output = kdf.derive_key(key, additional_input).unwrap(); - // TODO: will need to handle the fact that this API might return a truncated version of the expected output - // TODO: IE if output_len < expected; then check that the bit you have is equal - assert_eq!(output.ref_to_bytes(), expected_output.ref_to_bytes()); + #[cfg(feature = "alloc")] + { + /*** Test derive_key() ***/ + let kdf = H::default(); + let output = kdf.derive_key(key, additional_input).unwrap(); + // TODO: will need to handle the fact that this API might return a truncated version of the expected output + // TODO: IE if output_len < expected; then check that the bit you have is equal + assert_eq!(output.ref_to_bytes(), expected_output.ref_to_bytes()); + } /*** Test derive_key_out() ***/ let kdf = H::default(); @@ -40,10 +47,14 @@ impl TestFrameworkKDF { assert_eq!(output.key_len(), expected_output.key_len()); assert_eq!(output.ref_to_bytes(), expected_output.ref_to_bytes()); - /*** Test that additional_input changes the output ***/ - let out_key1 = H::default().derive_key(key, &[0u8; 0]).unwrap(); - let out_key2 = H::default().derive_key(key, b"some additional input").unwrap(); - assert_ne!(out_key1.ref_to_bytes(), out_key2.ref_to_bytes()); + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + /*** Test that additional_input changes the output ***/ + let out_key1 = H::default().derive_key(key, &[0u8; 0]).unwrap(); + let out_key2 = H::default().derive_key(key, b"some additional input").unwrap(); + assert_ne!(out_key1.ref_to_bytes(), out_key2.ref_to_bytes()); + } /*** Test truncation -- all KDFs should support this ***/ @@ -58,39 +69,43 @@ impl TestFrameworkKDF { // Some KDFs (such as HKDF) are XOFs underneath and will support longer outputs, but not all are (such as SHA3), // so we can't test extendable output generically for all KDFs. - /*** Test entropy mapping ***/ - - // Zeroized -> Zeroized - let zeroized_key = KeyMaterial256::new(); - assert_eq!(zeroized_key.key_type(), KeyType::Zeroized); - let out_key = H::default().derive_key(&zeroized_key, &[0u8; 10]).unwrap(); - // since we've done some computation, the result will not actually be zeroized, even if all input key material was zeroized. - assert_eq!(out_key.key_type(), KeyType::Unknown); - assert_eq!(out_key.security_strength(), SecurityStrength::None); - - // BytesLowEntropy -> BytesLowEntropy - let low_entropy_key = - KeyMaterial256::from_bytes_as_type(&[1u8; 16], KeyType::Unknown).unwrap(); - assert_eq!(low_entropy_key.key_type(), KeyType::Unknown); - let out_key = H::default().derive_key(&low_entropy_key, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::Unknown); - assert_eq!(out_key.security_strength(), SecurityStrength::None); - - // BytesFullEntropy -> BytesLowEntropy if not enough to fill the hash block - let low_entropy_key = - KeyMaterial256::from_bytes_as_type(&[1u8; 6], KeyType::CryptographicRandom).unwrap(); - assert_eq!(low_entropy_key.key_type(), KeyType::CryptographicRandom); - let out_key = H::default().derive_key(&low_entropy_key, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::Unknown); - assert_eq!(out_key.security_strength(), SecurityStrength::None); - - // BytesFullEntropy -> BytesFullEntropy - let full_entropy_key = - KeyMaterial512::from_bytes_as_type(&[1u8; 64], KeyType::CryptographicRandom).unwrap(); - assert_eq!(full_entropy_key.key_type(), KeyType::CryptographicRandom); - let out_key = H::default().derive_key(&full_entropy_key, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::CryptographicRandom); - assert!(out_key.security_strength() > SecurityStrength::None); + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + /*** Test entropy mapping ***/ + + // Zeroized -> Zeroized + let zeroized_key = KeyMaterial256::new(); + assert_eq!(zeroized_key.key_type(), KeyType::Zeroized); + let out_key = H::default().derive_key(&zeroized_key, &[0u8; 10]).unwrap(); + // since we've done some computation, the result will not actually be zeroized, even if all input key material was zeroized. + assert_eq!(out_key.key_type(), KeyType::Unknown); + assert_eq!(out_key.security_strength(), SecurityStrength::None); + + // BytesLowEntropy -> BytesLowEntropy + let low_entropy_key = + KeyMaterial256::from_bytes_as_type(&[1u8; 16], KeyType::Unknown).unwrap(); + assert_eq!(low_entropy_key.key_type(), KeyType::Unknown); + let out_key = H::default().derive_key(&low_entropy_key, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::Unknown); + assert_eq!(out_key.security_strength(), SecurityStrength::None); + + // BytesFullEntropy -> BytesLowEntropy if not enough to fill the hash block + let low_entropy_key = + KeyMaterial256::from_bytes_as_type(&[1u8; 6], KeyType::CryptographicRandom).unwrap(); + assert_eq!(low_entropy_key.key_type(), KeyType::CryptographicRandom); + let out_key = H::default().derive_key(&low_entropy_key, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::Unknown); + assert_eq!(out_key.security_strength(), SecurityStrength::None); + + // BytesFullEntropy -> BytesFullEntropy + let full_entropy_key = + KeyMaterial512::from_bytes_as_type(&[1u8; 64], KeyType::CryptographicRandom).unwrap(); + assert_eq!(full_entropy_key.key_type(), KeyType::CryptographicRandom); + let out_key = H::default().derive_key(&full_entropy_key, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::CryptographicRandom); + assert!(out_key.security_strength() > SecurityStrength::None); + } } /// pub fn test_kdf_multiple_key( @@ -99,16 +114,19 @@ impl TestFrameworkKDF { additional_input: &[u8], expected_output: &mut impl KeyMaterialTrait, ) { - /*** test derive_key_from_multiple() ***/ - let kdf = H::default(); - - let output = kdf.derive_key_from_multiple(keys, additional_input).unwrap(); - // This is sortof a hack since the rust language won't easily allow me to make the KeyMaterials the same length - if output.key_len() < expected_output.key_len() { - expected_output.set_key_len(output.key_len()).unwrap(); // truncates should be infallible + #[cfg(feature = "alloc")] + { + /*** test derive_key_from_multiple() ***/ + let kdf = H::default(); + + let output = kdf.derive_key_from_multiple(keys, additional_input).unwrap(); + // This is sortof a hack since the rust language won't easily allow me to make the KeyMaterials the same length + if output.key_len() < expected_output.key_len() { + expected_output.set_key_len(output.key_len()).unwrap(); // truncates should be infallible + } + assert_eq!(output.key_len(), expected_output.key_len()); + assert_eq!(output.ref_to_bytes(), expected_output.ref_to_bytes()); } - assert_eq!(output.key_len(), expected_output.key_len()); - assert_eq!(output.ref_to_bytes(), expected_output.ref_to_bytes()); /*** test derive_key_from_multiple_out() ***/ let kdf = H::default(); @@ -122,11 +140,15 @@ impl TestFrameworkKDF { assert_eq!(output.key_len(), expected_output.key_len()); assert_eq!(output.ref_to_bytes(), expected_output.ref_to_bytes()); - /*** Test that additional_input changes the output ***/ - let out_key1 = H::default().derive_key_from_multiple(keys, &[0u8; 0]).unwrap(); - let out_key2 = - H::default().derive_key_from_multiple(keys, b"some additional input").unwrap(); - assert_ne!(out_key1.ref_to_bytes(), out_key2.ref_to_bytes()); + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + /*** Test that additional_input changes the output ***/ + let out_key1 = H::default().derive_key_from_multiple(keys, &[0u8; 0]).unwrap(); + let out_key2 = + H::default().derive_key_from_multiple(keys, b"some additional input").unwrap(); + assert_ne!(out_key1.ref_to_bytes(), out_key2.ref_to_bytes()); + } /*** Test trunctation -- all KDFs should support this ***/ @@ -139,43 +161,47 @@ impl TestFrameworkKDF { assert_eq!(output.key_len(), 10); assert_eq!(output.ref_to_bytes(), &expected_output.ref_to_bytes()[..10]); - /*** Test entropy mapping ***/ - - // Zeroized -> Zeroized - let zeroized_key = KeyMaterial256::new(); - assert_eq!(zeroized_key.key_type(), KeyType::Zeroized); - assert_eq!(zeroized_key.security_strength(), SecurityStrength::None); - let keys = [&zeroized_key, &zeroized_key]; - let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::Unknown); - assert_eq!(out_key.security_strength(), SecurityStrength::None); - - // BytesLowEntropy -> BytesLowEntropy - let low_entropy_key = - KeyMaterial256::from_bytes_as_type(&[1u8; 16], KeyType::Unknown).unwrap(); - assert_eq!(low_entropy_key.key_type(), KeyType::Unknown); - let keys = [&zeroized_key, &low_entropy_key]; - let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::Unknown); - assert_eq!(out_key.security_strength(), SecurityStrength::None); - - // BytesFullEntropy -> BytesLowEntropy if not enough to fill the hash block - let low_entropy_key = - KeyMaterial256::from_bytes_as_type(&[1u8; 6], KeyType::CryptographicRandom).unwrap(); - assert_eq!(low_entropy_key.key_type(), KeyType::CryptographicRandom); - let keys = [&zeroized_key, &low_entropy_key]; - let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::Unknown); - assert_eq!(out_key.security_strength(), SecurityStrength::None); - - // BytesFullEntropy -> BytesFullEntropy - let zeroized64_key = KeyMaterial512::new(); - let full_entropy_key = - KeyMaterial512::from_bytes_as_type(&[1u8; 64], KeyType::CryptographicRandom).unwrap(); - assert_eq!(full_entropy_key.key_type(), KeyType::CryptographicRandom); - let keys = [&zeroized64_key, &full_entropy_key]; - let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); - assert_eq!(out_key.key_type(), KeyType::CryptographicRandom); - assert!(out_key.security_strength() > SecurityStrength::None); + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + /*** Test entropy mapping ***/ + + // Zeroized -> Zeroized + let zeroized_key = KeyMaterial256::new(); + assert_eq!(zeroized_key.key_type(), KeyType::Zeroized); + assert_eq!(zeroized_key.security_strength(), SecurityStrength::None); + let keys = [&zeroized_key, &zeroized_key]; + let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::Unknown); + assert_eq!(out_key.security_strength(), SecurityStrength::None); + + // BytesLowEntropy -> BytesLowEntropy + let low_entropy_key = + KeyMaterial256::from_bytes_as_type(&[1u8; 16], KeyType::Unknown).unwrap(); + assert_eq!(low_entropy_key.key_type(), KeyType::Unknown); + let keys = [&zeroized_key, &low_entropy_key]; + let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::Unknown); + assert_eq!(out_key.security_strength(), SecurityStrength::None); + + // BytesFullEntropy -> BytesLowEntropy if not enough to fill the hash block + let low_entropy_key = + KeyMaterial256::from_bytes_as_type(&[1u8; 6], KeyType::CryptographicRandom).unwrap(); + assert_eq!(low_entropy_key.key_type(), KeyType::CryptographicRandom); + let keys = [&zeroized_key, &low_entropy_key]; + let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::Unknown); + assert_eq!(out_key.security_strength(), SecurityStrength::None); + + // BytesFullEntropy -> BytesFullEntropy + let zeroized64_key = KeyMaterial512::new(); + let full_entropy_key = + KeyMaterial512::from_bytes_as_type(&[1u8; 64], KeyType::CryptographicRandom).unwrap(); + assert_eq!(full_entropy_key.key_type(), KeyType::CryptographicRandom); + let keys = [&zeroized64_key, &full_entropy_key]; + let out_key = H::default().derive_key_from_multiple(&keys, &[0u8; 10]).unwrap(); + assert_eq!(out_key.key_type(), KeyType::CryptographicRandom); + assert!(out_key.security_strength() > SecurityStrength::None); + } } } diff --git a/crypto/core-test-framework/src/lib.rs b/crypto/core-test-framework/src/lib.rs index 2dced83d..431871bd 100644 --- a/crypto/core-test-framework/src/lib.rs +++ b/crypto/core-test-framework/src/lib.rs @@ -8,6 +8,8 @@ //! implementations. //! //! Should only ever be a dev-dependency. +//! This crate need not support no_std + #![forbid(unsafe_code)] // Let's include this for completeness, but since this in an internal test crate, no reason to fully diff --git a/crypto/core-test-framework/src/mac.rs b/crypto/core-test-framework/src/mac.rs index 8430507c..5bd23d5e 100644 --- a/crypto/core-test-framework/src/mac.rs +++ b/crypto/core-test-framework/src/mac.rs @@ -27,9 +27,12 @@ impl TestFrameworkMAC { input: &[u8], expected_output: &[u8], ) { - // Test ::mac() - let out = M::new_allow_weak_key(key).unwrap().mac(input); - assert_eq!(out, expected_output); + #[cfg(feature = "alloc")] + { + // Test ::mac() + let out = M::new_allow_weak_key(key).unwrap().mac(input); + assert_eq!(out, expected_output); + } // Test ::mac_out let mut out = vec![0u8; expected_output.len()]; @@ -53,16 +56,43 @@ impl TestFrameworkMAC { // Test ::verify() assert!(M::new_allow_weak_key(key).unwrap().verify(input, expected_output)); - // Test .new(), .do_update(), .do_mac_final() - // At the same time, test .output_len() + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + // Test .new(), .do_update(), .do_mac_final() + // At the same time, test .output_len() + let mut mac = M::new_allow_weak_key(key).unwrap(); + let output_len = mac.output_len(); + mac.do_update(input); + let out = mac.do_final(); + assert_eq!(out, expected_output); + + // Test .output_len() + assert_eq!(output_len, out.len()); + } + + // Test ::mac_array() and ::do_final_array() (no_std alternatives). + // N = 64 is >= every supported MAC output length (and >= the FIPS minimum), so the tag lands + // in the first output_len bytes with a zero-padded tail. + let arr: [u8; 64] = M::new_allow_weak_key(key).unwrap().mac_array(input).unwrap(); + assert_eq!(&arr[..expected_output.len()], expected_output, "mac_array digest mismatch"); + assert!( + arr[expected_output.len()..].iter().all(|&b| b == 0), + "mac_array tail not zero-padded" + ); + let mut mac = M::new_allow_weak_key(key).unwrap(); - let output_len = mac.output_len(); mac.do_update(input); - let out = mac.do_final(); - assert_eq!(out, expected_output); - - // Test .output_len() - assert_eq!(output_len, out.len()); + let arr: [u8; 64] = mac.do_final_array().unwrap(); + assert_eq!( + &arr[..expected_output.len()], + expected_output, + "do_final_array digest mismatch" + ); + assert!( + arr[expected_output.len()..].iter().all(|&b| b == 0), + "do_final_array tail not zero-padded" + ); // Test .init(), .do_update(), .do_mac_final_out() let mut mac = M::new_allow_weak_key(key).unwrap(); @@ -125,23 +155,27 @@ impl TestFrameworkMAC { }) .unwrap(); - // init - assert!( - low_security_key.security_strength() - < M::new_allow_weak_key(key).unwrap().max_security_strength() - ); - // complains at first - match M::new(&low_security_key) { - Err(MACError::KeyMaterialError(KeyMaterialError::SecurityStrength(_))) => { /* fine */ } - _ => { - panic!( - "This should have thrown a KeyMaterialError::SecurityStrength error but it didn't" - ) + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + // init + assert!( + low_security_key.security_strength() + < M::new_allow_weak_key(key).unwrap().max_security_strength() + ); + // complains at first + match M::new(&low_security_key) { + Err(MACError::KeyMaterialError(KeyMaterialError::SecurityStrength(_))) => { /* fine */ } + _ => { + panic!( + "This should have thrown a KeyMaterialError::SecurityStrength error but it didn't" + ) + } } + // but fine if you do it with .allow_weak_keys() + let mut hmac = M::new_allow_weak_key(&low_security_key).unwrap(); + hmac.do_update(b"Hi There"); + hmac.do_final(); } - // but fine if you do it with .allow_weak_keys() - let mut hmac = M::new_allow_weak_key(&low_security_key).unwrap(); - hmac.do_update(b"Hi There"); - hmac.do_final(); } } diff --git a/crypto/core-test-framework/src/signature.rs b/crypto/core-test-framework/src/signature.rs index 28eece51..48c82b57 100644 --- a/crypto/core-test-framework/src/signature.rs +++ b/crypto/core-test-framework/src/signature.rs @@ -268,21 +268,25 @@ impl TestFrameworkSignature { _ => panic!("Unexpected error"), } - // sign_ph - let (pk, sk) = keygen().unwrap(); - let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); - let sig_val = PHSIGNER::sign_ph(&sk, &ph, None).unwrap(); - PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); - PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); - - // sign_ph_out - let (pk, sk) = keygen().unwrap(); - let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); - let mut sig_val = [0u8; SIG_LEN]; - let bytes_written = PHSIGNER::sign_ph_out(&sk, &ph, None, &mut sig_val).unwrap(); - assert_eq!(bytes_written, SIG_LEN); - PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); - PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] + { + // sign_ph + let (pk, sk) = keygen().unwrap(); + let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); + let sig_val = PHSIGNER::sign_ph(&sk, &ph, None).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); + + // sign_ph_out + let (pk, sk) = keygen().unwrap(); + let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); + let mut sig_val = [0u8; SIG_LEN]; + let bytes_written = PHSIGNER::sign_ph_out(&sk, &ph, None, &mut sig_val).unwrap(); + assert_eq!(bytes_written, SIG_LEN); + PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); + } } } diff --git a/crypto/core-test-framework/src/xof.rs b/crypto/core-test-framework/src/xof.rs index 9ec5040b..8dd05141 100644 --- a/crypto/core-test-framework/src/xof.rs +++ b/crypto/core-test-framework/src/xof.rs @@ -1,7 +1,11 @@ //! Generic behaviour tests for anything that implements [`XOF`]. +// Imports needed for alloc +#[allow(unused_imports)] use bouncycastle_core::errors::HashError; +#[allow(unused_imports)] use bouncycastle_core::traits::XOF; +// end imports needed for alloc /// Instance of the test framework. pub struct TestFrameworkXOF { @@ -16,6 +20,8 @@ impl TestFrameworkXOF { Self { enable_partial_byte_tests: true } } + // todo: may require no_std equivalent + #[cfg(feature = "alloc")] /// Test the absorb-after-squeeze members of trait XOF against the given input-output pair. /// This is not exhaustive; it covers the rules laid out in the "State and Absorb-after-Squeeze" /// section of the [`XOF`] docs: an XOF is an absorb phase followed by a squeeze phase, once diff --git a/crypto/core/Cargo.toml b/crypto/core/Cargo.toml index 6415376a..dac17648 100644 --- a/crypto/core/Cargo.toml +++ b/crypto/core/Cargo.toml @@ -4,14 +4,13 @@ version.workspace = true edition.workspace = true [features] -# `std` gates the ergonomic, allocating (`Vec`-returning) one-shot APIs. It is on by -# default today; a future `--no-default-features` build is what will let `core` become -# `#![no_std]` (see the TODO at the top of `src/lib.rs`). -default = ["std"] -std = [] +default = ["alloc"] +alloc = [ + "bouncycastle-rng/alloc" +] [dependencies] bouncycastle-utils.workspace = true [dev-dependencies] -bouncycastle-rng.workspace = true +bouncycastle-rng = { workspace = true, default-features = false } diff --git a/crypto/core/src/lib.rs b/crypto/core/src/lib.rs index a75792dc..42258bc8 100644 --- a/crypto/core/src/lib.rs +++ b/crypto/core/src/lib.rs @@ -1,11 +1,15 @@ //! This crate defines the core traits and types used by the rest of the bc-rust.test library. -// todo -- this is the goal, but first need to remove all the Vec in favour of compile-time array sizing. -// #![no_std] - +#![cfg_attr(not(feature = "alloc"), no_std)] #![forbid(unsafe_code)] #![forbid(missing_docs)] +// The `Vec`/`Box`-returning convenience APIs live behind the (default-on) `alloc` feature. +// When it is enabled we pull in the `alloc` crate; `no_std` users who disable it get the +// allocation-free `*_out(&mut [u8])` and `*_array::()` APIs only. +#[cfg(feature = "alloc")] +extern crate alloc; + pub mod errors; pub mod key_material; pub mod suspendable_state; diff --git a/crypto/core/src/suspendable_state.rs b/crypto/core/src/suspendable_state.rs index 47a8e0f0..fff132b9 100644 --- a/crypto/core/src/suspendable_state.rs +++ b/crypto/core/src/suspendable_state.rs @@ -65,6 +65,7 @@ pub const LIB_VERSION: SemVer = SemVer { patch: parse_version_component(env!("CARGO_PKG_VERSION_PATCH")), }; +#[cfg(feature = "alloc")] #[test] /// Just to check it visually fn print_lib_ver() { diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 22652570..99ab024c 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -5,6 +5,11 @@ use crate::key_material::KeyMaterialTrait; use core::fmt::{Debug, Display}; use core::marker::Sized; +#[cfg(feature = "alloc")] +use alloc::boxed::Box; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + // Imports needed for docs #[allow(unused_imports)] use crate::key_material::KeyMaterial; @@ -16,7 +21,7 @@ use crate::key_material::KeyType; pub trait AEADCipher: SymmetricCipher + Sized { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] /// A one-shot API to encrypt some plaintext with the given key. /// A distinguishing feature of AEAD ciphers is the ability to provide additional authenticated data (AAD) /// that is not encrypted but is protected by the authentication tag; ie it can be sent along with the ciphertext @@ -46,7 +51,7 @@ pub trait AEADCipher Result<[u8; TAG_LEN], SymmetricCipherError>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] /// A one-shot API to decrypt some ciphertext with the given key. /// This function returns the ciphertext as a `Vec`, and therefore is only available when compiling with std. fn aead_decrypt( @@ -177,6 +182,7 @@ pub trait Hash: Algorithm + Default { /// The size of the output in bytes. fn output_len(&self) -> usize; + #[cfg(feature = "alloc")] /// A static one-shot API that hashes the provided data. /// `data` can be of any length, including zero bytes. fn hash(self, data: &[u8]) -> Vec; @@ -187,11 +193,26 @@ pub trait Hash: Algorithm + Default { /// The return value is the number of bytes written. fn hash_out(self, data: &[u8], output: &mut [u8]) -> usize; + /// A static one-shot, `no_std`-friendly API that hashes the provided data and returns the digest + /// in a caller-sized array. This is the allocation-free counterpart to [Hash::hash]. + /// + /// `N` should equal [Hash::output_len]; the same truncation / zero-padding rules as + /// [Hash::hash_out] apply if `N` differs from the output length. + fn hash_array(self, data: &[u8]) -> [u8; N] + where + Self: Sized, + { + let mut output = [0u8; N]; + let _ = self.hash_out(data, &mut output); + output + } + /// Provide a chunk of data to be absorbed into the hashes. /// `data` can be of any length, including zero bytes. /// do_update() is intended to be used as part of a streaming interface, and so may by called multiple times. fn do_update(&mut self, data: &[u8]); + #[cfg(feature = "alloc")] /// Finish absorbing input and produce the hashes output. /// Consumes self, so this must be the final call to this object. fn do_final(self) -> Vec; @@ -209,6 +230,22 @@ pub trait Hash: Algorithm + Default { /// The return value is the number of bytes written. fn do_final_out(self, output: &mut [u8]) -> usize; + /// Finish absorbing input and produce the hashes output in a caller-sized array. + /// This is the allocation-free, `no_std`-friendly counterpart to [Hash::do_final]. + /// Consumes self, so this must be the final call to this object. + /// + /// `N` should equal [Hash::output_len]; the same truncation / zero-padding rules as + /// [Hash::do_final_out] apply if `N` differs from the output length. + fn do_final_array(self) -> [u8; N] + where + Self: Sized, + { + let mut output = [0u8; N]; + let _ = self.do_final_out(&mut output); + output + } + + #[cfg(feature = "alloc")] /// The same as [`Hash::do_final`], but allows for supplying a partial byte as the last input. /// The `num_bits` message bits are taken from the least significant bits of /// `partial_byte`, in order (bit 0 of `partial_byte` is the first message bit). This is the @@ -228,6 +265,24 @@ pub trait Hash: Algorithm + Default { output: &mut [u8], ) -> Result; + /// The same as [Hash::do_final_partial_bits], but returns the output in a caller-sized array. + /// This is the allocation-free, `no_std`-friendly counterpart. + /// + /// `N` should equal [Hash::output_len]; the same truncation / zero-padding rules as + /// [Hash::do_final_partial_bits_out] apply if `N` differs from the output length. + fn do_final_partial_bits_array( + self, + partial_byte: u8, + num_partial_bits: usize, + ) -> Result<[u8; N], HashError> + where + Self: Sized, + { + let mut output = [0u8; N]; + self.do_final_partial_bits_out(partial_byte, num_partial_bits, &mut output)?; + Ok(output) + } + /// Returns the maximum security strength that this KDF is capable of supporting, based on the underlying primitives. fn max_security_strength(&self) -> SecurityStrength; } @@ -275,6 +330,7 @@ pub trait KDF: Default { /// /// Output length: this function will create a KeyMaterial populated with the default output length /// of the underlying hash primitive. + #[cfg(feature = "alloc")] fn derive_key( self, key: &impl KeyMaterialTrait, @@ -315,6 +371,7 @@ pub trait KDF: Default { /// /// Output length: this function will create a KeyMaterial populated with the default output length /// of the underlying hash primitive. + #[cfg(feature = "alloc")] fn derive_key_from_multiple( self, keys: &[&impl KeyMaterialTrait], @@ -481,6 +538,7 @@ pub trait MAC: Sized { /// The size of the output in bytes. fn output_len(&self) -> usize; + #[cfg(feature = "alloc")] /// One-shot API that computes a MAC for the provided data. /// `data` can be of any length, including zero bytes. /// @@ -502,6 +560,20 @@ pub trait MAC: Sized { /// The entire output buffer is zeroized before the MAC value is written. fn mac_out(self, data: &[u8], out: &mut [u8]) -> Result; + /// One-shot, `no_std`-friendly API that computes a MAC for the provided data and returns it in a + /// caller-sized array. This is the allocation-free counterpart to [MAC::mac]. + /// + /// `N` should equal [MAC::output_len]; the same rules as [MAC::mac_out] apply (including the + /// possible [MACError::InvalidLength] for undersized buffers). + fn mac_array(self, data: &[u8]) -> Result<[u8; N], MACError> + where + Self: Sized, + { + let mut out = [0u8; N]; + self.mac_out(data, &mut out)?; + Ok(out) + } + /// One-shot API that verifies a MAC for the provided data. /// `data` can be of any length, including zero bytes. /// @@ -520,6 +592,7 @@ pub trait MAC: Sized { /// do_update() is intended to be used as part of a streaming interface, and so may by called multiple times. fn do_update(&mut self, data: &[u8]); + #[cfg(feature = "alloc")] /// Finish absorbing input and produce the MAC value. fn do_final(self) -> Vec; @@ -530,6 +603,20 @@ pub trait MAC: Sized { /// The entire output buffer is zeroized before the MAC value is written. fn do_final_out(self, out: &mut [u8]) -> Result; + /// The allocation-free, `no_std`-friendly counterpart to [MAC::do_final]: returns the MAC value + /// in a caller-sized array. Consumes self, so this must be the final call to this object. + /// + /// `N` should equal [MAC::output_len]; the same rules as [MAC::do_final_out] apply (including the + /// possible [MACError::InvalidLength] for undersized buffers). + fn do_final_array(self) -> Result<[u8; N], MACError> + where + Self: Sized, + { + let mut out = [0u8; N]; + self.do_final_out(&mut out)?; + Ok(out) + } + /// Internally, this will re-compute the MAC value and then compare it to the provided mac value /// using constant-time comparison. It is highly encouraged to use this utility function instead of /// comparing mac values for equality yourself. @@ -638,6 +725,7 @@ pub trait RNG { /// Returns the next random 32-bit integer. fn next_int(&mut self) -> Result; + #[cfg(feature = "alloc")] /// Returns the number of requested bytes. fn next_bytes(&mut self, len: usize) -> Result, RNGError>; @@ -995,7 +1083,7 @@ pub trait SuspendableKeyed: Sized { /// as AEADs or stream ciphers may need to stick extra data either at the beginning or end of the ciphertext. /// See the documentation of the underlying implementation for more details. pub trait SymmetricCipher: Algorithm { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] /// A one-shot API to encrypt some plaintext with the given key. /// This function returns the ciphertext as a `Vec`, and therefore is only available when compiling with std. /// Returns a tuple containing the initialization data and the ciphertext. @@ -1015,7 +1103,7 @@ pub trait SymmetricCipher: Alg plaintext: &[u8], ciphertext: &mut [u8], ) -> Result<([u8; INIT_DATA_LEN], usize), SymmetricCipherError>; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] /// A one-shot API to decrypt some ciphertext with the given key. /// This function returns the ciphertext as a `Vec`, and therefore is only available when compiling with std. /// This is not available if building for no_std. @@ -1066,6 +1154,7 @@ pub trait SymmetricCipher: Alg /// /// If Absorb-after-Squeeze becomes necessary to support in the future, then these design choices can be revisited. pub trait XOF: Default { + #[cfg(feature = "alloc")] /// A static one-shot API that digests the input data and produces `result_len` bytes of output. fn hash_xof(self, data: &[u8], result_len: usize) -> Vec; @@ -1074,6 +1163,17 @@ pub trait XOF: Default { /// The entire output buffer is zeroized before the output is written. fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize; + /// The allocation-free, `no_std`-friendly counterpart to [XOF::hash_xof]: digests the input data + /// and produces exactly `N` bytes of output in a fixed-size array. + fn hash_xof_array(self, data: &[u8]) -> [u8; N] + where + Self: Sized, + { + let mut output = [0u8; N]; + let _ = self.hash_xof_out(data, &mut output); + output + } + /// Absorb some amount of input. fn absorb(&mut self, data: &[u8]) -> Result<(), HashError>; @@ -1092,6 +1192,7 @@ pub trait XOF: Default { num_bits: usize, ) -> Result<(), HashError>; + #[cfg(feature = "alloc")] /// Can be called multiple times. fn squeeze(&mut self, num_bytes: usize) -> Vec; @@ -1100,6 +1201,17 @@ pub trait XOF: Default { /// The entire output buffer is zeroized before the output is written. fn squeeze_out(&mut self, output: &mut [u8]) -> usize; + /// The allocation-free, `no_std`-friendly counterpart to [XOF::squeeze]: squeezes exactly `N` + /// bytes into a fixed-size array. Can be called multiple times. + fn squeeze_array(&mut self) -> [u8; N] + where + Self: Sized, + { + let mut output = [0u8; N]; + let _ = self.squeeze_out(&mut output); + output + } + /// Squeezes a partial byte (`num_bits` in `0..=7`) from the XOF. /// The bits are returned in the least significant `num_bits` bits of the returned u8, with the /// remaining high bits zero. This follows the FIPS 202 Appendix B.1 bit-string convention diff --git a/crypto/hkdf/Cargo.toml b/crypto/hkdf/Cargo.toml index 6df444bd..5cb21b1e 100644 --- a/crypto/hkdf/Cargo.toml +++ b/crypto/hkdf/Cargo.toml @@ -3,9 +3,19 @@ name = "bouncycastle-hkdf" version.workspace = true edition.workspace = true +[features] +default = ["alloc"] +alloc = [ + "bouncycastle-core/alloc", + "bouncycastle-core-test-framework/alloc", + "bouncycastle-hmac/alloc", + "bouncycastle-rng/alloc", + "bouncycastle-sha2/alloc", +] + [dependencies] -bouncycastle-core.workspace = true -bouncycastle-hmac.workspace = true +bouncycastle-core = { workspace = true, default-features = false } +bouncycastle-hmac = { workspace = true, default-features = false } bouncycastle-utils.workspace = true # The concrete HKDF instantiations (HKDF_SHA256, HKDF_SHA512) live in bouncycastle-sha2, which makes @@ -14,8 +24,8 @@ bouncycastle-utils.workspace = true # library's own hashes; Cargo permits cycles through dev-dependencies. # todo -- we're about to change that and move them to their respective crates in the next phase. [dev-dependencies] -bouncycastle-core-test-framework.workspace = true +bouncycastle-core-test-framework = { workspace = true, default-features = false } criterion.workspace = true -bouncycastle-rng.workspace = true +bouncycastle-rng = { workspace = true, default-features = false } bouncycastle-hex.workspace = true -bouncycastle-sha2.workspace = true +bouncycastle-sha2 = { workspace = true, default-features = false } diff --git a/crypto/hkdf/src/lib.rs b/crypto/hkdf/src/lib.rs index 8d7dc8ac..879933a7 100644 --- a/crypto/hkdf/src/lib.rs +++ b/crypto/hkdf/src/lib.rs @@ -613,6 +613,7 @@ impl KDF for HKDF { + #[cfg(feature = "alloc")] /// This invokes [`HKDF::extract_and_expand_out`] with a zero salt and using the provided key as ikm. /// This provides a fixed-length output, which may be truncated as needed. fn derive_key( @@ -644,6 +645,7 @@ impl MAC for HMAC Vec { let mut out = vec![0_u8; self.hasher.output_len()]; let bytes_written = self.mac_out(data, &mut out).expect("HMAC::mac(): should not have failed because we gave it a sufficiently large output buffer to meet FIPS rules."); @@ -338,6 +339,7 @@ impl MAC for HMAC Vec { let mut out = vec![0_u8; self.hasher.output_len()]; self.do_final_internal_out(&mut out).expect("HMAC::do_final(): should not have failed because we gave it a sufficiently large output buffer to meet FIPS rules."); diff --git a/crypto/rng/Cargo.toml b/crypto/rng/Cargo.toml index 48e1a3c6..5a561324 100644 --- a/crypto/rng/Cargo.toml +++ b/crypto/rng/Cargo.toml @@ -3,16 +3,24 @@ name = "bouncycastle-rng" version.workspace = true edition.workspace = true +[features] +default = ["alloc"] +alloc = [ + "bouncycastle-core/alloc", + "bouncycastle-core-test-framework/alloc", + "bouncycastle-sha2/alloc", +] + [dependencies] -bouncycastle-core.workspace = true -bouncycastle-sha2.workspace = true +bouncycastle-core = { workspace = true, default-features = false } +bouncycastle-sha2 = { workspace = true, default-features = false } bouncycastle-utils.workspace = true # external getrandom = "0.4.0-rc.1" [dev-dependencies] -bouncycastle-core-test-framework.workspace = true +bouncycastle-core-test-framework = { workspace = true, default-features = false } criterion.workspace = true [[bench]] diff --git a/crypto/rng/src/hash_drbg80090a.rs b/crypto/rng/src/hash_drbg80090a.rs index be70cb8d..d7eb95cd 100644 --- a/crypto/rng/src/hash_drbg80090a.rs +++ b/crypto/rng/src/hash_drbg80090a.rs @@ -504,6 +504,7 @@ impl RNG for HashDRBG80090A { Ok(u32::from_le_bytes(out)) } + #[cfg(feature = "alloc")] fn next_bytes(&mut self, len: usize) -> Result, RNGError> { self.generate("next_bytes".as_bytes(), len) } diff --git a/crypto/sha2/Cargo.toml b/crypto/sha2/Cargo.toml index affcde1b..959e49da 100644 --- a/crypto/sha2/Cargo.toml +++ b/crypto/sha2/Cargo.toml @@ -3,16 +3,26 @@ name = "bouncycastle-sha2" version.workspace = true edition.workspace = true +[features] +default = ["alloc"] +alloc = [ + "bouncycastle-core/alloc", + "bouncycastle-core-test-framework/alloc", + "bouncycastle-hkdf/alloc", + "bouncycastle-hmac/alloc", + "bouncycastle-rng/alloc", +] + [dependencies] -bouncycastle-core.workspace = true -bouncycastle-hkdf.workspace = true -bouncycastle-hmac.workspace = true +bouncycastle-core = { workspace = true, default-features = false } +bouncycastle-hkdf = { workspace = true, default-features = false } +bouncycastle-hmac = { workspace = true, default-features = false } bouncycastle-utils.workspace = true [dev-dependencies] criterion.workspace = true -bouncycastle-core-test-framework.workspace = true -bouncycastle-rng.workspace = true +bouncycastle-core-test-framework = { workspace = true, default-features = false } +bouncycastle-rng = { workspace = true, default-features = false } [[bench]] name = "sha2_benches" diff --git a/crypto/sha2/src/sha256.rs b/crypto/sha2/src/sha256.rs index 34d09775..a203e8f5 100644 --- a/crypto/sha2/src/sha256.rs +++ b/crypto/sha2/src/sha256.rs @@ -188,6 +188,7 @@ impl Hash for SHA256Internal { PARAMS::OUTPUT_LEN } + #[cfg(feature = "alloc")] fn hash(self, data: &[u8]) -> Vec { let mut output = vec![0u8; PARAMS::OUTPUT_LEN]; self.hash_out(data, &mut output); @@ -234,6 +235,7 @@ impl Hash for SHA256Internal { self.x_buf_off = remaining; } + #[cfg(feature = "alloc")] fn do_final(self) -> Vec { let mut output = vec![0u8; PARAMS::OUTPUT_LEN]; self.do_final_out(&mut output); @@ -274,6 +276,7 @@ impl Hash for SHA256Internal { n } + #[cfg(feature = "alloc")] /// TODO: This is defined in FIPS 180-4 s. 5.1.2 /// TODO: /// TODO: It can be implemented if required diff --git a/crypto/sha2/src/sha512.rs b/crypto/sha2/src/sha512.rs index c31e3065..76d41fc0 100644 --- a/crypto/sha2/src/sha512.rs +++ b/crypto/sha2/src/sha512.rs @@ -200,6 +200,7 @@ impl Hash for SHA512Internal { PARAMS::OUTPUT_LEN } + #[cfg(feature = "alloc")] fn hash(self, data: &[u8]) -> Vec { let mut output = vec![0u8; self.output_len()]; self.hash_out(data, &mut output); @@ -245,6 +246,7 @@ impl Hash for SHA512Internal { self.x_buf_off = remaining; } + #[cfg(feature = "alloc")] fn do_final(self) -> Vec { let mut output = vec![0u8; PARAMS::OUTPUT_LEN]; self.do_final_out(&mut output); @@ -286,6 +288,7 @@ impl Hash for SHA512Internal { n } + #[cfg(feature = "alloc")] /// TODO: This is defined in FIPS 180-4 s. 5.1.2 /// TODO: /// TODO: It can be implemented if required diff --git a/crypto/utils/Cargo.toml b/crypto/utils/Cargo.toml index a23ce1a1..7c240445 100644 --- a/crypto/utils/Cargo.toml +++ b/crypto/utils/Cargo.toml @@ -6,4 +6,4 @@ edition.workspace = true [dependencies] [dev-dependencies] -bouncycastle-core.workspace = true +bouncycastle-core = { workspace = true, default-features = false }