Skip to content

Instantly share code, notes, and snippets.

@bryanhunter
Created August 8, 2012 17:20
Show Gist options
  • Save bryanhunter/3296790 to your computer and use it in GitHub Desktop.
Save bryanhunter/3296790 to your computer and use it in GitHub Desktop.
Testing idea of using sum of card numbers as security question
Based on Twitter conversation with @b6n
*Question 1*
The digits in the credit card pattern 4811 XXXX XXXX 2632 sum to 77, what are the
middle 8?There are 112,400 card numbers (about 1.2%) in this range that 1) pass
the luhn check and 2) sum to 77. The credit card isn't in great danger.
*Question 2*Does the sum of the card digits make a good security question for
phone support?The first hurdle is having a customer add the 16 digits without
miss-adding or freaking out. Next, the numbers do cluster to the middle. A bad
guy who knew the card met the pattern 4811 XXXX XXXX 2632 could create a
histogram and have a 4.8% chance of guessing the sum. In your case where 77 is
the sum you would be pretty safe. If given three attempts before alarm bells,
only a bad gambler would go outside of 61, 62, 63. Of course, if you were one of
14.4% of the population with a card sum falling in that range (61,62,63) you
wouldn't be too happy with this scheme. You would become an albino rabbit.
Sum Freq Prob
29 16 0.000%
30 20 0.000%
33 16 0.000%
34 312 0.003%
35 1040 0.010%
36 1960 0.020%
37 2400 0.024%
38 2496 0.025%
39 3680 0.037%
40 6740 0.067%
41 11200 0.112%
42 16804 0.168%
43 23568 0.236%
44 32248 0.322%
45 42960 0.430%
46 57040 0.570%
47 73888 0.739%
48 96128 0.961%
49 119344 1.193%
50 142040 1.420%
51 164960 1.650%
52 197300 1.973%
53 233856 2.339%
54 270104 2.701%
55 304800 3.048%
56 343220 3.432%
57 375472 3.755%
58 403340 4.033%
59 430848 4.308%
60 459520 4.595%
61 474320 4.743%
62 481156 4.812% <- Best guess
63 478464 4.785%
64 472500 4.725%
65 460000 4.600%
66 449820 4.498%
67 430016 4.300%
68 404452 4.045%
69 372992 3.730%
70 341740 3.417%
71 305760 3.058%
72 272732 2.727%
73 241152 2.412%
74 207876 2.079%
75 170960 1.710%
76 139140 1.391%
77 112400 1.124% <- Not in the running
78 90484 0.905%
79 72000 0.720%
80 57580 0.576%
81 43280 0.433%
82 31448 0.314%
83 22544 0.225%
84 16820 0.168%
85 12240 0.122%
86 8820 0.088%
87 5824 0.058%
88 3100 0.031%
89 1120 0.011%
90 360 0.004%
91 480 0.005%
92 560 0.006%
93 400 0.004%
94 140 0.001%
-module(luhnfun).
-export([find_matching_cards/0, calc_best_guesses_for_sum/0]).
% Slapped together to test credit cards in the range 4811xxxxxxxx2632
% -- public
find_matching_cards() ->
{ok, IoDevice} = file:open("cards.txt", write),
Logger = fun(Message) -> io:format(IoDevice, "~s\r\n", [Message]) end,
[test_card(X, Logger) || X <- lists:seq(0, 99999999)],
file:close(IoDevice).
calc_best_guesses_for_sum() ->
D1 = orddict:new(),
D2 = lists:foldl(fun(Middle8, Dict) -> tally_hits(Dict, Middle8) end,
D1, lists:seq(0,99999999)),
List = orddict:to_list(D2),
[io:format("Sum: ~p, Frequency: ~p ~n", [Key, Value]) || {Key, Value} <- List ].
% -- private
test_card(Middle8, Logger) ->
CardNumber = lists:flatten(io_lib:format("4811~8..0B2632", [Middle8])),
case validate(CardNumber) of
true ->
Logger(CardNumber),
hit;
_ -> miss
end.
tally_hits(Dict, Middle8) ->
CardNumber = lists:flatten(io_lib:format("4811~8..0B2632", [Middle8])),
case is_luhn(CardNumber) of
true ->
Key = lists:sum([X-48 || X <- CardNumber]),
orddict:update_counter(Key, 1, Dict);
_ ->
Dict
end.
validate(CardNumber) ->
sum_check(CardNumber, 77) andalso is_luhn(CardNumber).
is_luhn(CardNumber) ->
[Checksum|Numbers] = [X -48 || X <- lists:reverse(CardNumber)],
Sum = luhn_sum(Numbers, 0, false),
(Sum + Checksum) rem 10 == 0.
luhn_sum([], RunningSum, _) ->
RunningSum;
luhn_sum([H|T], RunningSum, IsEven) when IsEven == true ->
luhn_sum(T, RunningSum + H, not IsEven);
luhn_sum([H|T], RunningSum, IsEven) ->
Add = case H < 5 of
true -> H * 2;
false -> H * 2 -9
end,
luhn_sum(T, RunningSum + Add, not IsEven).
sum_check(CardNumber, MagicSum) ->
MagicSum == lists:sum([X-48 || X <- CardNumber]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment