Skip to content

Commit 8c457c2

Browse files
committed
chacha20: remove serde feature
See discussion from: rust-random/rand#1101 Being able to easily serialize the state of a cryptographic RNG is a footgun that risks both duplicating the keystream (which can lead to e.g. nonce reuse) or exposing it.
1 parent f0bb120 commit 8c457c2

3 files changed

Lines changed: 0 additions & 131 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chacha20/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ rand_core-compatible RNGs based on those ciphers.
2222
cfg-if = "1"
2323
cipher = { version = "0.5.0-rc.1", optional = true, features = ["stream-wrapper"] }
2424
rand_core = { version = "0.9", optional = true, default-features = false }
25-
serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] }
2625

2726
# `zeroize` is an explicit dependency because this crate may be used without the `cipher` crate
2827
zeroize = { version = "1.8.1", optional = true, default-features = false }
@@ -35,7 +34,6 @@ cipher = { version = "0.5.0-rc.1", features = ["dev"] }
3534
hex-literal = "1"
3635
proptest = "1"
3736
rand_chacha = "0.9"
38-
serde_json = "1.0" # Only to test serde
3937

4038
[features]
4139
default = ["cipher"]

chacha20/src/rng.rs

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ use rand_core::{
1313
block::{BlockRng, BlockRngCore, CryptoBlockRng},
1414
};
1515

16-
#[cfg(feature = "serde")]
17-
use serde::{Deserialize, Deserializer, Serialize, Serializer};
18-
1916
#[cfg(feature = "zeroize")]
2017
use zeroize::{Zeroize, ZeroizeOnDrop};
2118

@@ -32,7 +29,6 @@ pub(crate) const BLOCK_WORDS: u8 = 16;
3229
/// The seed for ChaCha20. Implements ZeroizeOnDrop when the
3330
/// zeroize feature is enabled.
3431
#[derive(PartialEq, Eq, Default, Clone)]
35-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3632
pub struct Seed([u8; 32]);
3733

3834
impl AsRef<[u8; 32]> for Seed {
@@ -500,25 +496,6 @@ macro_rules! impl_chacha_rng {
500496

501497
impl Eq for $ChaChaXRng {}
502498

503-
#[cfg(feature = "serde")]
504-
impl Serialize for $ChaChaXRng {
505-
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
506-
where
507-
S: Serializer,
508-
{
509-
$abst::$ChaChaXRng::from(self).serialize(s)
510-
}
511-
}
512-
#[cfg(feature = "serde")]
513-
impl<'de> Deserialize<'de> for $ChaChaXRng {
514-
fn deserialize<D>(d: D) -> Result<Self, D::Error>
515-
where
516-
D: Deserializer<'de>,
517-
{
518-
$abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
519-
}
520-
}
521-
522499
impl From<$ChaChaXCore> for $ChaChaXRng {
523500
fn from(core: $ChaChaXCore) -> Self {
524501
$ChaChaXRng {
@@ -528,14 +505,10 @@ macro_rules! impl_chacha_rng {
528505
}
529506

530507
mod $abst {
531-
#[cfg(feature = "serde")]
532-
use serde::{Deserialize, Serialize};
533-
534508
// The abstract state of a ChaCha stream, independent of implementation choices. The
535509
// comparison and serialization of this object is considered a semver-covered part of
536510
// the API.
537511
#[derive(Debug, PartialEq, Eq)]
538-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539512
pub(crate) struct $ChaChaXRng {
540513
seed: crate::rng::Seed,
541514
stream: u64,
@@ -661,58 +634,8 @@ pub(crate) mod tests {
661634
assert_eq!(rng.get_word_pos(), 8888);
662635
}
663636

664-
#[cfg(feature = "serde")]
665-
use super::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
666-
667637
type ChaChaRng = ChaCha20Rng;
668638

669-
#[cfg(feature = "serde")]
670-
#[test]
671-
fn test_chacha_serde_roundtrip() {
672-
let seed = [
673-
1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0,
674-
0, 0, 0, 2, 92,
675-
];
676-
let mut rng1 = ChaCha20Rng::from_seed(seed);
677-
let mut rng2 = ChaCha12Rng::from_seed(seed);
678-
let mut rng3 = ChaCha8Rng::from_seed(seed);
679-
680-
let encoded1 = serde_json::to_string(&rng1).unwrap();
681-
let encoded2 = serde_json::to_string(&rng2).unwrap();
682-
let encoded3 = serde_json::to_string(&rng3).unwrap();
683-
684-
let mut decoded1: ChaCha20Rng = serde_json::from_str(&encoded1).unwrap();
685-
let mut decoded2: ChaCha12Rng = serde_json::from_str(&encoded2).unwrap();
686-
let mut decoded3: ChaCha8Rng = serde_json::from_str(&encoded3).unwrap();
687-
688-
assert_eq!(rng1, decoded1);
689-
assert_eq!(rng2, decoded2);
690-
assert_eq!(rng3, decoded3);
691-
692-
assert_eq!(rng1.next_u32(), decoded1.next_u32());
693-
assert_eq!(rng2.next_u32(), decoded2.next_u32());
694-
assert_eq!(rng3.next_u32(), decoded3.next_u32());
695-
}
696-
697-
// This test validates that:
698-
// 1. a hard-coded serialization demonstrating the format at time of initial release can still
699-
// be deserialized to a ChaChaRng
700-
// 2. re-serializing the resultant object produces exactly the original string
701-
//
702-
// Condition 2 is stronger than necessary: an equivalent serialization (e.g. with field order
703-
// permuted, or whitespace differences) would also be admissible, but would fail this test.
704-
// However testing for equivalence of serialized data is difficult, and there shouldn't be any
705-
// reason we need to violate the stronger-than-needed condition, e.g. by changing the field
706-
// definition order.
707-
#[cfg(feature = "serde")]
708-
#[test]
709-
fn test_chacha_serde_format_stability() {
710-
let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#;
711-
let r: ChaChaRng = serde_json::from_str(j).unwrap();
712-
let j1 = serde_json::to_string(&r).unwrap();
713-
assert_eq!(j, j1);
714-
}
715-
716639
#[test]
717640
fn test_chacha_construction() {
718641
let seed = [

0 commit comments

Comments
 (0)