● Notice //GitHub (@shehzade) is temporarily suspended pending an automated false-positive review. All tools are hosted on this Code Mirror and available on request (contact); GitHub links will return once reinstated.
PUBLIC MIRRORGo v1.0

Multi-protocol network egress assessment and DLP verification framework featuring automated L4 sweeps, corporate proxy traversal, and covert protocol smuggling across 20+ channels.

$ git clone https://shehzade.io/repos/contraband.git Copy
Source ZIP (1.93 MB)
Code 174 Commits 1
contraband / pkg / client / dlp / credit_card.go
← Back to directory
230 lines · 5.6 KB
Raw
1package dlp
2
3import (
4 "fmt"
5 "math/rand"
6 "strconv"
7 "strings"
8 "time"
9)
10
11type CardBrand string
12
13const (
14 BrandVisa CardBrand = "visa"
15 BrandMasterCard CardBrand = "mastercard"
16 BrandAmex CardBrand = "amex"
17 BrandDiscover CardBrand = "discover"
18 BrandDiners CardBrand = "diners"
19 BrandJCB CardBrand = "jcb"
20)
21
22type FormatStyle string
23
24const (
25 FormatRaw FormatStyle = "raw"
26 FormatHyphenated FormatStyle = "hyphenated"
27 FormatSpaceDelimited FormatStyle = "space"
28)
29
30type CreditCard struct {
31 Brand CardBrand `json:"brand"`
32 Number string `json:"number"`
33 Formatted string `json:"formatted"`
34 ExpMonth int `json:"exp_month"`
35 ExpYear int `json:"exp_year"`
36 CVV string `json:"cvv"`
37 CardholderName string `json:"cardholder_name"`
38}
39
40// ValidateLuhn validates any numeric string against Luhn mod-10.
41func ValidateLuhn(number string) bool {
42 var digits []int
43 for _, r := range number {
44 if r >= '0' && r <= '9' {
45 digits = append(digits, int(r-'0'))
46 } else if r == ' ' || r == '-' {
47 continue
48 } else {
49 return false
50 }
51 }
52 if len(digits) < 2 {
53 return false
54 }
55 sum := 0
56 alt := false
57 for i := len(digits) - 1; i >= 0; i-- {
58 d := digits[i]
59 if alt {
60 d *= 2
61 if d > 9 {
62 d -= 9
63 }
64 }
65 sum += d
66 alt = !alt
67 }
68 return sum%10 == 0
69}
70
71// GenerateLuhnCheckDigit computes the single check digit for a given prefix.
72func GenerateLuhnCheckDigit(prefix string) (int, error) {
73 var digits []int
74 for _, r := range prefix {
75 if r >= '0' && r <= '9' {
76 digits = append(digits, int(r-'0'))
77 } else {
78 return 0, fmt.Errorf("invalid character in card prefix: %c", r)
79 }
80 }
81 sum := 0
82 alt := true
83 for i := len(digits) - 1; i >= 0; i-- {
84 d := digits[i]
85 if alt {
86 d *= 2
87 if d > 9 {
88 d -= 9
89 }
90 }
91 sum += d
92 alt = !alt
93 }
94 return (10 - (sum % 10)) % 10, nil
95}
96
97// GenerateCreditCard generates a fully valid CreditCard struct.
98func GenerateCreditCard(brand CardBrand, r *rand.Rand, style FormatStyle) (CreditCard, error) {
99 var prefix string
100 var length int
101
102 switch brand {
103 case BrandVisa:
104 prefix = "4"
105 length = 16
106 case BrandMasterCard:
107 if r.Intn(2) == 0 {
108 prefix = strconv.Itoa(51 + r.Intn(5)) // 51-55
109 } else {
110 prefix = strconv.Itoa(2221 + r.Intn(500)) // 2221-2720
111 }
112 length = 16
113 case BrandAmex:
114 if r.Intn(2) == 0 {
115 prefix = "34"
116 } else {
117 prefix = "37"
118 }
119 length = 15
120 case BrandDiscover:
121 if r.Intn(2) == 0 {
122 prefix = "6011"
123 } else {
124 prefix = "65"
125 }
126 length = 16
127 case BrandDiners:
128 opt := r.Intn(3)
129 if opt == 0 {
130 prefix = strconv.Itoa(300 + r.Intn(6)) // 300-305
131 } else if opt == 1 {
132 prefix = "36"
133 } else {
134 prefix = "38"
135 }
136 length = 14
137 case BrandJCB:
138 prefix = strconv.Itoa(3528 + r.Intn(62)) // 3528-3589
139 length = 16
140 default:
141 return CreditCard{}, fmt.Errorf("unsupported card brand: %s", brand)
142 }
143
144 needed := length - len(prefix) - 1
145 var sb strings.Builder
146 sb.WriteString(prefix)
147 for i := 0; i < needed; i++ {
148 sb.WriteByte(byte('0' + r.Intn(10)))
149 }
150 chk, err := GenerateLuhnCheckDigit(sb.String())
151 if err != nil {
152 return CreditCard{}, err
153 }
154 sb.WriteByte(byte('0' + chk))
155 raw := sb.String()
156
157 // Formatting
158 var formatted string
159 switch style {
160 case FormatRaw:
161 formatted = raw
162 case FormatHyphenated:
163 if length == 14 {
164 formatted = fmt.Sprintf("%s-%s-%s", raw[0:4], raw[4:10], raw[10:14])
165 } else if length == 15 {
166 formatted = fmt.Sprintf("%s-%s-%s", raw[0:4], raw[4:10], raw[10:15])
167 } else {
168 formatted = fmt.Sprintf("%s-%s-%s-%s", raw[0:4], raw[4:8], raw[8:12], raw[12:16])
169 }
170 case FormatSpaceDelimited:
171 if length == 14 {
172 formatted = fmt.Sprintf("%s %s %s", raw[0:4], raw[4:10], raw[10:14])
173 } else if length == 15 {
174 formatted = fmt.Sprintf("%s %s %s", raw[0:4], raw[4:10], raw[10:15])
175 } else {
176 formatted = fmt.Sprintf("%s %s %s %s", raw[0:4], raw[4:8], raw[8:12], raw[12:16])
177 }
178 default:
179 formatted = raw
180 }
181
182 // CVV & Expiration
183 var cvv string
184 if brand == BrandAmex {
185 cvv = fmt.Sprintf("%04d", r.Intn(10000))
186 } else {
187 cvv = fmt.Sprintf("%03d", r.Intn(1000))
188 }
189 now := time.Now()
190 expMonth := 1 + r.Intn(12)
191 expYear := (now.Year() % 100) + 1 + r.Intn(5) // next 1 to 5 years
192
193 return CreditCard{
194 Brand: brand,
195 Number: raw,
196 Formatted: formatted,
197 ExpMonth: expMonth,
198 ExpYear: expYear,
199 CVV: cvv,
200 CardholderName: GenerateRandomName(r),
201 }, nil
202}
203
204// ValidateCreditCard validates card number format, Luhn Mod-10, and identifies card brand.
205func ValidateCreditCard(number string) (CardBrand, bool) {
206 if !ValidateLuhn(number) {
207 return "", false
208 }
209 clean := strings.ReplaceAll(strings.ReplaceAll(number, "-", ""), " ", "")
210 l := len(clean)
211 switch {
212 case l == 16 && strings.HasPrefix(clean, "4"):
213 return BrandVisa, true
214 case l == 16 && (strings.HasPrefix(clean, "51") || strings.HasPrefix(clean, "52") ||
215 strings.HasPrefix(clean, "53") || strings.HasPrefix(clean, "54") || strings.HasPrefix(clean, "55") ||
216 (len(clean) >= 4 && clean[:4] >= "2221" && clean[:4] <= "2720")):
217 return BrandMasterCard, true
218 case l == 15 && (strings.HasPrefix(clean, "34") || strings.HasPrefix(clean, "37")):
219 return BrandAmex, true
220 case l == 16 && (strings.HasPrefix(clean, "6011") || strings.HasPrefix(clean, "65")):
221 return BrandDiscover, true
222 case l == 14 && (strings.HasPrefix(clean, "36") || strings.HasPrefix(clean, "38") ||
223 (len(clean) >= 3 && clean[:3] >= "300" && clean[:3] <= "305")):
224 return BrandDiners, true
225 case l == 16 && len(clean) >= 4 && clean[:4] >= "3528" && clean[:4] <= "3589":
226 return BrandJCB, true
227 default:
228 return "", false
229 }
230}