mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 12:20:52 +02:00
Merge pull request #10070 from holtrop-wolfssl/rust-rand_core-aead-cipher
Rust wrapper: add rand_core, aead, cipher trait implementations
This commit is contained in:
+102
@@ -2,6 +2,17 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"blobby",
|
||||
"crypto-common 0.1.7",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -37,6 +48,12 @@ version = "2.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||
|
||||
[[package]]
|
||||
name = "blobby"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "847495c209977a90e8aad588b959d0ca9f5dc228096d29a6bd3defd53f35eaec"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
@@ -52,6 +69,16 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
|
||||
dependencies = [
|
||||
"crypto-common 0.2.1",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
@@ -63,18 +90,66 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
@@ -156,6 +231,18 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.2"
|
||||
@@ -208,12 +295,24 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
@@ -289,6 +388,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
name = "wolfssl-wolfcrypt"
|
||||
version = "1.2.0"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"bindgen",
|
||||
"cipher",
|
||||
"rand_core 0.10.0",
|
||||
"regex",
|
||||
]
|
||||
|
||||
@@ -12,6 +12,18 @@ readme = "README.md"
|
||||
|
||||
[features]
|
||||
std = []
|
||||
rand_core = ["dep:rand_core"]
|
||||
aead = ["dep:aead"]
|
||||
cipher = ["dep:cipher"]
|
||||
|
||||
[dependencies]
|
||||
rand_core = { version = "0.10", optional = true, default-features = false }
|
||||
aead = { version = "0.5", optional = true, default-features = false }
|
||||
cipher = { version = "0.5", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
aead = { version = "0.5", features = ["alloc", "dev"] }
|
||||
cipher = "0.5"
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.72.1"
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
FEATURES := rand_core,aead,cipher
|
||||
CARGO_FEATURE_FLAGS := --features $(FEATURES)
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
cargo build
|
||||
cargo clippy
|
||||
cargo doc
|
||||
cargo build $(CARGO_FEATURE_FLAGS)
|
||||
cargo clippy $(CARGO_FEATURE_FLAGS)
|
||||
cargo doc $(CARGO_FEATURE_FLAGS)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
cargo test -- --test-threads=1
|
||||
cargo test $(CARGO_FEATURE_FLAGS) -- --test-threads=1
|
||||
|
||||
.PHONY: testfips
|
||||
testfips:
|
||||
cargo test --lib --bins --tests -- --test-threads=1
|
||||
cargo test $(CARGO_FEATURE_FLAGS) --lib --bins --tests -- --test-threads=1
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -155,8 +155,7 @@ impl ChaCha20Poly1305 {
|
||||
return Err(rc);
|
||||
}
|
||||
let wc_ccp = unsafe { wc_ccp.assume_init() };
|
||||
let chacha20poly1305 = ChaCha20Poly1305 { wc_ccp };
|
||||
Ok(chacha20poly1305)
|
||||
Ok(ChaCha20Poly1305 { wc_ccp })
|
||||
}
|
||||
|
||||
/// Update AAD (additional authenticated data).
|
||||
@@ -244,10 +243,95 @@ impl ChaCha20Poly1305 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(xchacha20_poly1305)]
|
||||
pub struct XChaCha20Poly1305 {
|
||||
// ---------------------------------------------------------------------------
|
||||
// ChaCha20-Poly1305 aead trait implementations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// ChaCha20-Poly1305 AEAD instance holding a key for use with the
|
||||
/// `aead::KeyInit` and `aead::AeadInPlace` traits.
|
||||
#[cfg(feature = "aead")]
|
||||
pub struct ChaCha20Poly1305Aead {
|
||||
key: [u8; 32],
|
||||
}
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
impl aead::KeySizeUser for ChaCha20Poly1305Aead {
|
||||
type KeySize = aead::generic_array::typenum::U32;
|
||||
}
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
impl aead::AeadCore for ChaCha20Poly1305Aead {
|
||||
type NonceSize = aead::generic_array::typenum::U12;
|
||||
type TagSize = aead::generic_array::typenum::U16;
|
||||
type CiphertextOverhead = aead::generic_array::typenum::U0;
|
||||
}
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
impl aead::KeyInit for ChaCha20Poly1305Aead {
|
||||
fn new(key: &aead::Key<Self>) -> Self {
|
||||
let mut k = [0u8; 32];
|
||||
k.copy_from_slice(key.as_ref());
|
||||
ChaCha20Poly1305Aead { key: k }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
impl aead::AeadInPlace for ChaCha20Poly1305Aead {
|
||||
fn encrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &aead::Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<aead::Tag<Self>, aead::Error> {
|
||||
let mut tag = aead::Tag::<Self>::default();
|
||||
// wc_ChaCha20Poly1305_Encrypt supports in-place (out == in).
|
||||
let buf_ptr = buffer.as_mut_ptr();
|
||||
let in_ptr = buf_ptr as *const u8;
|
||||
let nonce_bytes: &[u8] = nonce;
|
||||
let tag_bytes: &mut [u8] = &mut tag;
|
||||
let rc = unsafe {
|
||||
sys::wc_ChaCha20Poly1305_Encrypt(
|
||||
self.key.as_ptr(), nonce_bytes.as_ptr(),
|
||||
associated_data.as_ptr(), associated_data.len() as u32,
|
||||
in_ptr, buffer.len() as u32,
|
||||
buf_ptr, tag_bytes.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(aead::Error);
|
||||
}
|
||||
Ok(tag)
|
||||
}
|
||||
|
||||
fn decrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &aead::Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &aead::Tag<Self>,
|
||||
) -> Result<(), aead::Error> {
|
||||
let buf_ptr = buffer.as_mut_ptr();
|
||||
let in_ptr = buf_ptr as *const u8;
|
||||
let nonce_bytes: &[u8] = nonce;
|
||||
let tag_bytes: &[u8] = tag;
|
||||
let rc = unsafe {
|
||||
sys::wc_ChaCha20Poly1305_Decrypt(
|
||||
self.key.as_ptr(), nonce_bytes.as_ptr(),
|
||||
associated_data.as_ptr(), associated_data.len() as u32,
|
||||
in_ptr, buffer.len() as u32,
|
||||
tag_bytes.as_ptr(), buf_ptr,
|
||||
)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(aead::Error);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(xchacha20_poly1305)]
|
||||
pub struct XChaCha20Poly1305;
|
||||
|
||||
#[cfg(xchacha20_poly1305)]
|
||||
impl XChaCha20Poly1305 {
|
||||
/// Key size for XChaCha20-Poly1305 stream cipher.
|
||||
@@ -340,3 +424,111 @@ impl XChaCha20Poly1305 {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// XChaCha20-Poly1305 aead trait implementations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// XChaCha20-Poly1305 AEAD instance holding a key for use with the
|
||||
/// `aead::KeyInit` and `aead::AeadInPlace` traits.
|
||||
#[cfg(all(xchacha20_poly1305, feature = "aead"))]
|
||||
pub struct XChaCha20Poly1305Aead {
|
||||
key: [u8; 32],
|
||||
}
|
||||
|
||||
#[cfg(all(xchacha20_poly1305, feature = "aead"))]
|
||||
impl aead::KeySizeUser for XChaCha20Poly1305Aead {
|
||||
type KeySize = aead::generic_array::typenum::U32;
|
||||
}
|
||||
|
||||
#[cfg(all(xchacha20_poly1305, feature = "aead"))]
|
||||
impl aead::AeadCore for XChaCha20Poly1305Aead {
|
||||
type NonceSize = aead::generic_array::typenum::U24;
|
||||
type TagSize = aead::generic_array::typenum::U16;
|
||||
type CiphertextOverhead = aead::generic_array::typenum::U0;
|
||||
}
|
||||
|
||||
#[cfg(all(xchacha20_poly1305, feature = "aead"))]
|
||||
impl aead::KeyInit for XChaCha20Poly1305Aead {
|
||||
fn new(key: &aead::Key<Self>) -> Self {
|
||||
let mut k = [0u8; 32];
|
||||
k.copy_from_slice(key.as_ref());
|
||||
XChaCha20Poly1305Aead { key: k }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(xchacha20_poly1305, feature = "aead"))]
|
||||
impl aead::AeadInPlace for XChaCha20Poly1305Aead {
|
||||
// This function can encrypt a maximum of 4096 bytes.
|
||||
fn encrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &aead::Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<aead::Tag<Self>, aead::Error> {
|
||||
// wc_XChaCha20Poly1305_Encrypt writes ciphertext + 16-byte tag into a
|
||||
// single output buffer. Use a stack buffer to hold both, then split
|
||||
// the tag out and copy the ciphertext back over the caller's buffer.
|
||||
const MAX_INLINE: usize = 4096;
|
||||
debug_assert!(buffer.len() <= MAX_INLINE, "Maximum of 4096 bytes supported");
|
||||
if buffer.len() > MAX_INLINE {
|
||||
return Err(aead::Error);
|
||||
}
|
||||
let out_len = buffer.len() + 16;
|
||||
let mut out_buf = [0u8; MAX_INLINE + 16];
|
||||
let nonce_bytes: &[u8] = nonce;
|
||||
let rc = unsafe {
|
||||
sys::wc_XChaCha20Poly1305_Encrypt(
|
||||
out_buf.as_mut_ptr(), out_len,
|
||||
buffer.as_ptr(), buffer.len(),
|
||||
associated_data.as_ptr(), associated_data.len(),
|
||||
nonce_bytes.as_ptr(), nonce_bytes.len(),
|
||||
self.key.as_ptr(), self.key.len(),
|
||||
)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(aead::Error);
|
||||
}
|
||||
buffer.copy_from_slice(&out_buf[..buffer.len()]);
|
||||
let mut tag = aead::Tag::<Self>::default();
|
||||
let tag_bytes: &mut [u8] = &mut tag;
|
||||
tag_bytes.copy_from_slice(&out_buf[buffer.len()..out_len]);
|
||||
Ok(tag)
|
||||
}
|
||||
|
||||
// This function can decrypt a maximum of 4096 bytes.
|
||||
fn decrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &aead::Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &aead::Tag<Self>,
|
||||
) -> Result<(), aead::Error> {
|
||||
// wc_XChaCha20Poly1305_Decrypt expects the auth tag appended after the
|
||||
// ciphertext. Build a combined [ciphertext | tag] buffer on the stack.
|
||||
const MAX_INLINE: usize = 4096;
|
||||
debug_assert!(buffer.len() <= MAX_INLINE, "Maximum of 4096 bytes supported");
|
||||
if buffer.len() > MAX_INLINE {
|
||||
return Err(aead::Error);
|
||||
}
|
||||
let mut in_buf = [0u8; MAX_INLINE + 16];
|
||||
let in_len = buffer.len() + 16;
|
||||
in_buf[..buffer.len()].copy_from_slice(buffer);
|
||||
let tag_bytes: &[u8] = tag;
|
||||
in_buf[buffer.len()..in_len].copy_from_slice(tag_bytes);
|
||||
let nonce_bytes: &[u8] = nonce;
|
||||
let rc = unsafe {
|
||||
sys::wc_XChaCha20Poly1305_Decrypt(
|
||||
buffer.as_mut_ptr(), buffer.len(),
|
||||
in_buf.as_ptr(), in_len,
|
||||
associated_data.as_ptr(), associated_data.len(),
|
||||
nonce_bytes.as_ptr(), nonce_bytes.len(),
|
||||
self.key.as_ptr(), self.key.len(),
|
||||
)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(aead::Error);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,6 +380,34 @@ impl RNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement `rand_core::TryRng` for `RNG`, allowing it to be used anywhere
|
||||
/// a standard Rust RNG is expected.
|
||||
///
|
||||
/// `Error` is set to `Infallible` so that the blanket impls for `Rng` and
|
||||
/// `CryptoRng` apply automatically. wolfSSL RNG failures cause a panic, which
|
||||
/// is consistent with the infallible contract.
|
||||
#[cfg(feature = "rand_core")]
|
||||
impl rand_core::TryRng for RNG {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
rand_core::utils::next_word_via_fill(self)
|
||||
}
|
||||
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
rand_core::utils::next_word_via_fill(self)
|
||||
}
|
||||
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.generate_block(dest).expect("RNG failure");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark `RNG` as a cryptographically secure random number generator.
|
||||
#[cfg(feature = "rand_core")]
|
||||
impl rand_core::TryCryptoRng for RNG {}
|
||||
|
||||
impl Drop for RNG {
|
||||
/// Safely free the underlying wolfSSL RNG context.
|
||||
///
|
||||
|
||||
@@ -863,3 +863,563 @@ fn test_xtsstream_big_msg() {
|
||||
|
||||
assert_eq!(plain_out, BIG_MSG);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AES aead trait implementations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
use aead::{Aead, AeadInPlace, KeyInit, Payload};
|
||||
|
||||
/// NIST SP 800-38D, Test Case 2:
|
||||
/// Key = 00000000000000000000000000000000
|
||||
/// IV = 000000000000000000000000
|
||||
/// PT = 00000000000000000000000000000000
|
||||
/// AAD = (empty)
|
||||
/// CT = 0388dace60b6a392f328c2b971b2fe78
|
||||
/// Tag = ab6e47d42cec13bdf53a67b21257bddf
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_gcm))]
|
||||
fn test_aes128gcm_nist_tc2_encrypt() {
|
||||
let key = [0u8; 16];
|
||||
let nonce = [0u8; 12];
|
||||
let expected_ciphertext = [
|
||||
0x03u8, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
|
||||
0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78,
|
||||
];
|
||||
let expected_tag = [
|
||||
0xabu8, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
|
||||
0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf,
|
||||
];
|
||||
|
||||
let cipher = Aes128Gcm::new_from_slice(&key).unwrap();
|
||||
let nonce_arr: aead::Nonce<Aes128Gcm> = nonce.into();
|
||||
let mut buffer = [0u8; 16];
|
||||
let tag = cipher
|
||||
.encrypt_in_place_detached(&nonce_arr, &[], &mut buffer)
|
||||
.expect("AES-128-GCM encrypt failed");
|
||||
|
||||
assert_eq!(buffer, expected_ciphertext);
|
||||
assert_eq!(&tag[..], &expected_tag);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_gcm))]
|
||||
fn test_aes128gcm_nist_tc2_decrypt() {
|
||||
let key = [0u8; 16];
|
||||
let nonce = [0u8; 12];
|
||||
let mut ciphertext = [
|
||||
0x03u8, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
|
||||
0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78,
|
||||
];
|
||||
let tag_bytes = [
|
||||
0xabu8, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
|
||||
0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf,
|
||||
];
|
||||
|
||||
let cipher = Aes128Gcm::new_from_slice(&key).unwrap();
|
||||
let nonce_arr: aead::Nonce<Aes128Gcm> = nonce.into();
|
||||
let tag: aead::Tag<Aes128Gcm> = tag_bytes.into();
|
||||
cipher
|
||||
.decrypt_in_place_detached(&nonce_arr, &[], &mut ciphertext, &tag)
|
||||
.expect("AES-128-GCM decrypt failed");
|
||||
|
||||
assert_eq!(ciphertext, [0u8; 16]);
|
||||
}
|
||||
|
||||
/// Test AES-128-GCM roundtrip using the `aead::Aead` blanket impl.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_gcm))]
|
||||
fn test_aes128gcm_aead_roundtrip() {
|
||||
let key = [0x42u8; 16];
|
||||
let nonce_bytes = [0x11u8; 12];
|
||||
let aad = b"associated data";
|
||||
let plaintext = b"Hello, AEAD world!";
|
||||
|
||||
let cipher = Aes128Gcm::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<Aes128Gcm> = nonce_bytes.into();
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(&nonce, Payload { msg: plaintext, aad })
|
||||
.expect("AES-128-GCM Aead::encrypt failed");
|
||||
|
||||
let recovered = cipher
|
||||
.decrypt(&nonce, Payload { msg: &ciphertext, aad })
|
||||
.expect("AES-128-GCM Aead::decrypt failed");
|
||||
|
||||
assert_eq!(recovered, plaintext);
|
||||
}
|
||||
|
||||
/// Verify that decryption rejects a tampered tag.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_gcm))]
|
||||
fn test_aes128gcm_reject_bad_tag() {
|
||||
let key = [0u8; 16];
|
||||
let nonce_bytes = [0u8; 12];
|
||||
let plaintext = b"some plaintext!";
|
||||
|
||||
let cipher = Aes128Gcm::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<Aes128Gcm> = nonce_bytes.into();
|
||||
|
||||
let mut ct = cipher.encrypt(&nonce, plaintext.as_ref()).expect("encrypt failed");
|
||||
let last = ct.len() - 1;
|
||||
ct[last] ^= 0xff;
|
||||
assert!(cipher.decrypt(&nonce, ct.as_slice()).is_err());
|
||||
}
|
||||
|
||||
/// NIST SP 800-38D, Test Case 14 (256-bit key):
|
||||
/// Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
|
||||
/// IV = cafebabefacedbaddecaf888
|
||||
/// PT = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a7
|
||||
/// 21c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 (60 B)
|
||||
/// AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
|
||||
/// CT = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1a
|
||||
/// a8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0a (60 B)
|
||||
/// Tag = 76fc6ece0f4e1768cddf8853bb2d551b
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_gcm))]
|
||||
fn test_aes256gcm_nist_tc14_encrypt() {
|
||||
let key = [
|
||||
0xfeu8, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
|
||||
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
|
||||
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
|
||||
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
|
||||
];
|
||||
let nonce = [
|
||||
0xcau8, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
|
||||
0xde, 0xca, 0xf8, 0x88,
|
||||
];
|
||||
let aad = [
|
||||
0xfeu8, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
|
||||
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
|
||||
0xab, 0xad, 0xda, 0xd2,
|
||||
];
|
||||
let plaintext = [
|
||||
0xd9u8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
|
||||
0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
|
||||
0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
|
||||
0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
|
||||
0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
|
||||
0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
|
||||
0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
|
||||
0xba, 0x63, 0x7b, 0x39,
|
||||
];
|
||||
let expected_ciphertext = [
|
||||
0x52u8, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
|
||||
0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
|
||||
0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
|
||||
0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
|
||||
0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
|
||||
0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
|
||||
0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
|
||||
0xbc, 0xc9, 0xf6, 0x62,
|
||||
];
|
||||
let expected_tag = [
|
||||
0x76u8, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
|
||||
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b,
|
||||
];
|
||||
|
||||
let cipher = Aes256Gcm::new_from_slice(&key).unwrap();
|
||||
let nonce_arr: aead::Nonce<Aes256Gcm> = nonce.into();
|
||||
let mut buffer = plaintext;
|
||||
let tag = cipher
|
||||
.encrypt_in_place_detached(&nonce_arr, &aad, &mut buffer)
|
||||
.expect("AES-256-GCM encrypt failed");
|
||||
|
||||
assert_eq!(buffer, expected_ciphertext);
|
||||
assert_eq!(&tag[..], &expected_tag);
|
||||
}
|
||||
|
||||
/// Roundtrip test for AES-256-GCM using `aead::Aead`.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_gcm))]
|
||||
fn test_aes256gcm_aead_roundtrip() {
|
||||
let key = [0xabu8; 32];
|
||||
let nonce_bytes = [0xbcu8; 12];
|
||||
let aad = b"test aad";
|
||||
let plaintext = b"AES-256-GCM roundtrip test";
|
||||
|
||||
let cipher = Aes256Gcm::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<Aes256Gcm> = nonce_bytes.into();
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(&nonce, Payload { msg: plaintext, aad })
|
||||
.expect("encrypt failed");
|
||||
|
||||
let recovered = cipher
|
||||
.decrypt(&nonce, Payload { msg: &ciphertext, aad })
|
||||
.expect("decrypt failed");
|
||||
|
||||
assert_eq!(recovered, plaintext);
|
||||
}
|
||||
|
||||
/// Roundtrip test for AES-128-CCM using `aead::Aead`.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_ccm))]
|
||||
fn test_aes128ccm_aead_roundtrip() {
|
||||
let key = [0x01u8; 16];
|
||||
let nonce_bytes = [0x02u8; 12];
|
||||
let aad = b"ccm aad";
|
||||
let plaintext = b"AES-128-CCM plaintext!";
|
||||
|
||||
let cipher = Aes128Ccm::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<Aes128Ccm> = nonce_bytes.into();
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(&nonce, Payload { msg: plaintext, aad })
|
||||
.expect("AES-128-CCM encrypt failed");
|
||||
|
||||
let recovered = cipher
|
||||
.decrypt(&nonce, Payload { msg: &ciphertext, aad })
|
||||
.expect("AES-128-CCM decrypt failed");
|
||||
|
||||
assert_eq!(recovered, plaintext);
|
||||
}
|
||||
|
||||
/// Verify that AES-128-CCM decryption rejects a tampered ciphertext.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_ccm))]
|
||||
fn test_aes128ccm_reject_tampered() {
|
||||
let key = [0x01u8; 16];
|
||||
let nonce_bytes = [0x02u8; 12];
|
||||
let plaintext = b"AES-128-CCM tamper test!";
|
||||
|
||||
let cipher = Aes128Ccm::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<Aes128Ccm> = nonce_bytes.into();
|
||||
|
||||
let mut ct = cipher.encrypt(&nonce, plaintext.as_ref()).expect("encrypt failed");
|
||||
ct[0] ^= 0x01;
|
||||
assert!(cipher.decrypt(&nonce, ct.as_slice()).is_err());
|
||||
}
|
||||
|
||||
/// Roundtrip test for AES-256-CCM using `aead::Aead`.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", aes_ccm))]
|
||||
fn test_aes256ccm_aead_roundtrip() {
|
||||
let key = [0xddu8; 32];
|
||||
let nonce_bytes = [0xeeu8; 12];
|
||||
let aad = b"aes-256-ccm test";
|
||||
let plaintext = b"AES-256-CCM plaintext data";
|
||||
|
||||
let cipher = Aes256Ccm::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<Aes256Ccm> = nonce_bytes.into();
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(&nonce, Payload { msg: plaintext, aad })
|
||||
.expect("AES-256-CCM encrypt failed");
|
||||
|
||||
let recovered = cipher
|
||||
.decrypt(&nonce, Payload { msg: &ciphertext, aad })
|
||||
.expect("AES-256-CCM decrypt failed");
|
||||
|
||||
assert_eq!(recovered, plaintext);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AES cipher crate trait tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Test AES-128-ECB encryption against the known test vector used in the
|
||||
/// existing `test_ecb_encrypt_decrypt` test.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ecb))]
|
||||
fn test_aes128_ecb_enc_block_encrypt() {
|
||||
use cipher::{BlockModeEncrypt, KeyInit};
|
||||
use wolfssl_wolfcrypt::aes::Aes128EcbEnc;
|
||||
|
||||
let key: [u8; 16] = *b"0123456789abcdef";
|
||||
let plaintext: [u8; 16] = [
|
||||
0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
|
||||
];
|
||||
let expected: [u8; 16] = [
|
||||
0xd0, 0xc9, 0xd9, 0xc9, 0x40, 0xe8, 0x97, 0xb6,
|
||||
0xc8, 0x8c, 0x33, 0x3b, 0xb5, 0x8f, 0x85, 0xd1,
|
||||
];
|
||||
|
||||
let mut enc = Aes128EcbEnc::new_from_slice(&key).expect("key init failed");
|
||||
let mut block = cipher::Block::<Aes128EcbEnc>::try_from(&plaintext[..]).unwrap();
|
||||
enc.encrypt_block(&mut block);
|
||||
assert_eq!(block.as_slice(), &expected);
|
||||
}
|
||||
|
||||
/// Test AES-128-ECB decryption matches the plaintext after encryption.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ecb))]
|
||||
fn test_aes128_ecb_dec_block_decrypt() {
|
||||
use cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyInit};
|
||||
use wolfssl_wolfcrypt::aes::{Aes128EcbDec, Aes128EcbEnc};
|
||||
|
||||
let key: [u8; 16] = *b"0123456789abcdef";
|
||||
let plaintext: [u8; 16] = [
|
||||
0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
|
||||
];
|
||||
|
||||
let mut enc = Aes128EcbEnc::new_from_slice(&key).expect("enc init failed");
|
||||
let mut dec = Aes128EcbDec::new_from_slice(&key).expect("dec init failed");
|
||||
|
||||
let mut block = cipher::Block::<Aes128EcbEnc>::try_from(&plaintext[..]).unwrap();
|
||||
enc.encrypt_block(&mut block);
|
||||
|
||||
let mut block2 = cipher::Block::<Aes128EcbDec>::try_from(block.as_slice()).unwrap();
|
||||
dec.decrypt_block(&mut block2);
|
||||
|
||||
assert_eq!(block2.as_slice(), &plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-256-ECB encryption and decryption roundtrip.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ecb))]
|
||||
fn test_aes256_ecb_roundtrip() {
|
||||
use cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyInit};
|
||||
use wolfssl_wolfcrypt::aes::{Aes256EcbDec, Aes256EcbEnc};
|
||||
|
||||
let key = [0xabu8; 32];
|
||||
let plaintext = [0x5cu8; 16];
|
||||
|
||||
let mut enc = Aes256EcbEnc::new_from_slice(&key).expect("enc init failed");
|
||||
let mut dec = Aes256EcbDec::new_from_slice(&key).expect("dec init failed");
|
||||
|
||||
let mut block = cipher::Block::<Aes256EcbEnc>::try_from(&plaintext[..]).unwrap();
|
||||
enc.encrypt_block(&mut block);
|
||||
assert_ne!(block.as_slice(), &plaintext, "encrypted block should differ from plaintext");
|
||||
|
||||
let mut block2 = cipher::Block::<Aes256EcbDec>::try_from(block.as_slice()).unwrap();
|
||||
dec.decrypt_block(&mut block2);
|
||||
assert_eq!(block2.as_slice(), &plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-128-CTR `apply_keystream` against the NIST CTR test vector.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ctr))]
|
||||
fn test_aes128_ctr_apply_keystream() {
|
||||
use cipher::{KeyIvInit, StreamCipher};
|
||||
use wolfssl_wolfcrypt::aes::Aes128Ctr;
|
||||
|
||||
let key: [u8; 16] = [
|
||||
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
|
||||
];
|
||||
let iv: [u8; 16] = [
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
];
|
||||
let plaintext: [u8; 64] = [
|
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
|
||||
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
|
||||
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
|
||||
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
|
||||
];
|
||||
let expected_ciphertext: [u8; 64] = [
|
||||
0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
|
||||
0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
|
||||
0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
|
||||
0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
|
||||
0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
|
||||
0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
|
||||
0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
|
||||
0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
|
||||
];
|
||||
|
||||
let key_arr = cipher::Key::<Aes128Ctr>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes128Ctr>::try_from(&iv[..]).unwrap();
|
||||
let mut enc = Aes128Ctr::new(&key_arr, &iv_arr);
|
||||
let mut data = plaintext;
|
||||
enc.apply_keystream(&mut data);
|
||||
assert_eq!(data, expected_ciphertext);
|
||||
|
||||
// apply_keystream is self-inverse: applying again must recover plaintext.
|
||||
let mut dec = Aes128Ctr::new(&key_arr, &iv_arr);
|
||||
dec.apply_keystream(&mut data);
|
||||
assert_eq!(data, plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-256-CTR roundtrip via `apply_keystream`.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ctr))]
|
||||
fn test_aes256_ctr_roundtrip() {
|
||||
use cipher::{KeyIvInit, StreamCipher};
|
||||
use wolfssl_wolfcrypt::aes::Aes256Ctr;
|
||||
|
||||
let key = [0x01u8; 32];
|
||||
let iv = [0x02u8; 16];
|
||||
let plaintext = [0x55u8; 48];
|
||||
|
||||
let key_arr = cipher::Key::<Aes256Ctr>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes256Ctr>::try_from(&iv[..]).unwrap();
|
||||
|
||||
let mut enc = Aes256Ctr::new(&key_arr, &iv_arr);
|
||||
let mut data = plaintext;
|
||||
enc.apply_keystream(&mut data);
|
||||
assert_ne!(data, plaintext);
|
||||
|
||||
let mut dec = Aes256Ctr::new(&key_arr, &iv_arr);
|
||||
dec.apply_keystream(&mut data);
|
||||
assert_eq!(data, plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-256-OFB `apply_keystream` against the known OFB test vector.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ofb))]
|
||||
fn test_aes256_ofb_apply_keystream() {
|
||||
use cipher::{KeyIvInit, StreamCipher};
|
||||
use wolfssl_wolfcrypt::aes::Aes256Ofb;
|
||||
|
||||
let key: [u8; 32] = [
|
||||
0xc4, 0xc7, 0xfa, 0xd6, 0x53, 0x5c, 0xb8, 0x71,
|
||||
0x4a, 0x5c, 0x40, 0x77, 0x9a, 0x8b, 0xa1, 0xd2,
|
||||
0x53, 0x3e, 0x23, 0xb4, 0xb2, 0x58, 0x73, 0x2a,
|
||||
0x5b, 0x78, 0x01, 0xf4, 0xe3, 0x71, 0xa7, 0x94,
|
||||
];
|
||||
let iv: [u8; 16] = [
|
||||
0x5e, 0xb9, 0x33, 0x13, 0xb8, 0x71, 0xff, 0x16,
|
||||
0xb9, 0x8a, 0x9b, 0xcb, 0x43, 0x33, 0x0d, 0x6f,
|
||||
];
|
||||
let plaintext: [u8; 48] = [
|
||||
0x6d, 0x0b, 0xb0, 0x79, 0x63, 0x84, 0x71, 0xe9,
|
||||
0x39, 0xd4, 0x53, 0x14, 0x86, 0xc1, 0x4c, 0x25,
|
||||
0x9a, 0xee, 0xc6, 0xf3, 0xc0, 0x0d, 0xfd, 0xd6,
|
||||
0xc0, 0x50, 0xa8, 0xba, 0xa8, 0x20, 0xdb, 0x71,
|
||||
0xcc, 0x12, 0x2c, 0x4e, 0x0c, 0x17, 0x15, 0xef,
|
||||
0x55, 0xf3, 0x99, 0x5a, 0x6b, 0xf0, 0x2a, 0x4c,
|
||||
];
|
||||
let expected_ciphertext: [u8; 48] = [
|
||||
0x0f, 0x54, 0x61, 0x71, 0x59, 0xd0, 0x3f, 0xfc,
|
||||
0x1b, 0xfa, 0xfb, 0x60, 0x29, 0x30, 0xd7, 0x00,
|
||||
0xf4, 0xa4, 0xa8, 0xe6, 0xdd, 0x93, 0x94, 0x46,
|
||||
0x64, 0xd2, 0x19, 0xc4, 0xc5, 0x4d, 0xde, 0x1b,
|
||||
0x04, 0x53, 0xe1, 0x73, 0xf5, 0x18, 0x74, 0xae,
|
||||
0xfd, 0x64, 0xa2, 0xe1, 0xe2, 0x76, 0x13, 0xb0,
|
||||
];
|
||||
|
||||
let key_arr = cipher::Key::<Aes256Ofb>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes256Ofb>::try_from(&iv[..]).unwrap();
|
||||
let mut enc = Aes256Ofb::new(&key_arr, &iv_arr);
|
||||
let mut data = plaintext;
|
||||
enc.apply_keystream(&mut data);
|
||||
assert_eq!(data, expected_ciphertext);
|
||||
|
||||
// apply_keystream is self-inverse for OFB (same keystream for enc/dec).
|
||||
let mut dec = Aes256Ofb::new(&key_arr, &iv_arr);
|
||||
dec.apply_keystream(&mut data);
|
||||
assert_eq!(data, plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-128-OFB roundtrip via `apply_keystream`.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_ofb))]
|
||||
fn test_aes128_ofb_roundtrip() {
|
||||
use cipher::{KeyIvInit, StreamCipher};
|
||||
use wolfssl_wolfcrypt::aes::Aes128Ofb;
|
||||
|
||||
let key = [0xddu8; 16];
|
||||
let iv = [0xeeu8; 16];
|
||||
let plaintext = [0x42u8; 32];
|
||||
|
||||
let key_arr = cipher::Key::<Aes128Ofb>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes128Ofb>::try_from(&iv[..]).unwrap();
|
||||
|
||||
let mut enc = Aes128Ofb::new(&key_arr, &iv_arr);
|
||||
let mut data = plaintext;
|
||||
enc.apply_keystream(&mut data);
|
||||
assert_ne!(data, plaintext);
|
||||
|
||||
let mut dec = Aes128Ofb::new(&key_arr, &iv_arr);
|
||||
dec.apply_keystream(&mut data);
|
||||
assert_eq!(data, plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-128-CBC encryption against a known vector (same as test_cbc_encrypt_decrypt).
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_cbc))]
|
||||
fn test_aes128_cbc_enc_block_mode() {
|
||||
use cipher::{BlockModeEncrypt, KeyIvInit};
|
||||
use wolfssl_wolfcrypt::aes::Aes128CbcEnc;
|
||||
|
||||
let key: [u8; 16] = *b"0123456789abcdef";
|
||||
let iv: [u8; 16] = *b"1234567890abcdef";
|
||||
let plaintext: [u8; 16] = [
|
||||
0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
|
||||
];
|
||||
let expected: [u8; 16] = [
|
||||
0x95, 0x94, 0x92, 0x57, 0x5f, 0x42, 0x81, 0x53,
|
||||
0x2c, 0xcc, 0x9d, 0x46, 0x77, 0xa2, 0x33, 0xcb,
|
||||
];
|
||||
|
||||
let key_arr = cipher::Key::<Aes128CbcEnc>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes128CbcEnc>::try_from(&iv[..]).unwrap();
|
||||
let mut enc = Aes128CbcEnc::new(&key_arr, &iv_arr);
|
||||
let mut block = cipher::Block::<Aes128CbcEnc>::try_from(&plaintext[..]).unwrap();
|
||||
enc.encrypt_block(&mut block);
|
||||
assert_eq!(block.as_slice(), &expected);
|
||||
}
|
||||
|
||||
/// Test AES-128-CBC decryption roundtrip.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_cbc))]
|
||||
fn test_aes128_cbc_dec_block_mode() {
|
||||
use cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit};
|
||||
use wolfssl_wolfcrypt::aes::{Aes128CbcDec, Aes128CbcEnc};
|
||||
|
||||
let key: [u8; 16] = *b"0123456789abcdef";
|
||||
let iv: [u8; 16] = *b"1234567890abcdef";
|
||||
let plaintext: [u8; 16] = [
|
||||
0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
|
||||
];
|
||||
|
||||
let key_arr = cipher::Key::<Aes128CbcEnc>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes128CbcEnc>::try_from(&iv[..]).unwrap();
|
||||
let mut enc = Aes128CbcEnc::new(&key_arr, &iv_arr);
|
||||
let mut block = cipher::Block::<Aes128CbcEnc>::try_from(&plaintext[..]).unwrap();
|
||||
enc.encrypt_block(&mut block);
|
||||
|
||||
let key_arr = cipher::Key::<Aes128CbcDec>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes128CbcDec>::try_from(&iv[..]).unwrap();
|
||||
let mut dec = Aes128CbcDec::new(&key_arr, &iv_arr);
|
||||
dec.decrypt_block(&mut block);
|
||||
assert_eq!(block.as_slice(), &plaintext);
|
||||
}
|
||||
|
||||
/// Test AES-256-CBC encryption/decryption roundtrip across multiple blocks.
|
||||
#[test]
|
||||
#[cfg(all(feature = "cipher", aes_cbc))]
|
||||
fn test_aes256_cbc_roundtrip() {
|
||||
use cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit};
|
||||
use wolfssl_wolfcrypt::aes::{Aes256CbcDec, Aes256CbcEnc};
|
||||
|
||||
let key = [0xabu8; 32];
|
||||
let iv = [0xcdu8; 16];
|
||||
let plaintext = [[0x5cu8; 16], [0x3au8; 16], [0x1eu8; 16]];
|
||||
|
||||
let key_arr = cipher::Key::<Aes256CbcEnc>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes256CbcEnc>::try_from(&iv[..]).unwrap();
|
||||
let mut enc = Aes256CbcEnc::new(&key_arr, &iv_arr);
|
||||
let mut blocks: [cipher::Block<Aes256CbcEnc>; 3] = plaintext
|
||||
.iter()
|
||||
.map(|b| cipher::Block::<Aes256CbcEnc>::try_from(b.as_ref()).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
for block in blocks.iter_mut() {
|
||||
enc.encrypt_block(block);
|
||||
}
|
||||
// Ciphertext must differ from plaintext due to key and IV mixing.
|
||||
assert!(blocks.iter().zip(plaintext.iter()).any(|(c, p)| c.as_slice() != p));
|
||||
|
||||
let key_arr = cipher::Key::<Aes256CbcDec>::try_from(&key[..]).unwrap();
|
||||
let iv_arr = cipher::Iv::<Aes256CbcDec>::try_from(&iv[..]).unwrap();
|
||||
let mut dec = Aes256CbcDec::new(&key_arr, &iv_arr);
|
||||
for block in blocks.iter_mut() {
|
||||
dec.decrypt_block(block);
|
||||
}
|
||||
for (block, expected) in blocks.iter().zip(plaintext.iter()) {
|
||||
assert_eq!(block.as_slice(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,3 +273,229 @@ fn test_xchacha20_poly1305() {
|
||||
XChaCha20Poly1305::decrypt(&key, &iv, &aad, &ciphertext_buffer, &mut plaintext_buffer).expect("Error with decrypt()");
|
||||
assert_eq!(plaintext_buffer, PLAINTEXT);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ChaCha20-Poly1305 aead trait implementations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
use aead::{Aead, AeadInPlace, KeyInit, Payload};
|
||||
|
||||
/// RFC 8439, Section 2.8.2 test vector.
|
||||
///
|
||||
/// Key = 808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
|
||||
/// IV = 070000004041424344454647
|
||||
/// AAD = 50515253c0c1c2c3c4c5c6c7
|
||||
/// PT = 4c61646965732061...
|
||||
/// Tag = 1ae10b594f09e26a7e902ecbd0600691
|
||||
#[test]
|
||||
#[cfg(feature = "aead")]
|
||||
fn test_chacha20poly1305_rfc8439_encrypt() {
|
||||
let key = [
|
||||
0x80u8, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
];
|
||||
let nonce = [
|
||||
0x07u8, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
|
||||
0x44, 0x45, 0x46, 0x47,
|
||||
];
|
||||
let aad = [
|
||||
0x50u8, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
|
||||
0xc4, 0xc5, 0xc6, 0xc7,
|
||||
];
|
||||
let mut plaintext = [
|
||||
0x4cu8, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
|
||||
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
|
||||
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
|
||||
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
|
||||
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
|
||||
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
|
||||
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
|
||||
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
|
||||
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
|
||||
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
|
||||
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
|
||||
0x74, 0x2e,
|
||||
];
|
||||
let expected_ciphertext = [
|
||||
0xd3u8, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
|
||||
0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
|
||||
0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
|
||||
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
|
||||
0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
|
||||
0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
|
||||
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
|
||||
0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
|
||||
0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
|
||||
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
|
||||
0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
|
||||
0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
|
||||
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
|
||||
0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
|
||||
0x61, 0x16,
|
||||
];
|
||||
let expected_tag = [
|
||||
0x1au8, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
|
||||
0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91,
|
||||
];
|
||||
|
||||
let cipher = ChaCha20Poly1305Aead::new_from_slice(&key).unwrap();
|
||||
let nonce_arr: aead::Nonce<ChaCha20Poly1305Aead> = nonce.into();
|
||||
let tag = cipher
|
||||
.encrypt_in_place_detached(&nonce_arr, &aad, &mut plaintext)
|
||||
.expect("ChaCha20-Poly1305 encrypt failed");
|
||||
|
||||
assert_eq!(plaintext, expected_ciphertext);
|
||||
assert_eq!(&tag[..], &expected_tag);
|
||||
}
|
||||
|
||||
/// Roundtrip test for ChaCha20-Poly1305 using `aead::Aead`.
|
||||
#[test]
|
||||
#[cfg(feature = "aead")]
|
||||
fn test_chacha20poly1305_aead_roundtrip() {
|
||||
let key = [0x55u8; 32];
|
||||
let nonce_bytes = [0x66u8; 12];
|
||||
let aad = b"chacha20 aad";
|
||||
let plaintext = b"ChaCha20-Poly1305 roundtrip";
|
||||
|
||||
let cipher = ChaCha20Poly1305Aead::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<ChaCha20Poly1305Aead> = nonce_bytes.into();
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(&nonce, Payload { msg: plaintext, aad })
|
||||
.expect("encrypt failed");
|
||||
|
||||
let recovered = cipher
|
||||
.decrypt(&nonce, Payload { msg: &ciphertext, aad })
|
||||
.expect("decrypt failed");
|
||||
|
||||
assert_eq!(recovered, plaintext);
|
||||
}
|
||||
|
||||
/// Verify that ChaCha20-Poly1305 rejects a tampered message.
|
||||
#[test]
|
||||
#[cfg(feature = "aead")]
|
||||
fn test_chacha20poly1305_reject_tampered() {
|
||||
let key = [0x77u8; 32];
|
||||
let nonce_bytes = [0x88u8; 12];
|
||||
let plaintext = b"tamper me!";
|
||||
|
||||
let cipher = ChaCha20Poly1305Aead::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<ChaCha20Poly1305Aead> = nonce_bytes.into();
|
||||
|
||||
let mut ct = cipher.encrypt(&nonce, plaintext.as_ref()).expect("encrypt failed");
|
||||
ct[0] ^= 0x01;
|
||||
assert!(cipher.decrypt(&nonce, ct.as_slice()).is_err());
|
||||
}
|
||||
|
||||
/// Roundtrip test for XChaCha20-Poly1305 using `aead::Aead`.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", xchacha20_poly1305))]
|
||||
fn test_xchacha20poly1305_aead_roundtrip() {
|
||||
let key = [0xaau8; 32];
|
||||
let nonce_bytes = [0xbbu8; 24];
|
||||
let aad = b"xchacha20 aad";
|
||||
let plaintext = b"XChaCha20-Poly1305 roundtrip";
|
||||
|
||||
let cipher = XChaCha20Poly1305Aead::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<XChaCha20Poly1305Aead> = nonce_bytes.into();
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(&nonce, Payload { msg: plaintext, aad })
|
||||
.expect("XChaCha20-Poly1305 encrypt failed");
|
||||
|
||||
let recovered = cipher
|
||||
.decrypt(&nonce, Payload { msg: &ciphertext, aad })
|
||||
.expect("XChaCha20-Poly1305 decrypt failed");
|
||||
|
||||
assert_eq!(recovered, plaintext);
|
||||
}
|
||||
|
||||
/// RFC 8439-based XChaCha20-Poly1305 known-answer test.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", xchacha20_poly1305))]
|
||||
fn test_xchacha20poly1305_known_answer() {
|
||||
let key = [
|
||||
0x80u8, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
];
|
||||
let nonce = [
|
||||
0x40u8, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
];
|
||||
let aad = [
|
||||
0x50u8, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
|
||||
0xc4, 0xc5, 0xc6, 0xc7,
|
||||
];
|
||||
let mut plaintext = [
|
||||
0x4cu8, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
|
||||
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
|
||||
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
|
||||
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
|
||||
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
|
||||
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
|
||||
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
|
||||
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
|
||||
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
|
||||
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
|
||||
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
|
||||
0x74, 0x2e,
|
||||
];
|
||||
let expected_ciphertext = [
|
||||
0xbdu8, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b,
|
||||
0x95, 0x76, 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39,
|
||||
0x57, 0x2a, 0x17, 0x00, 0x25, 0x2b, 0xfa, 0xcc,
|
||||
0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 0x6c, 0xbb,
|
||||
0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44,
|
||||
0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39,
|
||||
0xae, 0x64, 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16,
|
||||
0xcb, 0x96, 0xb7, 0x2e, 0x12, 0x13, 0xb4, 0x52,
|
||||
0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 0xd9, 0x45,
|
||||
0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e,
|
||||
0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f,
|
||||
0x76, 0xb2, 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9,
|
||||
0x21, 0xf9, 0x66, 0x4c, 0x97, 0x63, 0x7d, 0xa9,
|
||||
0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 0x8b, 0x13,
|
||||
0xb5, 0x2e,
|
||||
];
|
||||
let expected_tag = [
|
||||
0xc0u8, 0x87, 0x59, 0x24, 0xc1, 0xc7, 0x98, 0x79,
|
||||
0x47, 0xde, 0xaf, 0xd8, 0x78, 0x0a, 0xcf, 0x49,
|
||||
];
|
||||
|
||||
let cipher = XChaCha20Poly1305Aead::new_from_slice(&key).unwrap();
|
||||
let nonce_arr: aead::Nonce<XChaCha20Poly1305Aead> = nonce.into();
|
||||
let tag = cipher
|
||||
.encrypt_in_place_detached(&nonce_arr, &aad, &mut plaintext)
|
||||
.expect("XChaCha20-Poly1305 encrypt failed");
|
||||
|
||||
assert_eq!(plaintext, expected_ciphertext);
|
||||
assert_eq!(&tag[..], &expected_tag);
|
||||
}
|
||||
|
||||
/// Verify that XChaCha20-Poly1305 decryption rejects a tampered ciphertext.
|
||||
#[test]
|
||||
#[cfg(all(feature = "aead", xchacha20_poly1305))]
|
||||
fn test_xchacha20poly1305_reject_tampered() {
|
||||
let key = [0x55u8; 32];
|
||||
let nonce_bytes = [0x66u8; 24];
|
||||
let plaintext = b"XChaCha tamper test";
|
||||
|
||||
let cipher = XChaCha20Poly1305Aead::new_from_slice(&key).unwrap();
|
||||
let nonce: aead::Nonce<XChaCha20Poly1305Aead> = nonce_bytes.into();
|
||||
|
||||
let mut ct = cipher.encrypt(&nonce, plaintext.as_ref()).expect("encrypt failed");
|
||||
ct[0] ^= 0x01;
|
||||
assert!(cipher.decrypt(&nonce, ct.as_slice()).is_err());
|
||||
}
|
||||
|
||||
@@ -97,3 +97,53 @@ fn test_rng_reseed() {
|
||||
let seed = [1u8, 2, 3, 4];
|
||||
rng.reseed(&seed).expect("Error with reseed()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rand_core")]
|
||||
fn test_rng_rand_core_fill_bytes() {
|
||||
use rand_core::Rng;
|
||||
let mut rng = RNG::new().expect("Failed to create RNG");
|
||||
let mut buf = [0u8; 32];
|
||||
rng.fill_bytes(&mut buf);
|
||||
assert_ne!(buf, [0u8; 32]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rand_core")]
|
||||
fn test_rng_rand_core_try_fill_bytes() {
|
||||
use rand_core::TryRng;
|
||||
let mut rng = RNG::new().expect("Failed to create RNG");
|
||||
let mut buf = [0u8; 32];
|
||||
rng.try_fill_bytes(&mut buf).expect("Failed to try_fill_bytes");
|
||||
assert_ne!(buf, [0u8; 32]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rand_core")]
|
||||
fn test_rng_rand_core_next_u32() {
|
||||
use rand_core::Rng;
|
||||
let mut rng = RNG::new().expect("Failed to create RNG");
|
||||
// Generate several values and verify they aren't all zero
|
||||
let v: u64 = (0..4).map(|_| rng.next_u32() as u64).sum();
|
||||
assert_ne!(v, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rand_core")]
|
||||
fn test_rng_rand_core_next_u64() {
|
||||
use rand_core::Rng;
|
||||
let mut rng = RNG::new().expect("Failed to create RNG");
|
||||
// Generate two values and verify they aren't all ones
|
||||
let v1 = rng.next_u64();
|
||||
let v2 = rng.next_u64();
|
||||
assert_ne!(v1 & v2, u64::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rand_core")]
|
||||
fn test_rng_is_crypto_rng() {
|
||||
use rand_core::CryptoRng;
|
||||
fn requires_crypto_rng<R: CryptoRng>(_: &R) {}
|
||||
let rng = RNG::new().expect("Failed to create RNG");
|
||||
requires_crypto_rng(&rng);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user