1

I am working on a project, where user email address hashes will be available publicly, and I need to prevent them from being quickly discovered by spammers.

The main idea of the undertaking is to give anyone who already knows the email addresses an easy way to find users by them, but make it difficult to discover emails by simple enumeration of possible alternatives.

What I thought about is using BCrypt or PBKDF2 to create the hashes, and use salt to create hashes where the sum of the bytes in the first half equals the sum of the bytes in the second half.

Here's what the algorithm could look like:

    static byte[] GenerateMagicSignature(string text)
    {
        long id = 0;
        const int nParts = 2;
        while (true)
        {
            var key = BitConverter.GetBytes(id);

            for (long i = 0; i < id+1; i++)
            {
                var dd = new HMACSHA256(key);//replaced new encoding....
                key = dd.ComputeHash(key); 
            }

            var b=new Rfc2898DeriveBytes(text,key,10000);

            var sig=b.GetBytes(32);
            id++;
            var pts = SplitIntoPartsAndSum(sig, nParts);

            int val = pts[0];

            bool wrong = false;
            for (int i = 1; i < pts.Length; i++)
            {
                if (val!=pts[i])
                {
                    wrong = true;
                    break;
                }
            }

            if (wrong)
            {
                continue;
            }


            return sig;
        }
    }

    static int[] SplitIntoPartsAndSum(byte[] data, int parts)
    {
        var sums=new List<int>();

        for (int i = 0; i < parts; i++)
        {
            int sum = 0;
            var start = i*data.Length/parts;
            var end = (i + 1)*data.Length/parts;
            if (i==parts-1)
            {
                end = data.Length;
            }
            for (int j = start; j < end; j++)
            {
                sum += data[j];
            }

            sums.Add(sum);
        }

        return sums.ToArray();
    }

The average hashing time for a known email address with these settings is around 1 minute on a single CPU. Which right now can be divided by 5000 cuda cores, if I understand this stuff correctly (or is the use of PBKDF2 going to significantly reduce that number?).

My question is: is doing this a good idea, or do I have to re-think the whole thing? My goal is not to make the email addresses fully protected, but make it more difficult for the attacker to get them than, say, by sending queries to facebook and checking if it knows those emails or not.

  • Maybe I am too tired to understand, but how do hashes of e-mails have anything to do with spammers? The salt should be random per user or even per mail. – John Jan 11 '16 at 23:16
  • 1
    If I understand this correctly, if I set the hash randomly, the emails won't be discoverable by hashes for those, who already know them. Since the hashes will be public, everyone can access them, including spammers, and I'm thinking on how to prevent that from happening – Arsen Zahray Jan 11 '16 at 23:20
  • Do you mean "emails" or "email addresses"? – Neil Smithline Jan 11 '16 at 23:22
  • 1
    I guess I really don't understand what you are trying to do. – Neil Smithline Jan 11 '16 at 23:24
  • I mean, email addresses. Let's say, I've got email myemail@example.com and a few hundred thousand more like it. I want to compute a hash of it (in this case, GojBUqM8qndfuL3e5wBejyCRLA9I2o+jMMwAhs3E7vo=) and make it publicly available. If you know the email, you should be able to easily discover it, if not, it should be hard. Is this going to work? – Arsen Zahray Jan 11 '16 at 23:31
1

Email addresses are very often built off of easy to construct, common patterns with public data - first initial plus last name @ company, first name dot last name @ company, etc. etc. etc.

Further, many actual email addresses have been leaked, and several sets of attackers are going to have stolen or purchased large lists of email addresses to try as well.

Therefore, attackers have a much, much smaller keyspace than when attacking passwords.

I'll address PBKDF2 in specific; assuming your clients have powerful, modern 64-bit machines, they can still only use one core to hash one email address (their own); Hashcat probably has one of the most optimized sets of code available for CPU, and oclHashcat likewise for GPU.

Assuming a PBKDF2-HMAC-SHA-1 style setup (i.e. SHA-1 is the base hash), then you can expect a single serious modern 8-GPU box to crunch passwords 1500 to 2500 times faster than x64 code running on a fairly serious modern CPU; the advantage only grows if your users have out of date hardware, inexpensive hardware, low power hardware, or mobile devices.

Even at, say, 2000 times faster, the attacker averages 0.03 seconds to run a test on an email it took a client one minute to generate.

PBKDF2-HMAC-SHA-512 would reduce the attacker's advantage, but you're still in a losing game, since an attacker can spin up their GPU's and leave the machine to try email patterns for two and a half million seconds (30 days) easily, paying only an electric bill and the loss of that machine for other actions.

Alternately, spammers may simply dedicate spare CPU time, which they probably have plenty of, to validating their email lists against your email list. It's even free if they're using other people's computers (i.e. a botnet)!

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.