Autopsy  4.20.0
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  */
19 package org.sleuthkit.autopsy.keywordsearch;
20 
21 import com.google.common.base.CharMatcher;
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.Range;
24 import com.google.common.collect.RangeMap;
25 import com.google.common.collect.TreeRangeMap;
26 import java.util.Set;
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit;
29 
43 final 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-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.