I understand PCI DSS 3.0 allows hashes of cardnumbers to be stored separately from encrypted values, but I'm startled at the efficiency of tools like hashcat in discovering card numbers from hashed data given the limited entropy.

Since, for lookup purposes, a random salt is not an option (since often you only have the cardnumber to do the lookup), then any salt would have to be static to lookup the hash.

I read one suggestion that said,

A secret key can be effectively used as a salt value, albeit this defeats some of the reasons for hashing in the first place and requires the same key management as encryption. http://www.integrigy.com/files/Integrigy_Hashing_Credit_Card_Numbers_Unsafe_Practices.pdf

My question is, if I am using a "secret key" for a salt, which is subject to discovery and brute force (though its length might make the latter impractical), why not just encrypt the value with AES256, and do the lookups via the encrypted value?

Is there any security advantage to hashing with a "secret but uniform salt", versus deterministic encryption?

  • 4
    A "secret but uniform salt" is a "pepper".
    – Brilliand
    Commented Jan 8, 2015 at 19:12

3 Answers 3


Performing the card lookups against a hash rather than against an encrypted value is done for speed so it is for performance, rather than security, benefit.

In terms of security and the lookup functionality, you could consider a static salt (pepper) as well as an additional, somewhat dynamic salt (such as the expiry date of the card number).

  • Credit cards I see usually expire in next few years. Assuming 5, that only gives you 12*5 = 60 different salts. That's not very unique.
    – domen
    Commented Feb 9, 2015 at 10:35
  • 1
    not to mention using exp. date as salt means leaking another information about the card that's part of card security
    – jficz
    Commented Mar 22, 2015 at 23:09

The difference between a hash function and an encryption is that a hash is suppose to be a one way function while with encryption you can easily get the original data.

If your encryption key gets stolen you can read out all card numbers directly. If your salt gets stolen you still have to brute force it. Depending on your hash function this might be harder as you might think.

With a weak hash function like md5 or sha1 brute forcing would be simple and hashing is not a big improvement. But with a memory and CPU intensive hash you can gain some security here.

Have a look at bcrypt or maybe even scrypt. With bcrypt you can increase the needed CPU time with a parameter to make it harder to brute force. Scrypt is memory heavy so it can't be brute forced with GPUs but is kind of new (2009).

  • So, the advantage of the (pepper)hash would be that we could add security by keeping it secret. And, then on top of that, a slower hash function might make it non-trivial to crack, even if the key was discovered? I'm concluding that slow hash + pepper gives greater security, because it gives the cracker 2 barriers instead of one. Commented Jan 9, 2015 at 13:57
  • 1
    In both cases you have a secret pepper or password (1. barrier). But yes with slow hash + pepper you are more secure as with a symmetric encryption like AES. The 2. barrier would be to brute force the slow hash function. Commented Jan 9, 2015 at 14:58
  • SHA1 is not considered weak yet. Commented Feb 8, 2015 at 12:21
  • @SilverlightFox It might not have the official status yet but other functions are recommended for password hashing. I think card numbers are just like weak passwords that can be brute forced. But you are right SHA1 is not weak. It just not optimal in this use case. Commented Feb 9, 2015 at 7:56
  • 2
    Hashing doesn't help you here, even with bcrypt and scrypt. There are only 15 "free" digits in a credit card (the last number is a check digit), leaving log2(10^15) or roughly 50 bits of entropy. Worse, card tokens are frequently stored alongside their cleartext bin number (the first six digits) and their last four digits. This leaves only five digits, or less than six bits of entropy to break any individual card. Long story short, your best option is likely to use an HMAC with a key stored in an HSM. Commented Feb 9, 2015 at 15:38

In fact although you might be said to be performing the hash for lookup performance, it is being done to be PCI compliant. There are two ways of looking at this.

  1. Do x, it is the right thing to do.
  2. Do x, or we'll get caught not doing it.

Doing x to prevent cracking does not really come into it, since there are only about 5 numbers to guess in some cases. 6 digits of BIN, 1 check digit, and it has to pass Luhn.

It should only useful together with expiry dates, cvv, and billing details.

Checking and input card number against a hash is odd. Is it being used as a defacto password? Or is the decrypted value being checked against the hash ?

That is, if the user is authenticated, we can use the "Vault stored" card for a transaction, why are we checking the card number again ?

The only other reason to hash is to level an index, which otherwise would have an almighty great hotspot on each of the BINs, cardinality of the following digits aside.

  • Hashing the cardnumber is probably not necessary for a retailer. But in a card vendor scenario, one of the expected services is IVR activation. The normal prodedure, is dial in, enter the 16 digits of the card number, and activate the card. In this scenario, the only way to lookup the card to activate is by some deterministic value based on the cardnumber. Commented Jul 7, 2015 at 14:59

You must log in to answer this question.

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