5 ms·
I'm not following unfortunately. To be clear, what I'm saying is ciphertext = Encrypt(plaintext || Hash(plaintext)) where Encrypt(data_stream)[i] = data_stream[
by dataflow 3y ago
I'm not following unfortunately. To be clear, what I'm saying is ciphertext = Encrypt(plaintext || Hash(plaintext)) where Encrypt(data_stream)[i] = data_stream[i] XOR random_stream[i].
I'm not following how an attacker can tamper or decipher anything in the ciphertext here. The moment you tamper with any bit, the hash would become invalid. You can XOR it with whatever you want but you can't turn it into anything valid... right? What am I missing?
- tptacek 3y agoIf you know the plaintext, you know the hash of the plaintext, because the hash doesn't have a key. Encrypt() is CTR, so you can flip bits in ciphertext to alter the same bits in the plaintext. You know the plaintext and the hash and you know where the hash is, so you can mechanically rewrite the hash to be whatever you need it to be. You can prove this to yourself in Python or Ruby or whatever: just CTR-encrypt "We all live in a yellow submarine", along with its hash. Then bitflip "yellow" to "orange", compute the hash for "We all live in a orange submarine" (ignore the grammar), and bitflip that into the original hash. There are formalisms to why hash-then-encrypt is unsafe that I'm not giving you here, because I'm not smart enough to pull them out of the top of my head, but the scenario I just described is already a game-over vulnerability in many settings; a similar fact pattern has broken lots of encrypted cookie schemes, which you do in fact know the plaintext, and some bit of the plaintext (like "admin=n") happens to be incovenient to attackers.
- dataflow 3y ago> If you know the plaintext, you know the hash of the plaintext, because the hash doesn't have a key. I actually was imagining the key would be used in the hash function (just like it's also used by the encryption function). It didn't occur to me to explicitly mention it, but I see why it can be interpreted differently otherwise. (Thanks for explaining/clarifying.) If I did that though, wouldn't that take care of this?
- akerl_ 3y agoUsing a key in the hash function is basically what an HMAC is.
- dataflow 3y agoMy recollection was that by definition an HMAC crucially performs 2 rounds of hashing layered over the message... something like h(key || h(key || msg))? Whereas in my mind I was imagining something with one layer over the message (like h(f(key) || msg)) could work; I didn't actually see the need to do two layers of hashing over the message in what constituted (or at least I understood to constitute) a proper HMAC. Not sure if I had a misunderstanding of either the concepts or the terminology here, but if I did, please do let me know.
- akerl_ 3y agohttps://en.wikipedia.org/wiki/HMAC#Design_principles https://en.wikipedia.org/wiki/HMAC#Design_principles addresses the rationale for performing 2 rounds of hashing.
- dataflow 3y agoRight, I get that it's guarding against a bad hash. I was (obviously) assuming the hash and RNG aren't flawed. In which case an proper HMAC seems unnecessary in this scheme. But thanks for clarifying.
- akerl_ 3y agoI think maybe the gap here is about what a "bad hash" is. The attack described in the design principles section is applicable to hashes like SHA1 and SHA2, which makes it a pretty big deal. You could just always use a truncated variant of SHA2, or use SHA3, and you'd be covered for this specific risk... but at some point it's way easier to just start with an existing AEAD scheme instead of trying to piece something together from parts.
- upofadown 3y ago>ciphertext = Encrypt(plaintext || Hash(plaintext)) As already mentioned, this allows the attacker to generate a valid hash in some circumstances. You don't have to allow this and it has been argued that such an approach is secure[1]. As a practical example, which is guaranteed to annoy someone just by the suggestion, the OpenPGP authenticated encryption mode that has been around forever has never been subverted in this way but is at its heart "hash then encrypt". It depends on a random value that is kept from attackers[2]. [1] https://cseweb.ucsd.edu/~mihir/papers/enc-red.pdf https://cseweb.ucsd.edu/~mihir/papers/enc-red.pdf [2] https://articles.59.ca/doku.php?id=pgpfan:mdc https://articles.59.ca/doku.php?id=pgpfan:mdc (my article)