I have a standard random key and IV. Then I am creating a cipher using these keys and iv and then encrypt a specific message. 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?

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

key = os.urandom(32)
iv = os.urandom(16)

cipher = Cipher(algorithms.AES(key), modes.CTR(iv))

encryptor = cipher.encryptor()
decrypter = cipher.decryptor()

ciphertext1 = encryptor.update(b"secret message")
ciphertext2 = encryptor.update(b"I'll give you 100 and that's my last offer") + encryptor.finalize()

decrypted_message = decrypter.update(ciphertext1)
print("the decrypted message from the cyphertext : ", ciphertext1, " is : ", decrypted_message)

decrypted_message2 = decrypter.update(ciphertext2) + decrypter.finalize()
print("the decrypted message from the ciphertext : ", ciphertext2, " is : ",decrypted_message2)
  • 1
    $\begingroup$ This strongly leans to a question for Stack Overflow rather than cryptography. We deal with the algorithms here; it is expected that if you use the same key / IV that you get the same ciphertext. How and if the IV is used is up to the library, and has little to do with cryptography. From a theoretical stand point, you'd hope that the API is designed to only allow one encryption / decryption using the same key and IV pair for one specific instance, but there are few API's that do this, unfortunately. My recommendation is to always create a new instance and, if required, just persist the key. $\endgroup$
    – Maarten Bodewes
    Oct 20 at 10:45
  • $\begingroup$ Please don't change the question once answered. If you need ask something else, you can always ask a new question. $\endgroup$
    – kelalaka
    Oct 21 at 23:32

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.

  • 1
    $\begingroup$ okay, this is very clear. Thank you so much $\endgroup$
    – user96631
    Oct 20 at 21:51
  • $\begingroup$ @dmtrs18 you also need to read this Disadvantages of AES-CTR? $\endgroup$
    – kelalaka
    Oct 21 at 16:03

You're encrypting only one message here, namely secret messageI'll give you 100 and that's my last offer.

You chose AES-CTR without authentication. In this mode, AES is used to generate a stream of pseudorandom bits that is simply xored with the plaintext bits one by one. So when you pass the first 14 bytes of the ciphertext to the decryption function, you get the first 14 bytes of plaintext back.

Encryption without authentication is dangerous, and CTR especially so. In fact the documentation for this module says

This is a “Hazardous Materials” module. You should ONLY use it if you’re 100% absolutely sure that you know what you’re doing because this module is full of land mines, dragons, and dinosaurs with laser guns. You may instead be interested in Fernet (symmetric encryption).

If you use Fernet then you won't be able to decrypt the message in two pieces like this.

  • $\begingroup$ Okay, I get what you mean. Thank you very much I will try and fix it now. $\endgroup$
    – user96631
    Oct 20 at 21:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy