0

I'm building a sharing protocol where users share data. To make it so only those authorised to read the data can do it, I'm using AES256 encryption. Every authorized person has a keyset (IV & key) to decrypt the information. The same keyset (key & IV) is only used for one data.

The thing is, the data can change, like a new version, and then the user will download the new version of the data and decrypt it. Using the same keyset.

The data always starts with 8 random bytes (changed for each 'version'), can be over a hundred MB and yes uses the same key & IV.

I use AES256 CTR, butpeople have been questioning my choice (without more information than that) and I would like to know what you think.

For me (which might be wrong) it is quite safe to reuse the same keyset for specific data even when new versions are distributed because they all start off on a new version-specific random 8 bytes.

Am I delusional, or is 64bits entropy enough to counter the reuse?

3 Answers 3

2

Am I delusional, or is 64bits entropy enough to counter the reuse?

In CTR mode, the entropy contained within the plaintext doesn't get incorporated into the key generation or permutation algorithms. So, injecting entropy into the plaintext doesn't solve the problem of nonce reuse. The randomization of CTR mode comes from encrypting the nonce & counter with the key. So, the pair (nonce, counter) must never repeat when using the same key(0)(1).

Diagram from Wikipedia of a block cipher in CTR mode.

Illustration 1: Diagram of a block cipher in CTR mode.

A rather comprehensive list of disadvantages (& the resulting requirements) of CTR mode has been detailed in a previous answer. There's a property called nonce misuse-reuse resistance that considers ways ciphers can remain safe even when the nonce is reused. It's an active & challenging field of study(2)(3)(4)(5). The Synthetic IV (SIV) modes of operation are the ones which are typically studied with regard to this property.

There are two major violations of security with what you're doing:

  1. You are explicitly reusing the nonce (what you call the IV) with the same counter & key in CTR mode. This is not allowed.
  2. You are not using authenticated encryption (or AEAD) even though you are expecting the system to utilize some notion of an "authorized person", & presumably, authenticated data.

[...]it is quite safe to reuse the same keyset for specific data even when new versions are distributed because they all start off on a new version-specific random 8 bytes.

This is not true.

3
  • I'm a bit slow, but first of all thank you. I understand I cannot do what I'm wanting to do using CTR mode (or any stream version), if I don't use a stream cipher I'll eventually hit the 2^256/2 limit (is that even what I think it is, a number of bytes encrypted?) of what can safely be encrypted, or is there a way around reusing a symmetric AES key over and over again? I mean reasonably, 2^128 is quite much.
    – Valmond
    Commented Sep 11, 2023 at 19:06
  • 1
    This answer missing a clear recommendation. Long message distinguisher may not me your problem and it is not related to key size. It is related to block size and an attack may see that there is an encryption instead of random data. I'm not sure you are encryption such long data. You may benefit AES-GCM-SIV mode or better use xChaCha20-Poly1305 that is slower to AES due to AES-NI, however, it is easier to use that AES-GCM-SIV. Then nonce has 192-bit size and you will never have a nonce collision if you generate from a good random source.
    – kelalaka
    Commented Sep 12, 2023 at 14:38
  • Another solution to your problem, you may encrypt the file with a random key and random nonce/IV then send the key to the corresponders, The nonce/IV can be prepended to the ciphertext with no problem. The NaCL library has most of the tool that you will need.
    – kelalaka
    Commented Sep 12, 2023 at 14:41
1

You should look at existing solutions like the Cryptographic Message Syntax defined in PKCS#7 instead of trying to design your own crypto. With CMS you can

  • avoid key reuse: every message has its own AES key
  • avoid key sharing: every recipient can have their own RSA key

Additionally, you can add authentication via message signing, should you want to do this.

1
  • Thanks, when I communicate there is a fresh key iv each time, but my (maybe wrong or impossible) design needs the same key to decipher different messages.
    – Valmond
    Commented Sep 11, 2023 at 19:07
1

The entire point of the IV is that it's not secret and not tied to the key, so you can generate a new one for each message. It is important that you never, ever re-use it for multiple messages with the same key. Especially for stream ciphers (or block ciphers in stream-like modes of operation, such as CTR), it is essential that you don't re-use it with the same key, because a given (cipher, IV, key) tuple will produce an identical "keystream" every time, and that keystream gets XORed with the plaintext to produce ciphertext (and vice versa; the encrypt and decrypt operations are identical). It's like a one-time pad, except instead of the entire pad being generated randomly each time, you have a long-term random secret (the key) and a single-use random public datum (the IV, or "nonce" as they're usually called in such cases, for "number used once"), and these two random fields are combined in an algorithmic was to generate an arbitrary-length pseudo-random stream of bits.

