XChacha20poly1305 vulnerability to known plaintext attacks During a security audit, the guy said our cryptosystem is vulnerable to known-plaintext attacks. He said that's because «the implementation uses a crypto_stream_xor() approach» (from libsodium). That's way above my skill, and I did not find anything relevant so far so I'm trying to understand if that's really a problem.

Here is what we do: we derive a key using a global (password, salt) pair. This key −always the same− is used in order to cipher all the documents using xchacha20poly1305. We initialize the stream using xchacha20poly1305::Stream::init_push: it provides us with a header (the nonce ?) that we store with the file for decryption later on. We use rust's implementation of libsodium, sodiumoxide.


Is its assessment correct? (= is xchacha20poly1305 or our usage vulnerable to KPA, and is it due to the fact it uses a xor ?) Didn't the guy mistakingly mixed things with the fact that we reuse password?
How bad is it? Does it mean that someone who can cipher a known document in our system can decipher anything else it puts its hands on?


Edit:
As requested, here is what we do, with more details, using pseudo rust code. I edited out all the irrelevant details but hopefully left enough relevant information and comments.

password, salt, chunk_size are stored in environment variables and never change.




function encrypt(file, password, salt, chunk_size) {
    // first, we derive a key
    sodiumoxide::crypto::pwhash::derive_key(
        &amp;mut key,
        &amp;password,
        &amp;salt,
        pwhash::OPSLIMIT_INTERACTIVE,
        pwhash::MEMLIMIT_INTERACTIVE,
    )

    // Then we initialize the encryption stream
    let (stream, encryption_header) =
        xchacha20poly1305::Stream::init_push(&amp;key);

    // we store the IV
    let encryption_header_bytes = Bytes::from(encryption_header.as_ref());
    store encryption_header_bytes in the output file

    // then we encrypt the file
    buffer = read file content
    while (there are data in the file) {
        // cipher the buffer using xchacha20poly1305's stream
        let encoded = stream.push(&amp;buffer[0..chunk_size], None, Tag::Message).unwrap();
        buffer.advance(chunk_size);
        store `encoded` in the output file
    }
}

function decrypt(encrypted_file, password, salt, chunk_size) {
    // first, we derive a key
    sodiumoxide::crypto::pwhash::derive_key(
        &amp;mut key,
        &amp;password,
        &amp;salt,
        pwhash::OPSLIMIT_INTERACTIVE,
        pwhash::MEMLIMIT_INTERACTIVE,
    )
    // then we read the file in a buffer
    buffer = read encrypted_file content

    // then we read the header, and create a stream out of the header and the key
    let header = Header::from_slice(&amp;buffer[0..xchacha20poly1305::HEADERBYTES])
                        .unwrap();
    stream_decoder = Some(xchacha20poly1305::Stream::init_pull(&amp;header, &amp;key).unwrap());
    buffer.advance(xchacha20poly1305::HEADERBYTES);

    // then we decrypt the rest of the file using said stream
    while(there are data to decrypt in the buffer) {
        let (decrypted, _) = stream
                        .pull(
                            &amp;buffer[0..(xchacha20poly1305::ABYTES + chunk_size)],
                            None,
                        )
                        .unwrap();
        buffer
            .advance(xchacha20poly1305::ABYTES + chunk_size);

        store `decrypted` in the output file
    }
}
```
Using crypto_secretstream that should be fine. It generates a random nonce for each message. Reusing a key in that context is fine.

Original answer, before edit follows:

Yes, that's bad. You have to use a unique IV/nonce for each document.

A stream cipher, such as ChaCha, which is combined with the plaintext using XOR reveals the keystream to anyone who knows the plaintext. That allows them to decrypt other documents. And even if they do not know the plaintext, there can be attacks.

Every document has to have some unique identifier that you can use as a nonce. It does not have to be secret or unpredictable.