cybersecurity · intermediate · ~30 min

Redact credit-card-like number runs

Combine character-class scanning with a numeric checksum.

Challenge

Implement void redact_cards(char *line) that mutates line in place, replacing every run of digits whose length is in [13, 19] AND that passes the Luhn checksum with the literal text [redacted].

The Luhn check, briefly:

  1. Walk the digits from right to left.
  2. Every second digit is doubled; if the doubled value is > 9, sum its decimal digits (equivalently, subtract 9).
  3. Sum every digit.
  4. The number passes if the total mod 10 is 0.

You only redact runs of plain digits. Spaces or dashes between digits do not extend the run for this exercise.

Examples

"card 4532015112830366 in log"
   -> "card [redacted] in log"   // Luhn-valid 16 digits

"old 1234567890123456 is invalid"
   -> "old 1234567890123456 is invalid"  // 16 digits, but Luhn-invalid

"ten digits 1234567890 leave alone"
   -> "ten digits 1234567890 leave alone"  // too short

"long 12345678901234567890 leave alone"
   -> "long 12345678901234567890 leave alone"  // 20 digits, too long

Why this matters

PCI-DSS compliance requires masking primary account numbers (PANs) in logs and exports. The pragmatic check is: any run of 13–19 digits that passes the Luhn checksum is treated as a card number and redacted.

Input format

Mutable null-terminated line.

Output format

line mutated in place.

Constraints

No allocations beyond a local scratch buffer.

Starter code

void redact_cards(char *line) { /* TODO */ }

Common mistakes

Forgetting the length window (13..19). Doubling the wrong digit (it's every second from the right, not the left).

Edge cases to handle

Digit run too short; too long; valid Luhn but not in window; multiple cards in one line.

Complexity

O(strlen(line) * avg-digit-run-length).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.