Problem
Is there any combination of hash and encryption algorithms with show the following properties:
File $\rightarrow$ Hash $\rightarrow$ Encrypt $==$ Hash $\leftarrow$ Encrypt $\leftarrow$ File
So a combination of hashing and encryption which can be applied in arbitrary order so that it leads to the same result.
Use case
I want to add optional encryption to an existing file synchronisation service. Currently only trusted nodes exist, which store data unencrypted. They use the file hash as an identifier.
My idea is, to add untrusted nodes which store the data encrypted. Only the trusted nodes have the key.
In order to detect changes, hash values are compared. Since the data only exists in encrypted form on untrusted clients, they can only compute the hash of encrypted files. On trusted clients, data exists unencrypted and has a hash of the unencrypted version stored along. Now it would be far easier to just encrypt the hash on the fly instead of encrypting the whole file and computing the hash of it.
Don't overlook the extension in my edit!
Edit (2019-03-26)
I noticed that I should clarify some things about the use case:
- Two equal files do not exist in our application since they are deduplicated!
- We split files into equally sized blocks. So in this example all files have the same length!
- There are multiple nodes. For simplicity let's look at the case where we have 2 trusted ($N_{t1}$, $N_{t2}$) and 1 untrusted node ($N_u$). They are all in sync at an arbitrary point in time. Now node $N_{t1}$ creates a new file, encrypts it and synchronizes it with $N_u$. Now $N_{t2}$ comes back online and wants to determine which files have changed.
Further, I want to respond to Ilmari Karonen's answer (also too long for a comment):
The case $m_1 = m_2$ does not exist (see my clarification above).
We use relatively small blocks (128KB). So plaintext-guessing-attacks are an issue?
I thought about something like your first scheme already (please correct me if there is a structural difference):
I could just store the hash of the unencrypted file (which is our current file identifier) $H(m)$ together with the encrypted file $E_K(m)$. This would allow offline key-guessing attacks though:
1. Try to decrypt the ciphertext $E_K(m)$ with different keys $K_i$:
$E^{-1}_{K_i}(E_K(m)))=m_i$
2. Hash the result $H(m_i)$
3. Check if this is equal to the stored hash $H(m_i)\stackrel{?}{=}H(m)$
If so, we found the plaintext :/
When the used keys are long enough, this shouldn't be a problem. But with increasing computing power, it is only a question of time until this can be cracked.Is your third scheme different from what I try to avoid (see use case): In order to calculate $H_K(m)$, I need to encrypt and hash the plaintext ($H(E_K(m))$). This needs a lot of computational power for big directories. Alternatively, I could compute it once and save it. This would decrease data efficiency significantly. Nevertheless, if it is considered secure, I guess it is the best we have since I don't want to compromise on security.
Your second scheme seems interesting, although I didn't understand it completely yet (I will have to check the links you posted). Do you think this scheme is more promising with the clarified use case than the third scheme?