For a hash function what is the best secure method, XOR or Concatenate:

h(data1 XOR data2 XOR data3 XOR data4) ? or use h(data1||data2||data3||data4)?

  • 4
    What do you want to achieve with that? The first one is obviously not collision or second pre-image resistant. – CodesInChaos Jan 17 '13 at 10:47
  • +1 to @CodesInChaoes. It's important to know what you're trying to accomplish. In addition to the first case, your second example does not uniquely identify the components. Better than both is (probably) H(32-bit-length-of-data1 || data1 || 32-bit-length-of-data2 || data2 || ...). But it's critically important to know exactly the problem you're trying to solve. – Stephen Touset Jan 17 '13 at 20:05
  • 1
    For your concatenation approach, consider H("Bob Dole" || "bobdole@example.com") versus H("Bob Dol" || "ebobdole@example.com"). For the XOR example, consider H(0b0001 ^ 0b0101) versus H(0b0000 ^ 0b0100). – Stephen Touset Jan 17 '13 at 20:07

It really depends on what you are trying to do; a hash function is a tool. Just like a hammer is good if you want to hit on nails, not so much if you want to feed a baby (a baby bottle is better for that).

One main usage of hash functions is to get a "digest" which represents a given piece of data. This is the first step for digital signatures: instead of signing a piece of data, we actually sign the hash of the piece of data; the hash is "as good" as the original data for verification purposes (since you cannot cheat a hash function) but the hash value has a fixed, short size which is much more convenient to map into the mathematical structures used by the signature algorithm. A similar usage of hash functions is for storing "verification tokens" such as what happens with passwords: you store the hash of the password, so that when the password "comes back", you can verify that it matches what you stored; but what you store is not sufficient to (easily) recompute the password.

Apparently, you want to hash a set of data elements: the input data is a set of four data blocks.

If your set is ordered (you consider "data1,data2,data3,data4" to be distinct from "data1,data2,data4,data3") then you should use concatenation, not the XOR. For that matter, you would probably want to hash a somewhat less ambiguous encoding, because if data1 is "df" and data2 is "gh", then concatenation yields "dfgh" which is the same value that you would get from concatenating "d" with "fgh". If your data elements are string of characters which never include a comma, then you can concatenate them with comma signs as separator, which is enough to avoid this ambiguity.

If your set is unordered (you consider "data1,data2,data3,data4" to have the same meaning as "data1,data2,data4,data3", and you want both to hash to the same value), then the XOR is not the right solution either; you should instead enforce a "sorting step" in which the four data elements are first ordered unambiguously (e.g. lexicographic order), and then you do concatenation as above.

I don't imagine a scenario where XORing would do something useful here, but maybe you have a use case where the XOR happens to do the right thing. It really depends on what you want to achieve.

  • 1
    I sometimes use xor to calculate hashes of unordered data for use in a hashtable since sorting is relatively expensive. For example as part when implementing value equality on sets. Clearly it's not such a great idea for most security purposes. | It might be possible to use xor in some keyed hashing scenarios. But that certainly requires careful design. – CodesInChaos Jan 17 '13 at 20:15

In your example, XOR is a way of scrambling the data. Hash functions already provide good scrambling so concatenating would provide a longer piece of data that would better resist a brute-force attack.

If you use XOR and the attacker can control the data1 field, then the attacker can control the output of the XOR operation and the resulting hash. An example would be XOR-ing something controlled by the attacker with a something that is changing, like a time-stamp. The attacker can craft an input in order control the output of the XOR, therefore eliminating the effect of the changing time-stamp.


Concatenation*: It will give you:

  1. A unique hash: If some combinations of data1-4 produce the same XOR (yes they can) you'll have a collision even before applying the hash.
  2. A longer keyspace. Even if data1-4 never collide when XORed, the input keyspace is larger, and will be harder to brute force its way into.

    • Concatenation is the "best method" of the two (see @StephenTouset's comment below)
  • 3
    However, both are probably bad. Without fixed-width field length specifiers, the resulting hashes don't uniquely identify their components. Consider H("Bob Dole" || "bobdole@example.com") versus H("Bob Dol" || "ebobdole@example.com"). – Stephen Touset Jan 17 '13 at 20:03
  • @StephenTouset fair point! – Henning Klevjer Jan 17 '13 at 20:14
  • Another way of saying it: you need a canonical representation in bits of the entire set. – Maarten Bodewes May 22 '15 at 11:30

Your Answer

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