cocoon: sequential calls of encryption API result in nonce reuse (<=0.3.3) (#1805)

This commit is contained in:
Alexander Fadeev
2023-10-24 04:36:07 +03:00
committed by GitHub
parent 71d80e811f
commit 0da5ced09c

View File

@@ -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]
```