Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CreditCardValidator.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2011-2017 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.keywordsearch;
20
21import com.google.common.base.CharMatcher;
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.Range;
24import com.google.common.collect.RangeMap;
25import com.google.common.collect.TreeRangeMap;
26import java.util.Set;
27import org.apache.commons.lang3.StringUtils;
28import org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit;
29
43final class CreditCardValidator {
44
45 private CreditCardValidator() {
46 }
47
48 private static final LuhnCheckDigit CREDIT_CARD_NUM_LUHN_CHECK = new LuhnCheckDigit();
49
53 static private final RangeMap<Integer, Set<Integer>> allowedLengths = TreeRangeMap.create();
54 private static final ImmutableSet<Integer> Set12to19 = ImmutableSet.of(12, 13, 14, 15, 16, 17, 18, 19);
55 private static final ImmutableSet<Integer> Set14to19 = ImmutableSet.of(14, 15, 16, 17, 18, 19);
56 private static final ImmutableSet<Integer> Set16to19 = ImmutableSet.of(16, 17, 18, 29);
57
58 static {
59 //amex
60 allowedLengths.put(Range.closedOpen(34000000, 35000000), ImmutableSet.of(15));
61 allowedLengths.put(Range.closedOpen(37000000, 38000000), ImmutableSet.of(15));
62
63 //visa
64 allowedLengths.put(Range.closedOpen(40000000, 50000000), Set12to19);
65
66 //visa electron
67 allowedLengths.put(Range.closedOpen(40260000, 40270000), ImmutableSet.of(16));
68 allowedLengths.put(Range.closedOpen(41750000, 41750100), ImmutableSet.of(16));
69 allowedLengths.put(Range.closedOpen(44050000, 44060000), ImmutableSet.of(16));
70 allowedLengths.put(Range.closedOpen(45080000, 45090000), ImmutableSet.of(16));
71 allowedLengths.put(Range.closedOpen(48440000, 48450000), ImmutableSet.of(16));
72 allowedLengths.put(Range.closedOpen(49130000, 49140000), ImmutableSet.of(16));
73 allowedLengths.put(Range.closedOpen(49170000, 49180000), ImmutableSet.of(16));
74
75 //China UnionPay
76 allowedLengths.put(Range.closedOpen(62000000, 63000000), Set16to19);
77
78 //MasterCard
79 allowedLengths.put(Range.closedOpen(51000000, 56000000), ImmutableSet.of(16));
80 allowedLengths.put(Range.closedOpen(22210000, 27210000), ImmutableSet.of(16));
81
82 //Verve, these over lap with discover
83 allowedLengths.put(Range.closedOpen(50609900, 50619900), ImmutableSet.of(16, 19));
84 allowedLengths.put(Range.closedOpen(65000200, 65002700), ImmutableSet.of(16, 19));
85
86 //Maestro
87 allowedLengths.put(Range.closedOpen(50000000, 50100000), Set12to19);
88 allowedLengths.put(Range.closedOpen(56000000, 59000000), Set12to19);
89 allowedLengths.put(Range.closedOpen(60000000, 70000000), Set12to19);
90 allowedLengths.put(Range.closedOpen(63900000, 63910000), Set12to19);
91 allowedLengths.put(Range.closedOpen(67000000, 68000000), Set12to19);
92
93 //Diners Club International (processed by discover
94 allowedLengths.put(Range.closedOpen(30000000, 30600000), Set16to19);
95 allowedLengths.put(Range.closedOpen(30950000, 30960000), Set16to19);
96 allowedLengths.put(Range.closedOpen(36000000, 37000000), Set14to19);
97 allowedLengths.put(Range.closedOpen(38000000, 40000000), Set16to19);
98
99 //Diners Club USA & Canada (MasterCard co brand)
100 allowedLengths.put(Range.closedOpen(54000000, 56000000), Set14to19);
101
102 //Discover
103 allowedLengths.put(Range.closedOpen(60110000, 60120000), Set16to19);
104 allowedLengths.put(Range.closedOpen(62212600, 62292600), Set16to19);
105 allowedLengths.put(Range.closedOpen(64400000, 66000000), Set16to19);
106
107 //JCB //process by discover
108 allowedLengths.put(Range.closedOpen(35280000, 35900000), Set16to19);
109
110 //Dankort
111 allowedLengths.put(Range.closedOpen(50190000, 50200000), Set16to19);
112
113 //InterPayment
114 allowedLengths.put(Range.closedOpen(63600000, 63700000), Set16to19);
115 }
116
127 static public boolean isValidCCN(String rawCCN) {
128 //check for a valid separator
129 boolean hasSpace = StringUtils.contains(rawCCN, ' ');
130 boolean hasDash = StringUtils.contains(rawCCN, '-');
131 if (hasSpace && hasDash) {
132 return false; //can only have dashes or spaces, not both.
133 }
134
135 Character separator = null;
136 if (hasSpace) {
137 separator = ' ';
138 } else if (hasDash) {
139 separator = '-';
140 }
141
142 final String cannonicalCCN;
143 String[] splitCCN;
144 if (separator != null) {
145 //there is a seperator, strip if for canoncial form of CCN
146 cannonicalCCN = CharMatcher.anyOf(separator.toString()).removeFrom(rawCCN);
147 splitCCN = rawCCN.split(separator.toString());
148 } else {
149 //else use 'defualt'values
150 cannonicalCCN = rawCCN;
151 splitCCN = new String[]{cannonicalCCN};
152 }
153
154 if (false == lengthMatchesBin(cannonicalCCN)) {
155 return false;
156 }
157
158 // validate digit grouping for 15, 16, and 19 digit cards
159 switch (cannonicalCCN.length()) {
160 case 15:
161 if (false == isValid15DigitGrouping(splitCCN)) {
162 return false;
163 }
164 break;
165 case 16:
166 if (false == isValid16DigitGrouping(splitCCN)) {
167 return false;
168 }
169 break;
170 case 19:
171 if (false == isValid19DigitGrouping(splitCCN)) {
172 return false;
173 }
174 break;
175 default:
176 if (false == isValidOtherDigitGrouping(splitCCN)) {
177 return false;
178 }
179 }
180
181 return CREDIT_CARD_NUM_LUHN_CHECK.isValid(cannonicalCCN);
182 }
183
184 static private boolean lengthMatchesBin(String cannonicalCCN) {
185 String BIN = cannonicalCCN.substring(0, 8);
186 final Set<Integer> lengthsForBIN = allowedLengths.get(Integer.valueOf(BIN));
187 return null == lengthsForBIN || lengthsForBIN.contains(cannonicalCCN.length());
188 }
189
190 static private boolean isValidOtherDigitGrouping(String[] splitCCN) {
191 if (splitCCN.length == 1) {
192 return true;
193 } else {
194 return splitCCN[0].length() == 4;
195 }
196 }
197
198 static private boolean isValid19DigitGrouping(String[] splitCCN) {
199 switch (splitCCN.length) {
200 case 1:
201 return true;
202 case 2:
203 return splitCCN[0].length() == 6
204 && splitCCN[1].length() == 13;
205 case 5:
206 return splitCCN[0].length() == 4
207 && splitCCN[1].length() == 4
208 && splitCCN[2].length() == 4
209 && splitCCN[3].length() == 4
210 && splitCCN[4].length() == 3;
211 default:
212 return false;
213 }
214 }
215
216 static private boolean isValid16DigitGrouping(String[] splitCCN) {
217 switch (splitCCN.length) {
218 case 1:
219 return true;
220 case 4:
221 return splitCCN[0].length() == 4
222 && splitCCN[1].length() == 4
223 && splitCCN[2].length() == 4
224 && splitCCN[3].length() == 4;
225 default:
226 return false;
227 }
228 }
229
230 static private boolean isValid15DigitGrouping(String[] splitCCN) {
231 switch (splitCCN.length) {
232 case 1:
233 return true;
234 case 3:
235 return (splitCCN[0].length() == 4 && splitCCN[1].length() == 6 && splitCCN[2].length() == 5);
236// UATP || ((splitCCN[0].length() == 4 && splitCCN[1].length() == 5 && splitCCN[2].length() == 6));
237 default:
238 return false;
239 }
240 }
241}

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.