Credit Card Scrambler

This Hazel HZML/HTML page demonstrates my idea for a way to hide credit card numbers in plain sight. First, here's the demo part, with the discussion below.

Enter a test credit card number here:

CLIENT= %HZE_CLIENT
CREDTEST= %HZV_CREDTEST
Last 2 of Client = %HZE_02R_CLIENT
First 2 of Credtest = %HZV_02L_CREDTEST
SCRAMBLER = %HZV_scrambler

The credit card number is 16 digits long.
SCRAMBLER = %HZV_SCRAMBLER
The first ten digits of the card are %HZV_10L_CREDTEST
The scrambler variable is = %HZV_SCRAM
The last six digits of the card number plus the scrambler variable = %HZV_SCRAM

The credit card number is 15 digits long.
SCRAMBLER = %HZV_SCRAMBLER
The first nine digits of the card are %HZV_09L_CREDTEST
The last six digits plus the scrambler variable = %HZV_SCRAM
The last six digits of the card number plus the scrambler variable = %HZV_SCRAM

The credit card number is 14 digits long.
SCRAMBLER = %HZV_SCRAMBLER
The first eight digits of the card are %HZV_08L_CREDTEST
The last six digits plus the scrambler variable = %HZV_SCRAM
The last six digits of the card number plus the scrambler variable = %HZV_SCRAM

The credit card number is 13 digits long.
SCRAMBLER = %HZV_SCRAMBLER
The first seven digits of the card are %HZV_07L_CREDTEST
The last six digits plus the scrambler variable = %HZV_SCRAM
The last six digits of the card number plus the scrambler variable = %HZV_SCRAM

The scrambled card number is %HZV_scrambled_cred.
The credit card number is not between 13 and 16 digits long.
The number in clear is %HZV_credtest.

To derive the original credit card number, multiply the first two digits of the card number by the last two digits of the client number, and use the six right-hand digits of that number. Subtract that result from the scrambled card number.

Decryption result: %HZV_FRONT%HZV_06R_descrambled.

If you search the Hazel knowledge base, you will see there have been intermittent queries as to how best to encrypt the emails that Hazel uses to send credit card numbers. The consensus has been that the risk of sending the emails is very low, provided the email messages are stored on the same server where Hazel resides prior to being sent. The further consensus is that implementing an encryption program such as PGPSendmail or GnuPG is a hassle, there are limits to how a commercial operation can support PGP (though I take it GnuPG is a different story) and it's just not worth the trouble. There's also the issue of having to send half the email messages (the store invoices) encrypted while sending the other half (the messages to the customers) in clear.

For all of that, there is something unsettling about email messages with unprotected credit card numbers flitting hither and yon -- and maybe accumulating on the receiving computer. (And you likely want to retain those order emails for a while in case of problems with an order, etc.) If a bad guy managed to wander into your office with a 3.5 floppy and copied three months' worth of order emails off your hard drive -- well, that would be uncool. It might well be that keeping your credit card data secure on your own system was the bigger challenge.

Just yesterday, it struck me that the only thing that needs encryption is the credit card number itself. Furthermore, having that number off by a mere one digit ought to be enough to render it useless -- and would leave the bad guy wasting his time trying to get a useless number to work. (The system below actually scrambles four or five digits.) If the card number were scrambled just a trifle, and still looked like a legit number, and it were done in such a way that the original number would be easy to recover, that would be encryption enough. If the email were intercepted in transit, or stolen off your computer, the credit card number as shown wouldn't work.

I got the idea of using the credit card number itself, and/or other numbers sent in the store invoice, as a source of very basic encryption keys. The example above takes the first two digits of the credit card number and the last two digits of the client number and multiples them together. It then adds that result to the last six digits of the credit card number, and then prepends the first part of the credit card number to the addition result. It is in four sections, to accommodate card numbers of 13, 14, 15 or 16 digits.

(It would be more elegant to do one word loop, running it over each length and testing for the length, then doing the encrypt when the length matched, but that would require getting some pretty complex tags going. You'd not only have to drop the card length value into the regular expression that checked length, but also subtract six (I use the six digits on the right) from the card length value, and then plug that result into the fixed-length tag inside the value statement of the Hazel Vset that sets the value of HZV_scrambled_cred. I just couldn't figure out how to get a complex tag to do all that. Any suggestions?)

