Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

My security officer is looking for a hashing algorithm that will take a string of up to 20 characters, and then output a unique, 12-character alphanumeric hash. The 20-character string is generally just going to be numbers (okay, I'll tell you, it's credit card numbers) so it seems compressible to me.

Probably he'd have more of a comfort level if it's something that's publicly available and tested, but my research thus far suggests that popular hashing algorithms have generally fixed length outputs (or variable outputs, but to specific predetermined lengths).

share|improve this question
While you want to hide context, I would like to ask you to provide more context as your question is in no way constructive. Make sure that the title actually matches the body of your question. Why are you operating on the credit card number? Have you researched hashing, credit card numbers and the standards and laws that apply to them? Which exact problem are you having when trying to implement a solution? The answer to your question title is "yes", all the rest in this Q&A is mostly not constructive... Please improve your question. – Tom Wijsman Feb 23 '12 at 16:08

Watch out when you handle credit card numbers!

Just adhere to the standards and laws that apply in your area, or are given by your security officer. If you really need to do this then make sure that you reconsider your design, you really don't want to pass a credit card number around your code or have credit card numbers collide because of hashing.

That's asking for trouble sooner or later...

A credit card number should have a very short time to live in your code, use it for the payment and no more than that. At best you can store a trimmed version of it, for display purposes only. But don't use it in cases were its hashes would collide or in a way that the original can be retrieved, and if you somehow really need to do so make sure you have a good hashing and/or security system, that no collisions are possible and you are able to contact all customers when your database / software security has been breached.

share|improve this answer
What does "do never literally hash" mean? Oh and by the way, I don't want a decryption algorithm, that's why I said hashing rather than encryption. It's intended (in fact, required) to be one-way. – spinn Feb 22 '12 at 20:59
What good is the hash if it's one-way? It's a security liability if the hash is discovered to be weak, and useless otherwise. – afrazier Feb 22 '12 at 21:06
@spinn: I would really advise you to read up on hashing credit card numbers. If you do it wrong you'll end up with an easy to find credit card numbers as a result, you could of course go one-way but then you would be throwing data away which just makes brute forcing easier... – Tom Wijsman Feb 22 '12 at 21:07
The idea of having the hash is so we have a token we can use internally, without actually passing the raw credit card numbers around our database. I get the impression that the token would be used to match and identify the actual credit card elsewhere in a significantly more secure area. Yes, possible path of entry blah blah blah, but I'm not trying to solve all my SO's problems here, I'm just trying to help him out with the question he asked me. – spinn Feb 22 '12 at 21:14
@spinn: Why would you have to pass around credit card numbers if you can use integer IDs as primary keys? Why would you match by credit card and not by the user who used that credit card? – Tom Wijsman Feb 22 '12 at 21:22

There shouldn't be any reason for a merchant to store a full credit card number, hashed or not.

I think you really need to evaluate why you need to do this.

If you're storing credit card numbers, the number space may be small enough that brute-forcing the hash is plausible, making storing even this hash dangerous and probably in violation of PCI.

There's almost certainly a better solution that's going to allow you to solve the real problem you're facing.

share|improve this answer
Don't they need the full credit card number to do automated subscriptions? Like for example when you play World of Warcraft and don't have to touch your billing anymore because it goes automatically... – Tom Wijsman Feb 22 '12 at 21:00
There is no point into brute-forcing the hash as you can't use the hash to do something; if the hash were actually a one-to-one mapping then it would just be equivalent to brute forcing the credit card number itself. But indeed, credit card numbers should be handled with great attention to legal stuff... – Tom Wijsman Feb 22 '12 at 21:02
The merchant? I don't think so, no. That can be handled by the payment processor. The merchant only needs to store an ID received from the processor. – afrazier Feb 22 '12 at 21:02
@TomWijsman: If you can brute force the hash, you've got a list of known-good credit card numbers. – afrazier Feb 22 '12 at 21:05
Well, to make it clear, it's up to my security officer to need to evaluate why he's doing this. I can pass concerns along, but I'm just answering the question about technical possibility. But he's always dealing with PCI compliance, so he's going to be mindful of the issues. (I hope.) – spinn Feb 22 '12 at 21:12

If your input is a 20-digit number, then there are 1020 possible inputs.
If your output is a 12 character alphanumeric string, then there are 6212 possible outputs.





If we look closely, we see the bottom number is longer.
Which means there are more possible outputs than inputs.
Which means the hashing is pointless as every possible output can be mapped directly to one input. So that means it would be incredibly easy to break and get the actual numbers back.

So, we'll just use a shorter hash!

What's the point? Just use an integer, a random one if you have to.

Let's take passwords as an example.
You never store a password. You only store the hash. That makes it easy to check a given input against that hash (to see if the provided password is correct) without ever storing the actual password.

This works because:

  1. our hashing algorithms don't produce the same hash for two inputs easily (collisions unlikely)
  2. it is unreasonable to assume that someone could figure out the original input for a given hash

And why is that? Well, the password I used could be 1,000,000 characters long. How are you gonna figure that out from a short hash? You can't. You can only try to calculate as many hashes as you can, compare them to the one you have and hope for a match. In this case it usually isn't even relevant to find the actual, original input as any input that produces the same hash will work.

So, if I'm an attacker and I got a hold of the database with the hashes, I could compare the hashes to a set I previously computed to find a valid input for that hash. This is usually countered by salting your hashes.

So an attacker would be forced to brute-force so long until he found a valid input for a matching hash (which would take forever, because there's an insane amount of possible hashes).

But what if the passwords were limited to a certain length and they could only contain numbers?
This drastically reduces the possible inputs and, thus, the time it would take to brute-force a matching hash.
And that's basically what you're doing when hashing credit card numbers. But it's worse because if the attacker got a match, then it's not just going to be an arbitrary string but, most likely, a valid credit card number!

share|improve this answer
Wouldn't you have to compute all 100000000000000000000 hashes to be certain of finding which 20-digit number produced a particular 12 character string? – RedGrittyBrick Feb 22 '12 at 23:46
@RedGrittyBrick, What happens if there is a collision? (Two numbers that result in the same hash)? – Zoredache Feb 23 '12 at 0:00
@RedGrittyBrick Yes, but every hit time you calculate a hash that exists in the database, you have a valid CC number (worth it). And there aren't actually that many valid numbers. By knowing what CC numbers are valid, you can trim the input down quite a bit. – Oliver Salzburg Feb 23 '12 at 9:56
@Zoredache: well that's even better, after computing 100000000000000000000 hashes you still don't know for certain which are valid CC numbers. However you are stating the opposite of Oliver who says there's a weakness because "every possible output can be mapped directly to one input" (no collisions). – RedGrittyBrick Feb 23 '12 at 11:02
@OliverSalzburg - I think saying "incredibly easy" is the perfect word to describe it. Its "incredibly easy" if your dealing with a criminal organization that has unlimited funds ( hey its not their money in theory ) and a huge possible pay day. – Ramhound Feb 23 '12 at 13:12

Ignoring all of the questions above, there's a really, really, blindingly simple solution.

In pseudocode:

function my_hash(string data, int length){
    string t = md5sum(data);
    return t.substring(0,length)

Or sha512 sum or whatever strikes your fancy. Personally I recommend multiple rounds of blowfish. If someone grabs the database, and knows how you've created this hash, they can simple run through the space of all CC numbers as well and compare data to reverse it. This is bad.

However, beware. Read all of the other answers, they all have very valid points.

share|improve this answer
Also, for the love of all things good and holy, salt them well if you do this. – EricR Feb 23 '12 at 17:01

You must log in to answer this question.

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