Can I calculate the CVV from the 3 credit card track data? When I scan a card, there is no CVV, just the number, name and service numbers that don't relate to anything else.
-
4That is somewhat the point of the CVV: that it is not in the magstripe. – Mitch Dec 24 '15 at 17:34
2 Answers
The CVV that is on the mag stripe is actually a CVC1 code, which only attempts to verify that the mag stripe details have not been tampered/corrupted. It is not the same as, nor has any relevance to the CVV code printed onto the back of the card (which is formally known as a CVC2 code.
The CVC2 that is printed onto the back of the card is (by design) intended to be viewed with eyes only, and not machine readable.
More reading : https://randomoracle.wordpress.com/2012/08/25/cvv1-cvv2-cvv3-demystifying-credit-card-data-12/

- 13,871
- 9
- 56
- 78
You need two DES keys(CVK's), card no, service code, expiry to generate CVV.
CVV = Fun(CVK1, CVK2, card_no, service_code, expiry_YYMM);
There are three CVV's
CVV1 : in magnetic stripe CVV2 : back of card ICVD : in chip data
Service Code for each CVV differs
Service code for CVV1 : differs according to card type and usage Service code for CVV2 : 000 Service code for ICVD : 999*
I have implemented following CVV generation algorithm
private static final char[] decTable = "0123456789012345".toCharArray();
private static final int hexToByte(char ch) {
if ('0' <= ch && ch <= '9') return ch - '0';
if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
return -1;
}
/**
* @param cvk1 : card verification key1
* @param cvk2 : card verification key1
* @param pan : Account No
* @param svc : Service code CVV1(000), ICVV(999), CVV2(custom)
* @param expiry : Expiry date in YYMM format
* @return : CVV
*/
public static final String calculateCVV(final String cvk1, final String cvk2, final String pan, final String svc, final String expiry) {
String input = Strings.padRight(new StringBuilder().append(pan).append(expiry).append(svc), '0', 32);
String data1 = input.substring(0, 16);
String data2 = input.substring(16);
String d1 = DES.encrypt(data1, cvk1, null, MODE.ECB, PADDING.NoPadding);
String d2 = ByteHexUtil.byteToHex(ByteHexUtil.xor(ByteHexUtil.hexToByte(d1), ByteHexUtil.hexToByte(data2)));
String d3 = TripleDES.encrypt(d2, cvk1 + cvk2, null, MODE.ECB, PADDING.NoPadding);
return Decimalizer.decimalizeDigitsFirst(d3, 3);
}
//This method takes a encrypted value(hexadecimal string) as input, scans for digits[0-9] and selects them to form cvv. If the no of digits in input hexadecimal string is less than outLen the it starts scan(excluding previously selected digits) from beginning and converts hexadecimal[A-F] characters to digits using decimalization table.
public static final String decimalizeDigitsFirst(String data, final int outLen) {
StringBuilder selected = new StringBuilder(outLen);
int selectionCounter = 0;
int len = data.length();
for(int i=0; i<len && selectionCounter < outLen ; i++){
if(hexToByte(data.charAt(i)) < 10) {
selected.append(data.charAt(i));
selectionCounter++;
}
}
if(selectionCounter !=2) {
for(int i=0; i<len && selectionCounter < outLen ; i++){
if(hexToByte(data.charAt(i)) > 9) {
selected.append(decTable[hexToByte(data.charAt(i))]);
selectionCounter++;
}
}
}
return selected.toString();
}
Test Vectors
String CVK1 = "F40157F249232FCE";
String CVK2 = "7CE6C8CB9E8683EC";
String EXP_YYMM = "2005";
String SVC = "520";
String PAN = "4263970000005262";
String CVV = calculateCVV(CVK1, CVK2, PAN, SVC, EXP_YYMM);
EXPECTED CVV OUTPUT : 782
The output of above function is matched with output of Thales 9000 HSM with the same data. The above mentioned decimalization table is used.

- 425
- 4
- 14
-
what is **decTable** in **selected.append(decTable[hexToByte(data.charAt(i))]);** ? – koding Jan 03 '20 at 13:19
-
1@koding primary purpose of decimalization table is to map hexadecimal character value to some decimal character value. I have updated answer with sample decimalization table we usually use. The Card Issuer can also use decimalization table to randomize the CVV. – krishna T Jan 03 '20 at 14:34
-
-
@koding I have added context to the decimalizeDigitsFirst method. The Implementation is tested OK by comparing its output to Thales PayShield 9000 HSM output with small set of test vectors. I am planning to test it with different set of decimalization tables and large set of test vectors. I will let you know the results here once available. – krishna T Jan 03 '20 at 14:49
-
-
Brother, can you add example of input of cvk1, cvk2, pan, svc, expiry and result of cvv to test if that functions is worked as expected. Thanks – koding Jan 08 '20 at 23:45
-
-
@koding Earlier i said organization can choose decimalization table which is wrong. The decimalization table is fixed for cvv generation algorithm(0123456789012345). – krishna T Jan 10 '20 at 09:20
-
I get that result similiar with your test vector, I change d2 to 8 bytes. Thanks brother – koding Jan 10 '20 at 17:41