The idea is to do these calculations on the store invoice after Hazel has done her initial checks on the credit card number and has established that it is passes the CRC checks -- that is, that the number is valid format. Since the error-checking has already been done, it doesn't have to be done here. We can't get to this point in the process unless we have a properly formed card number. Once this very light encryption has been done, all that has to be done at the receiving end is to multiply the two values by each other and then subtract them from the reported card number to get the original card number. It would be duck soup to set up a little program, or a spreadsheet worksheet, into which the scrambled card number and the encryption keys could be cut-and-pasted, and which then would recover the original card number.

I am deliberately leaving one flaw in place here to make a point about selecting your keys carefully. By using the last two digits of the client number, I am leaving myself open to the one-in-a-hundred chance that the last digits will be 00, which, when multiplied by something else, will give the result of zero. When added to the credit card number, you'd get the number in clear. (Try it for yourself. Enter a bogus card number that starts with two zeros (impossible in real life) and you'll see the card number comes through unscrambled.) For this reason, it is probably wiser to use the leading rather than trailing digits of a number (because the first two digits won't be zero) and/or to add a fixed value to the final scrambler number before adding it to the card number. If you added three to whatever else the calculation came up with, you'd still have knocked the card number off by something, even if your previous additions and multiplications came up zero. A few other notes on the process:

  • The card number is split up and then stuck back together because Hazel's Math tag flips like a cheese omlette when called upon to do calculations using a sixteen-digit number.
  • There are any number of numbers than could be used as the keys for the scrambler -- the customer's phone or zip code, the timestamp of the invoice, the card expiration date, etc. And, of course, you could add an "offline" variable as well. You might add one to the number for orders placed on Monday, two for Tuesday orders, etc, or do something similar with the day of the month.
  • Care should be taken to select a scrambling method that doesn't add or remove digits from the final result. (In order to prevent my scrambled card number from changing the length of a value, I truncate the results, taking the right-hand digits, for the calculations that might add a digit to length of a number.)
  • Also note that (unless I missed something) only the last five digits of the card can change using the technique shown. If something goes badly wrong, all you have to get from the customer is the last five digits of the number -- you'll have the rest of the original number. The customer will be more confident and trusting if he or she only has to give a partial number.
  • Bear in mind that anyone who could read the source code of your storeinvoice.txt template would, with a working knowledge of Hazel, be able to derive your scrambling procedure. As it normally hides in your Hazel-cat where the average web browser can't reach, this shouldn't be a problem. But it is something to be aware of.
  • Also note that most of the outliers that might screw things up -- a card number that started with two zeroes or 99, a card number that had a string of 999999 that might cause the length to change if you added a value to it, etc. shouldn't cause trouble for the code as written -- but it doesn't really matter because there are no card numbers with those characteristics -- at least that I know of.
 

(Note: I have deliberately omitted the leading % (percent sign) from the Hazel Tags in this paragraph so Hazel wouldn't actually try and present the values instead of the tag names.) What is shown here is a demo. In real life, you'd replace HZV_CREDTEST with HZE_CREDIT_CODE, and insert the calculation loops into your storeinvoice.txt template. Obviously, you would not display any of the interim values, but would merely show the results, formatted to make the card number look real. You'd remove the HZM_PAYMENT_INFO tag from your storeinvoice.txt template. That tag shows credit card info in this manner: "XXXXXXXXXXXXXXXX (type, expires XX/XXXX) issued to'cardholder name'." You would instead provide the information in the tags HZV_SCRAMBLED_CRED, HZE_CREDIT_MONTH, HZE_CREDIT_YEAR, HZE_CREDIT_TYPE, and HZE_CREDIT_NAME. Also just by the way, I used Hazel's fixed-width token feature to snag the bits of numbers. For a given variable HZx_Variant, (with x being any of the namespaces) HZx_nnR_Variant will show the last nn characters of the value of Variant. Use nnL to pick off digits from the front of the variable. For example, HZV_04L_Variant will show the first four characters of Variant. The number of digits must have a leading zero if it less than ten. See Fixed-Width Tokens in the Tokens section of the Hazel Online docs for more info.



Roger Allen