Home
> Uncategorized > Creating Fake Credit Card Numbers in c#
Creating Fake Credit Card Numbers in c#
I recently had to create a credit card number generator, nothing nefarious, just we needed unique valid credit card numbers after asking on StackOverflow and getting a less than stellar response (for the first time). I came across something on DarkCoding.Net which did exactly what I wanted but was in Java, I’ve ported it over to c# and I hope you find it useful
Update
I recently rewrote this code. removing a couple of bugs and making it a bit more c# and bit less Java
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace CreditCardNumberGenerator
{
public class RandomCreditCardNumberGenerator
{
/*This is a port of the port of of the Javascript credit card number generator now in C#
* by Kev Hunter http://kevhunter.wordpress.com
* See the license below. Obviously, this is not a Javascript credit card number
generator. However, The following class is a port of a Javascript credit card
number generator.
@author robweber
Javascript credit card number generator Copyright (C) 2006 Graham King
graham@darkcoding.net
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
www.darkcoding.net
*/
public static string[] AMEX_PREFIX_LIST = new[] {"34", "37"};
public static string[] DINERS_PREFIX_LIST = new[]
{
"300",
"301", "302", "303", "36", "38"
};
public static string[] DISCOVER_PREFIX_LIST = new[] {"6011"};
public static string[] ENROUTE_PREFIX_LIST = new[]
{
"2014",
"2149"
};
public static string[] JCB_15_PREFIX_LIST = new[]
{
"2100",
"1800"
};
public static string[] JCB_16_PREFIX_LIST = new[]
{
"3088",
"3096", "3112", "3158", "3337", "3528"
};
public static string[] MASTERCARD_PREFIX_LIST = new[]
{
"51",
"52", "53", "54", "55"
};
public static string[] VISA_PREFIX_LIST = new[]
{
"4539",
"4556", "4916", "4532", "4929", "40240071", "4485", "4716", "4"
};
public static string[] VOYAGER_PREFIX_LIST = new[] {"8699"};
/*
'prefix' is the start of the CC number as a string, any number
private of digits 'length' is the length of the CC number to generate.
* Typically 13 or 16
*/
private static string CreateFakeCreditCardNumber(string prefix, int length)
{
string ccnumber = prefix;
while (ccnumber.Length < (length - 1))
{
double rnd = (new Random().NextDouble()*1.0f - 0f);
ccnumber += Math.Floor(rnd*10);
//sleep so we get a different seed
Thread.Sleep(20);
}
// reverse number and convert to int
var reversedCCnumberstring = ccnumber.ToCharArray().Reverse();
var reversedCCnumberList = reversedCCnumberstring.Select(c => Convert.ToInt32(c.ToString()));
// calculate sum
int sum = 0;
int pos = 0;
int[] reversedCCnumber = reversedCCnumberList.ToArray();
while (pos < length - 1)
{
int odd = reversedCCnumber[pos]*2;
if (odd > 9)
odd -= 9;
sum += odd;
if (pos != (length - 2))
sum += reversedCCnumber[pos + 1];
pos += 2;
}
// calculate check digit
int checkdigit =
Convert.ToInt32((Math.Floor((decimal) sum/10) + 1)*10 - sum)%10;
ccnumber += checkdigit;
return ccnumber;
}
public static IEnumerable<string> GetCreditCardNumbers(string[] prefixList, int length,
int howMany)
{
var result = new Stack<string>();
for (int i = 0; i < howMany; i++)
{
int randomPrefix = new Random().Next(0, prefixList.Length - 1);
if(randomPrefix>1)
{
randomPrefix--;
}
string ccnumber = prefixList[randomPrefix];
result.Push(CreateFakeCreditCardNumber(ccnumber, length));
}
return result;
}
public static IEnumerable<string> GenerateMasterCardNumbers(int howMany)
{
return GetCreditCardNumbers(MASTERCARD_PREFIX_LIST, 16, howMany);
}
public static string GenerateMasterCardNumber()
{
return GetCreditCardNumbers(MASTERCARD_PREFIX_LIST, 16, 1).First();
}
public static bool IsValidCreditCardNumber(string creditCardNumber)
{
try
{
var reversedNumber = creditCardNumber.ToCharArray().Reverse();
int mod10Count = 0;
for (int i = 0; i < reversedNumber.Count(); i++)
{
int augend = Convert.ToInt32(reversedNumber.ElementAt(i).ToString());
if (((i + 1)%2) == 0)
{
string productstring = (augend*2).ToString();
augend = 0;
for (int j = 0; j < productstring.Length; j++)
{
augend += Convert.ToInt32(productstring.ElementAt(j).ToString());
}
}
mod10Count += augend;
}
if ((mod10Count%10) == 0)
{
return true;
}
}
catch
{
return false;
}
return false;
}
}
}
Categories: Uncategorized
Hi Kev!
I’m also using this “generator”, although I have a major problem with it: we are running automated tests a lot of times, and we definitely need _unique_ numbers, but this algorithm seems to generate duplicates very often.
I haven’t really debugged the code, maybe if you have any immediate proposal how to enhance this piece of code – that would be brilliant.
If you have no time or mood, obviously I’ll do the debugging myself, just wanted to let you know about my comments
Regards,
Zoltan
Hi Zoltan,
within the same session should be very easy, at least to give the appearance of uniqueness you could just use the Linq Distinct() statement on the GetCreditCardNumbers() method. This would mean you would only get unique records back, if you need unique numbers across sessions you’ll probably have to insert them into a database or something similar.
If there are lots of duplicates it may well be to with the random code in lines 80 to 90 in the code sample above.
hope this helps
Kev
Hi Kev,
Unfortunately using a DB for this is not an option for us.
So I did my homework and found the following quick solution:
[...]
private static string CreateFakeCreditCardNumber(string prefix, int length)
{
//sleep so we get a different seed if called multiple times
Thread.Sleep(20);
string ccnumber = prefix;
Random rndGen = new Random();
while (ccnumber.Length < (length – 1))
{
double rnd = (rndGen.NextDouble() * 1.0f – 0f);
ccnumber += Math.Floor(rnd * 10);
}
[...]
This modification is anyway better coding (result: faster generation), you don't need to recreate Random() if you are using it in the same static function.
Relocation of the "Sleep" is needed so we indeed use a different seed while creating multiple CC numbers.
Self-criticism: I particularly don't like the position of Sleep() in my solution, I hate to waste 20ms, even if it's only in the first cycle. So for those tick-maniac, move Sleep() here (in this case, you will HAVE to use *Numbers() method instead of *Number()):
[..]
public static IEnumerable GetCreditCardNumbers(string[] prefixList, int length, int howMany)
[..]
result.Push(CreateFakeCreditCardNumber(ccnumber, length));
//sleep so we get a different seed in CreateFakeCreditCardNumber()
Thread.Sleep(20);
[..]
Ideal solution OO-wise would be to change the structure and force the user to create a new instance of this class (like in case of system Random and call Next() to get new CC number), but I like your simple “static” interface, so I guess this is OK like this
Keep up the great work and sorry for the long “comment”, I hope you like it!
Regards,
Zoltan
I couldn’t agree more about the Thread.Sleep in the code, never feels right..
The whole class could be made much nicer, its a pretty flat copy from the existing java solution Graham King has on his site, we needed something fairly quick for generating credit cards for when I was writing tests, and this is what I came up with.
Glad you found it useful
Kev