You did not clearly read the documentation of your library.
With the cipher.encryptor()
you open streaming and it is only finalized with the finalize()
method. This operation is important to process large files and streamings. One can divide the input into chunks, call update()
method many times to process chunks.
One can call this as a session of the $(IV,key)$ is opened until you close!.
Later on, if I try to encrypt another message with the same cipher(which means same key and iv) it is possible. What is the explanation for this?
The CTR mode uses a combination of IV and counter for the input to the PRF/PRF ( ChaCha/AES) to produce a stream to x-or with the plaintext to produce the ciphertext. CTR mode in a sense modern version of OTP with the main difference; OPT has perfect secrecy whereas CTR has Ind-CPA ( relaxation to computationally bounded adversaries).
Once the CTR mode is initialized, for each block encryption the counter is incremented. Depending on the library, the counter can be 32 or 64-bits.
CTR mode like OPT has a catastrophic failure if $(IV,key)$ pair is reused. An attacker can try crib-dragging technique to break confidentiality.
In your case, the update continues to use the CTR mode where it is left. The only danger there, you may deplete the counter where the danger starts.
Why is possible to encrypt multiple messages within the same stream in AES
You simply did not close the encryptor()
with the finalize()
. As the documentation says;
- Once finalize is called this object can no longer be used and update() and finalize() will raise an AlreadyFinalized exception.
You need to finalize()
and choose a new $IV$ or $key$ and create a new encryptor with that. Or better, create a new Cipher
Instance after purging the previous.
Extra: How to encrypt multiple messages with CTR mode
A key in the CTR mode with $IV$ can be used for a long time. Since the nonce is not long, using random $IV$'s can create collision due to the birthday bound. If you use 64-bit random $IV$'s and 64-counter for AES, you should stop way earlier than encryption $2^{32}$ messages under the same key.
The proper recommended method is using counter/LFSR (see NITS 800-38a Appendix C) for the IVs so that there is no collision. The only problem is the system failures where you may lose the track of the LFSR/counter. In this case, use a new key that is selected uniformly randomly.
You may continue to use the stream to encrypt multiple messages, however, this is dangerous, adds more risk to the encryption than necessary.
The proper way is to use a new $(IV,key)$ pair for each message.
CTR mode can only give you Ind-CPA. In modern cryptography, we want more than Ind-CPA. Authenticated Encryption (AE )(with Associated Data (AEAD)) is the modern standard and still evolving. We have;
- AES-GCM, and
- ChaCha20-Poly1305
ciphers that both exist in the TLS 1.3. Both cipher suites are AEAD modes and can provide you confidentiality, integrity, and authentication in a combined mode.
AES-GCM internally uses CTR mode to encrypt the data, so $(IV,key)$ is still problematic there. To mitigate this there is SIV mode, AES-GCM-SIV that incorporates the message into IV to solve this issue.
ChaCha20 internally has CTR mode (PRF to CTR) and has the same issue. To mitigate this we have xCHaCha20-Poly1305 that enables 192-bit random nonces so that a random $IV/nonce$ collision is not going to happen.
In all cases, use 256-bit keys for encryption to mitigate possible Cryptographic Quantum computer.