The problem is, you are reusing that stream of bits for multiple messages, which means anybody who sees two ciphertexts (for the same key+IV) can just XOR them together to get the difference of the two plaintexts, revealing what parts of the data changed, and how. It gets even worse, though. Suppose user A gets v1 of the data. User A then is removed from the service, so they'll never get future versions. However, user A intercepts the encrypted traffic as user B downloads the same v1 data. User A can now XOR the encrypted traffic with their own (decrypted) version of v1, and learn user B's keystream (up to the length of v1). When v2 ships, even though user B won't officially receive it, they can read the encrypted traffic to user B, XOR it with their computed value for user B's keystream, and decrypt v2 anyhow! They could also potentially do things like encrypt traffic to the server using user B's keystream, thus seemingly using user B's actual key (they aren't, they don't know that, but they don't need it) and impersonating user B.

Finally, since encryption and decryption of CTR traffic is just XOR, an attacker with the ability to intercept and modify traffic for another user can simply flip bits in the ciphertext - even if they don't know what the decrypted value should be - and flip exactly those bits (and no others) in the plaintext. Such "bit-flipping attacks" can be used for all sorts of mischief, from giving people incorrect information to maliciously tampering with trusted data such that when it gets processed, it exploits a vulnerability in the parser and gets code execution on the victim's machine.

Stuff like this is the entire reason the number one rule in applied cryptography is "never roll your own".

people have been questioning my choice (without more information than that) and I would like to know what you think

I think you should have listened to them. I didn't need most of the information you gave here to know that what you were doing was dangerously insecure; most of the details are just different ways you're doing it wrong.

Like I said above, never roll your own cryptography. Is there some reason you didn't just use TLS?

Am I delusional, or is 64bits entropy enough to counter the reuse?

I don't know about delusional, but you're absolutely wrong!

  1. Since in CTR mode every bit of message is independent of every other bit, changing the first 64 bits doesn't do a single thing for security of the rest of the message.
  2. Even if you were using a mode where changes to one part of the message propagate to other parts (like CBC), reusing IVs exposes information about which message is being transmitted.
  3. This still doesn't address bit-flipping or spoofing attacks at all.
9
  • Thank you, it really explains at least the why (I love cryptography, doesn't mean I'm good at it). So if I need to use a fix key for several and even lots of data, is it even possible with a symmetric encryption (I have understood that stream ciphers are off the table)? Or should I look into asymmetric algos like RSA (which I use for handshake and sending random key+nonce AES keys for communication which is what I learned is the way to go, but now I wonder why that would work too)? Cheers and thank you again for taking your time! I'm a slow learner.
    – Valmond
    Commented Sep 11, 2023 at 19:32
  • Just a friendly post > "never roll your own". Yeeah that's why I rolled with AES and RSA for this FOSS project back in 2013-2014 (not yet ready for release)! > I think you should have listened to them. I did so and that's why I'm here today! I never thought AES, a sort of industry standard, would be so fragile, almost like a single use pad cipher...
    – Valmond
    Commented Sep 11, 2023 at 21:00
  • ... For TLS, as a transport layer protection I couold use it on top of everything, but the data is supposed to be encrypted, so neither the emitter, nor any man in the middle can get to it. Generating a TLS cipher for each data, why not. Or just reuse the RSA code I'm already using? I mean one asymmetric cipher or another (I'm not rolling my own implementation here of course). Thanks again!
    – Valmond
    Commented Sep 11, 2023 at 21:00
  • Using a single key for many messages is the entire point of the IV/nonce: it's a unique value (or at least, unique for a given key) that is not secret (you can send it, in plain text, along with the encrypted message). This is true for all symmetric ciphers, be they block or stream. All crypto is fragile if used wrong; it's a complicated and error-prone thing. TLS protects data between two hosts, regardless of how many network nodes it passes over (unless they terminate the TLS connection and start a new one). However, modern TLS does not use RSA encryption, and protocol design matters a lot!
    – CBHacking
    Commented Sep 12, 2023 at 12:44
  • Some light in the tunnel :-), so if I want to encrypt say 128 blocks, I could just deliver in the open: the 128 encrypted blocks + the 128 unencrypted nonces used to encrypt all the blocks? And deliver the key secretly to the receivers? Keeping track of the nonces used for each key so I don't reuse any of course. Would that be a viable solution?
    – Valmond
    Commented Sep 13, 2023 at 15:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .