Image of Navigational Map linked to Home / Contents / Search Validating Credit Card Numbers

by Jim Karabatsos - GUI Computing
Image of Line Break

If your application needs to input credit card numbers, then you may want to have your input validated to ensure that the operator is alerted when an invalid credit card number is entered.

All credit cards use a simple but effective checksum algorithm that ensures that data is input correctly. This scheme is not foolproof (not by a long shot) but it does protect against the most common types of errors that are encountered during entry of these numbers. In particular, it will correctly detect a wrong digit, or a transposed pair of digits. If the checksum is correct, you have a 90% degree of confidence that the data was entered correctly.

Not all credit card numbers are the same length. Most cards use 16 digits but some use more or less; for example, American Express uses 15 digits. The algorithm caters for different-length card numbers.

Let's look at the code for a validation function - which is, as usual, available for download. This function accepts a credit card number as it might be entered into an edit control, so it uses a string parameter. It returns a boolean result, True for a valid card number and False otherwise.

Public Function IsValidCreditCardNumber(ByVal sCardNo As String) As Boolean

	Const MAX_DIGITS = 20  ' actually don't know any card using more than 16 digits

	Dim anDigits(1 To MAX_DIGITS) As Byte  
	Dim nDigits As Long

	Dim ofsCurrentDigit As Long
	Dim ofsCurrentCharacter As Long

	Dim CurrentCharacter As String

	Dim Multiplier As Long
	Dim CheckSum As Long
	Dim DigitValue As Long

	Dim ValidDigits As String

	If Len(Trim$(sCardNo)) < 1 Then
	  Result = False
	  GoTo Exit_Point
	End If

	ValidDigits = "0123456789"

	For ofsCurrentCharacter = 1 To Len(sCardNo)
	  CurrentCharacter = Mid$(sCardNo, ofsCurrentCharacter, 1)
	  If InStr(1, ValidDigits, CurrentCharacter, vbBinaryCompare) Then
		 nDigits = nDigits + 1
		 If nDigits > MAX_DIGITS Then
			Result = False
			Goto Exit_Point
		 End If
		 anDigits(nDigits) = Val(CurrentCharacter)
	  End If
	Next ofsCurrentCharacter

	CheckSum = anDigits(nDigits)

	For ofsCurrentDigit = nDigits - 1 To 1 Step -1

	  If Multiplier = 2 Then
		 Multiplier = 1
		 Multiplier = 2
	  End If
		  DigitValue = anDigits(ofsCurrentDigit) * Multiplier
		  CheckSum = CheckSum + DigitValue
		  If DigitValue > 9 Then
		 CheckSum = CheckSum - 9
	  End If

	Next ofsCurrentDigit

	Result = ((CheckSum Mod 10) = 0)


	IsValidCreditCardNumber = Result
	Exit Function

End Function

The function needs to strip any non-digit characters from the input string. Many people, when asked to input a credit card number, will input spaces or hyphens to match the spacing on the card. The spaces are not significant -- logically, a credit card number is just a string of digits. The validation logic presented here will strip all non-numerics to obtain the credit card number. You may prefer to enforce a more rigid scheme where you will reject any non-numeric input, or accept only digits, spaces and hyphens.

As it has to examine each character anyway, the function uses the opportunity to convert each valid character into an integral value (a Byte, actually) and stores them into an array. It also counts how many digits were found, because it needs to walk through the number backwards so it needs to know where to start from.

When the string has been parsed into digits, we are ready to start. The LAST digit is the checksum. It is generated by the software at the credit card company to make the sum come out right. We start of by initialising the Checksum to this digit. If the card is valid, the checksum will end up being an exact multiple of 10.

We derive the checksum by starting with the value of the last digit, unchanged. We then work BACKWARDS from the digit immediately before the checksum to the first digit. For each digit, we work out a value, which is the digit multiplied by either 2 or 1. We alternate the multiplier, starting with 2 for the digit before the checksum, then 1 for the digit before that, then back to 2 and so on. We take the value of the digit and multiply it by the multiplier. If the result is > 9, we subtract 9. Then we add it into the Checksum. This continues back to the first digit.

When we are done, we simply check whether the checksum is an exact multiple of 10 (using the MOD operator). If it is, then the card number is valid; otherwise it is not.

You can use the function above as-is, but if you want to understand, we can work through this example:
Card Number : 1234 5678 9012 3456
Multiplier: 2121 2121 2121 212
Value: 2264 1658 9022 641 <- Sum = 58

The value is worked out by multiplying the digit by the multiplier. If the multpilication results in a two-digit number, then you subtract 9 to get the value (as we did for the digits highlighted with asterisks). Note that we started the multiplier with 2 at the last non-checksum digit, so that for this 16-digit number the multiplier for the first digit is also 2. For 15-digit numbers like American Express, the multiplier for the first digit is 1, so it is important to always start at the end as shown.

If we add all the values, we come up with 58. Adding in the check digit (6) gives us 64, which is NOT evenly divisible by 10, meaning that this is not a valid credit card number. The check digit would need to be a 2 in order for this card number to be valid.

Pop Quiz

The prize for the first correct answer only is a box of smarties: The algorithm, as presented, is correct and in accurately models the way the algorithm works. However, it can be somewhat simplified if we make one small and valid generalisation. Can you see it? The performance benefits would be all but non-existent, so don't stress it.

Written by: Jim Karabatsos

Image of Arrow linked to Previous Article Image of Arrow linked to Next Article
Image of Line Break