Luhn algorithm and why it makes CC number DLP a reality.
Mark Osborne
CISO, Mentor, Security Advisor, Issue Resolver and Foundational advocate for the Cyber-security Industry
Introduction
With PCIDSS 4 dead-lines approaching, I figured it was time to ?revisit some of the basics of CC payments. ??If you work in the real-world you will know that without autoclassification, training and buckets of management support, that? cost effective DLP has been a pipe dream for the small FinTech.
Why? How does a simple text search program detect the difference between a bank sort-code and a date of birth, or ?a telephone-number v’s a bank account number*. Answer = they dont, they have no context.? We all know that these false positives from a DLP system takes an army to deal with.? Yes, good machine learning has been about in the top flight products to reduce that flood. But there is still a long way to go before a challenger fintech can utilise it. The detection success rate needs to go up and the staffing maintenance requirements needs to come down. ?Most of these firms will have 1000 or 2000 employees with a security team no bigger than a dozen (probably half that ). They wont keep pace.
The credit card number
Obviously, the credit card number, known as the Primary Account Number( PAN) is the long number on your card. It, as a detectable immutable datatype, has always been an exception.? The designers created it with a structured format that ?can be verified by a checksum algorithm. In my experience, if the reserved nature of the Luhn algorithm is observed, DLP can be enabled on that field with 5 nines accuracy and minimal staffing overhead.? Very few data types offer that advantage.
To comply with payment industry standards storage of PANs needs to be controlled and restricted, so this attribute is great.? Even if you use tokenisation, you need to demonstrate those peskie Pans don’t sneak in somewhere.
?
PANS ARE ALL 16 Digits Long.
Its amazing what experts say, I got told it the other day.? I am not a payments systems expert but even I know that’s cods-wallop.? Card# are usually 16 digits long – but I have seen them much shorter, 14 characters is not uncommon. ?I think have seen 19 characters but my memory isn’t perfect and that is certainly not a use case we need to worry about.
In this article, we will assume that a credit? card number:
THE LUHN ALGORITHM – How it works
The algorithm is based on Modulo ten ( divisible by 10 ) and divides the card digits into 2 groups. These are treated in a different? manner. The offset of the two groups is shown below.
const grp1 = [ 14, 12, 10, 8, 6, 4, 2, 0 ]
const grp2 = [ 15, 13, 11, 9, 7, 5, 3, 1 ]
I have used a “Discover” test card number as it demonstrated less entropy 6011000990139424 than other test card numbers and because I don’t have any relationship with that particular player. The table below shows how the card can be dissected into the two groups.
????????????????????? ?
?
The group2 digits are just added together as shown below:
Group 1 digits require a more complex treatment, but it is hardly at the complexity of elliptic curve encryption.
This is shown below:
Lastly, we take the Group1 total and the Group2 total and them together
????????????????? 21+ 29 = 50
Any valid PAN will have a least significant digit equal to zero. Simples.
This is a valid PAN
Pro's & Con's
?Just like Paddington bear and Bertie Wooster, lets review the +ves and -ves:
* It is possible to input validate some UK current accounts numbers. There are currently 3 modulo calculations with nearly 20 exceptions for current accounts - these don't cover all building society accounts and other specialist accounts that may be capable of direct payment methods. Many international account bank numbers differ or have no validation at all. This doesn't lend it selve to "bank account number detection" within a real-time dlp system without back-end post processing.
Example Code
I write code on Linked-in because other don’t, cant and prefer pictures of kittens
?
// Code starts
<htmL>
<body>
? <p id="demo1">>>></p>
? <h1> JAVASCRIPT Credit Card Pan validator </h1>
? <p>This little program validates the Credit Card PAN using the Luhn Alogrithm.
??? There are better Web based tools but this shows the working for a 16digit Pan.
? </p>
?
? <br>
? <hr>
? <form name="myForm" action="" method="GET">
??? Enter a 16digit Pan in the box: <br> <br>
??? <input type="text" name="inputbox" value="">
??? <input type="button" name="button" value="Click" onClick="getResults(this.form)">
? </form>
?<hr>
?<b><p id="grp1">? <br>?????????????????????? </p>
?<p id="grp2">???????? <br>???????????? ???????????</p>
?<p id="tot">????????????? <br>?????? ???????????????</p>
?<p>If the? Total shown above is divisible by 10 (modulo 10) then it has passed the cc checksum
?
?</p></b>
?<p id="verdict">???????????????????????? </p>
?<p id="maskedpan">???????????????????????? </p>
领英推荐
<script>
arrayx= []
var fff = " "
const grp1 = [ 14, 12, 10, 8, 6, 4, 2, 0 ]
const grp2 = [ 15, 13, 11, 9, 7, 5, 3, 1 ]
function getResults (form) {
? var ccPan = form.inputbox.value;
? var grp1Tot = 0
? var grp2Tot = 0
? console.log(ccPan.length)
? console.log(ccPan)
? arrayx= [...ccPan]
? // alert ("You typed: " + ccPan); Removed at Alex's request
? grp1Tot = doGrp1(ccPan)
? document.getElementById("grp1").innerHTML = "<b> Group 1 total: "? +? grp1Tot + "</b>"
? console.log( " Group 1 total "? +? grp1Tot)??
? grp2Tot = doGrp2(ccPan)
? document.getElementById("grp2").innerHTML =? " Group 2 total "? +? grp2Tot
? console.log( " Group 2 total "? +? grp2Tot)
?
? document.getElementById("tot").innerHTML = " Total ( (Group 2 + Group 1) = " +? ( grp2Tot +? grp1Tot)?
? console.log( " Total ( (Group 2 + Group 1) = "? +? ( grp2Tot +? grp1Tot)? )
? if (???? (( grp2Tot +? grp1Tot) %? 10 ) === 0 )
??? {
???? document.getElementById("verdict").innerHTML = "valid pan? "
???? console.log( " valid pan? "? )
??? } else
??? {
???? console.log( " invalid pan? "? )
???? document.getElementById("verdict").innerHTML = " invalid pan? "
??? }?
? ?document.getElementById("maskedpan").innerHTML =? " Masked Pan:"? +
?? ccPan.slice(0,5) + "XXXXXX" + ccPan.slice(12, )
? }
function addmgrp1(num1){
? if ( num1*2 < 10 )? {
??? return (num1*2)
? } else
? {
??? var temp = ( ( num1 2 ) % 10 ) +? Math.floor(num1 2 / 10 )
??? return(temp)
? }
}
function doGrp1(ccPan){
? var Tot =0 ;
? arrayx= [...ccPan]
? for ( let n= 14 ; n > -1? ; n = n - 2 ){
???? console.log( "index " + n + " cc digit " + arrayx[n] + " *2 = " + addmgrp1(arrayx[n] ))
???? Tot += addmgrp1(arrayx[n]? )
??? }
? return(Tot)
? }
function doGrp2(ccPan)
? {
? var Tot=0;
? arrayx= [...ccPan]
? for ( let n= 15 ; n > 0? ; n = n - 2 ){
??? Tot += parseInt(arrayx[n]? )
??? console.log( " Group 2 inx " + n + " " + parseInt(arrayx[n] ) +? " = " +? Tot )
???? }
? return(Tot)
?}
</script>
</body>
</htm>
!!! end of snip
Group Chief Information Security Officer at Qatar National Bank at QNB Group
11 个月You realise your code is vulnerable to XSS ?????? no input validation ?? alert ("You typed: " + ccPan); ??
Thanks for the code! I'll have a play with this. I think there's something missing at the end...