libsodium stream encryption I am new to cryptography, I have used OpenSSL and its aes-256-cfb cipher before to do stream encryption, which works great. Now I am going to try libsodium, since it's light and its APIs look concise, but I can't get it working.

I tried its XChaCha20 stream cipher, but it only has the crypto_stream_xchacha20_xor and crypto_stream_xchacha20_xor_ic functions, I can easily encrypt and decrypt messages when the message lengths appear in pairs, like encrypting 20 bytes, then decrypting 20 bytes, this works fine. but it will fail if encrypting 20 bytes, then decrypting 10 bytes and decrypting 10 more bytes. The latter case is what I want, I am implementing a proxy, I would like to read random length (i.e. not in blocks and no boundaries) of data from one TCP connection, encrypt and stream the data through another TCP connection, the other end of the connection reads random length of the encrypted data and decrypts it.

For what I want, xoring my data wouldn't work, since there's no context object like OpenSSL's EVP_CIPHER_CTX and no information like how many bytes have been encrypted/decrypted is kept, this looks weird to me, if it doesn't support this kind of stream mode, why is it called a stream cipher?

My question: Is it possible to do what I want using libsodium, if so, how?
libsodium has an API dedicated to stream encryption: crypto_secretstream, which is fully documented here: https://download.libsodium.org/doc/secret-key_cryptography/secretstream.html

Using simply crypto_stream_* or OpenSSL aes-256-cfb would be completely insecure. Without any authentication tags, the stream can be tampered with, without any ways to detect that it happened.

crypto_secretstream lets you encrypt and decrypt a sequence of variable-length messages, and prevents tampering, reordering and truncation.

However, if 50 bytes, then 20 bytes are encrypted, you must decrypt 50 bytes, then 20 bytes as well, in this order.

If you are reading data from a TCP connection, you can accumulate it into a fixed-size buffer, and once that buffer is full or you have reached the end of the stream, encrypt or decrypt its content. This will also improve performance and minimize the overhead of authentication tags over encrypting the outcome of ever single read() call.

If the session is interactive, your options are:


Pad messages to the chunk size (sodium_pad(), sodium_unpad()) before encrypting them. This uses more bandwidth, but improves security by revealing less information about the message sizes.
Prefix each ciphertext with its size, so you know how much data has to be read before being decrypted.