Skip to content

Commit f2b667e

Browse files
authored
chacha20: remove serde feature (#461)
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 9f095c4 commit f2b667e

File tree

3 files changed

+0
-131
lines changed

3 files changed

+0
-131
lines changed

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 {
@@ -498,25 +494,6 @@ macro_rules! impl_chacha_rng {
498494

499495
impl Eq for $ChaChaXRng {}
500496

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

528505
mod $abst {
529-
#[cfg(feature = "serde")]
530-
use serde::{Deserialize, Serialize};
531-
532506
// The abstract state of a ChaCha stream, independent of implementation choices. The
533507
// comparison and serialization of this object is considered a semver-covered part of
534508
// the API.
535509
#[derive(Debug, PartialEq, Eq)]
536-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
537510
pub(crate) struct $ChaChaXRng {
538511
seed: crate::rng::Seed,
539512
stream: u64,
@@ -659,58 +632,8 @@ pub(crate) mod tests {
659632
assert_eq!(rng.get_word_pos(), 8888);
660633
}
661634

662-
#[cfg(feature = "serde")]
663-
use super::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
664-
665635
type ChaChaRng = ChaCha20Rng;
666636

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

0 commit comments

Comments
 (0)