From 0da5ced09c6b10f732682ca8f80f948754e73581 Mon Sep 17 00:00:00 2001 From: Alexander Fadeev Date: Tue, 24 Oct 2023 04:36:07 +0300 Subject: [PATCH] cocoon: sequential calls of encryption API result in nonce reuse (<=0.3.3) (#1805) --- crates/cocoon/RUSTSEC-0000-0000.md | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 crates/cocoon/RUSTSEC-0000-0000.md diff --git a/crates/cocoon/RUSTSEC-0000-0000.md b/crates/cocoon/RUSTSEC-0000-0000.md new file mode 100644 index 0000000..e3f4b4b --- /dev/null +++ b/crates/cocoon/RUSTSEC-0000-0000.md @@ -0,0 +1,72 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "cocoon" +date = "2023-10-15" +url = "https://github.com/fadeevab/cocoon/issues/22" +categories = ["crypto-failure"] +cvss = "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N" +keywords = ["nonce", "stream-cipher"] + +[affected.functions] +"cocoon::Cocoon::encrypt" = ["<= 0.3.3"] +"cocoon::Cocoon::dump" = ["<= 0.3.3"] +"cocoon::Cocoon::wrap" = ["<= 0.3.3"] +"cocoon::MiniCocoon::encrypt" = ["<= 0.3.3"] +"cocoon::MiniCocoon::dump" = ["<= 0.3.3"] +"cocoon::MiniCocoon::wrap" = ["<= 0.3.3"] + +[versions] +patched = [">= 0.4.0"] +``` + +# Sequential calls of encryption API (`encrypt`, `wrap`, and `dump`) result in nonce reuse + +**Problem**: Trying to create a new encrypted message with the same cocoon +object generates the same ciphertext. It mostly affects `MiniCocoon` and +`Cocoon` objects with custom seeds and RNGs (where `StdRng` is used under +the hood). + +**Note**: The issue does **NOT** affect objects created with **`Cocoon::new`** +which utilizes `ThreadRng`. + +**Cause**: `StdRng` produces the same nonce because `StdRng::clone` resets its +state. + +**Measure**: Make encryption API mutable (`encrypt`, `wrap`, and `dump`). + +**Workaround**: Create a new cocoon object with a new **seed** per each +encryption. + +## How to Reproduce + +```rust +let cocoon = MiniCocoon::from_password(b"password", &[1; 32]); +let mut data1 = "my secret data".to_owned().into_bytes(); +let _ = cocoon.encrypt(&mut data1)?; + +let mut data2 = "my secret data".to_owned().into_bytes(); +let _ = cocoon.encrypt(&mut data2)?; + +// data1: [23, 217, 251, 151, 179, 62, 85, 15, 253, 92, 192, 112, 200, 52] +// data2: [23, 217, 251, 151, 179, 62, 85, 15, 253, 92, 192, 112, 200, 52] +``` + +## Workaround + +For `cocoon <= 0.3.3`, create a new cocoon with a different **seed** +per each `encrypt`/`wrap`/`dump` call. + +```rust +let cocoon = MiniCocoon::from_password(b"password", &[1; 32]); +let mut data1 = "my secret data".to_owned().into_bytes(); +let _ = cocoon.encrypt(&mut data1)?; + +// Another seed: &[2; 32]. +let cocoon = MiniCocoon::from_password(b"password", &[2; 32]); +let mut data2 = "my secret data".to_owned().into_bytes(); +let _ = cocoon.encrypt(&mut data2)?; + +// data1: [23, 217, 251, 151, 179, 62, 85, 15, 253, 92, 192, 112, 200, 52] +// data2: [53, 223, 209, 96, 130, 99, 209, 108, 83, 189, 123, 81, 19, 1] +```