Updated code on Credit/Debit Card Magnetic Stripe Processing for Snort 2.9.8.x/3.0.0
Bill Parker <[email protected]>
| Newsgroups | gmane.comp.security.ids.snort.devel |
|---|---|
| Message-ID | <CAFrbyQyuk5eqn5SN+yH3fJ7aztisCUPOEUv=dWXRTqai0fX8=w@mail.gmail.com> |
Russ,
Here is some new code which should detect Track 1/Track Credit Card
Magnetic Stripe Data, as opposed to just the generic credit card information
which can already be detected by the DLP in ClamAV.
The four (4) files attached to this feature report are:
new_magstripe.c <--- main source code
new_magstripe.h <--- header file for new_magstripe.c
results-release.txt <--- results from processing data file
'testdata.txt'
results-debug.txt <--- debug output from processing data file
'testdata.txt'
testdata.txt <--- simulated magnetic test stripe data
Note that this program does NOT test for the validity of the credit/debit
card number in the magnetic stripe on track 1 or 2, but just checks that
the data format for magnetic stripe processing matches the defined standard.
Bill Parker (wp02855 at gmail dot com)
------------------------------------------------------------------------------
_______________________________________________
Snort-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/snort-devel
Archive:
http://sourceforge.net/mailarchive/forum.php?forum_name=snort-devel
Please visit http://blog.snort.org for the latest news about Snort!
results-debug.txt
(text/plain, 1.9 KB)
Enter Line for CC/DC Mag Stripe Testing: The Line Entered was: %b1234567890123456789^AbCdEfGhIjKlmnopQRStuvwxyz^11171270874?LRC Length of Buffer entered is: 65 First Character in BUFFER is: % ASCII value is: 37 Last Character in BUFFER is: ASCII value is: 10 Buffer after conversion to upper case is: %B1234567890123456789^ABCDEFGHIJKLMNOPQRSTUVWXYZ^11171270874?LRC In function TrackOneFormatB() Length of buffer is (not counting NULL terminator): 64 current value of starting sentinel is: % Current value of track 1 format code is: B The Account Number is: 1234567890123456789 The Card Holder Name is: ABCDEFGHIJKLMNOPQRSTUVWXYZ The Credit/Debit Card Expiration Date is: 1117 Service Code 1st digit is: 1 Message: International interchange OK Service Code 2nd digit is: 2 Message: Contact issuer via online means Service Code 3rd digit is: 7 Message: Goods and services only (no cash), use PIN where feasible Track 1 or 2 end sentinel is: ? The Credit/Debit Card Discretionary Data is: 0874 The Longitudinal redundancy check value is: LRC Enter Line for CC/DC Mag Stripe Testing: The Line Entered was: ;1234567890123456789=06211010874?x Length of Buffer entered is: 35 First Character in BUFFER is: ; ASCII value is: 59 Last Character in BUFFER is: ASCII value is: 10 Buffer after conversion to upper case is: ;1234567890123456789=06211010874?X In function TrackTwo() Length of buffer is (not counting NULL terminator): 34 current value of starting sentinel is: ; The Account Number is: 1234567890123456789 The Credit/Debit Card Expiration Date is: 0621 Service Code 1st digit is: 1 Message: International interchange OK Service Code 2nd digit is: 0 Message: Normal Service Code 3rd digit is: 1 Message: No restrictions Track 1 or 2 end sentinel is: ? The Credit/Debit Card Discretionary Data is: 0874 The Longitudinal redundancy check Data is: X
new_magstripe.c
(text/x-csrc, 22.4 KB)
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/unistd.h>
#include <sys/types.h>
#include <ctype.h>
#include "new_magstripe.h"
void StringToLower(char *s)
{
while (*s != '\0') {
*s = tolower((unsigned char)*s);
++s;
}
}
void StringToUpper(char *s)
{
while (*s != '\0') {
*s = toupper((unsigned char)*s);
++s;
}
}
void ReverseString(char *s)
{
size_t len = strlen(s);
size_t i, j;
if (len > 0)
for (i = 0, j = len - 1; i < j; i++, j--)
s[i] ^= s[j], s[j] ^= s[i], s[i] ^= s[j];
}
int service_code_valid(char *s)
{
/* This function checks the validity of the */
/* service code passed to it. Valid Codes are */
/* as follows: */
/* */
/* Service code values common in financial cards: */
/* */
/* First Digit: */
/* */
/* 1: International interchange OK */
/* 2: International interchange, use IC (chip) where feasible */
/* 5: National interchange only except under bilateral agreement */
/* 6: National interchange only except under bilateral agreement, */
/* use IC (chip) where feasible */
/* 7: No interchange except under bilateral agreement */
/* (closed loop) */
/* 9: Test */
/* */
/* Second Digit: */
/* */
/* 0: Normal */
/* 2: Contact issuer via online means */
/* 4: Contact issuer via online means except under */
/* bilateral agreement */
/* */
/* Third Digit: */
/* */
/* 0: No restrictions, PIN required */
/* 1: No restrictions */
/* 2: Goods and services only (no cash) */
/* 3: ATM only, PIN required */
/* 4: Cash Only */
/* 5: Goods and services only (no cash), PIN required */
/* 6: No restrictions, use PIN where feasible */
/* 7: Goods and services only (no cash), use PIN where feasible */
int first_digit;
int second_digit;
int third_digit;
/* grab first digit and bump pointer */
first_digit = (int)(*s - '0');
s++;
/* grab second digit and bump pointer */
second_digit = (int)(*s - '0');
s++;
/* grab third digit and bump pointer */
third_digit = (int)(*s - '0');
#if 0
printf("\nIn function 'service_code_valid'...\n");
printf("Value of first digit is:\t%d\n", first_digit);
printf("Value of second digit is:\t%d\n", second_digit);
printf("Value of third digit is:\t%d\n", third_digit);
#endif // 1
/* Now check the 1st digit in the service code for validity */
if (first_digit == 0 || first_digit == 3 ||
first_digit == 4 || first_digit == 8)
return 1; /* return 1 if first digit is invalid */
else if (first_digit == 1 || first_digit == 2 || first_digit == 5 ||
first_digit == 6 || first_digit == 7 || first_digit == 9)
printf("\nService Code 1st digit is: %d Message: %s\n", first_table[first_digit].digit,
first_table[first_digit].message);
else {
printf("\nValue not in range -- INTERNAL ERROR...exiting...\n");
exit(EXIT_FAILURE);
}
/* Now Check the 2nd digit in the service code for validity */
if (second_digit == 1 || second_digit == 3 || second_digit == 5 ||
second_digit == 6 || second_digit == 7 || second_digit == 8 ||
second_digit == 9)
return 2; /* return 2 if second digit is invalid */
else if (second_digit == 0 || second_digit == 2 || second_digit == 4)
printf("Service Code 2nd digit is: %d Message: %s\n", second_table[second_digit].digit,
second_table[second_digit].message);
else {
printf("\nValue not in range -- INTERNAL ERROR...exiting...\n");
exit(EXIT_FAILURE);
}
/* Now check the 3rd digit in the service code for validity */
if (third_digit == 8 || third_digit == 9)
return 3; /* return 3 if third_digit is invalid */
else if (third_digit == 0 || third_digit == 1 || third_digit == 2 ||
third_digit == 3 || third_digit == 4 || third_digit == 5 ||
third_digit == 6 || third_digit == 7)
printf("Service Code 3rd digit is: %d Message: %s\n", third_table[third_digit].digit,
third_table[third_digit].message);
else {
printf("\nValue not in range -- INTERNAL ERROR...exiting...\n");
exit(EXIT_FAILURE);
}
return 0; /* return zero means success */
}
/* Track 1 is written with code known as DEC SIXBIT plus odd parity. */
/* The information on track 1 on financial cards is contained in */
/* several formats: A, which is reserved for proprietary use of */
/* the card issuer, B, which is described below */
/* C-M, which are reserved for use by ANSI Subcommittee X3B10 and */
/* N-Z, which are available for use by individual card issuers: */
/* This function checks Magnetic Stripe Track 1 per ISO-IEC 7813 */
/* The format for data layout on Track 1 is as follows: */
/* Start sentinel one character (generally '%') */
/* Format code="B" one character (alpha only) */
/* Primary account number (PAN) up to 19 characters. */
/* Usually, but not always, matches the credit card number printed */
/* on the front of the card. */
/* Field Separator one character (generally '^') */
/* Name 2 to 26 characters */
/* Field Separator one character (generally '^') */
/* Expiration date four characters in the form YYMM. */
/* Service code three characters */
/* Discretionary data may include Pin Verification Key Indicator */
/* (PVKI, 1 character), PIN Verification Value (PVV, 4 characters),*/
/* Card Verification Value or Card Verification Code (CVV or CVC, */
/* 3 characters) */
/* End sentinel one character (generally '?') */
/* Longitudinal redundancy check (LRC) it is one character and a */
/* validity character calculated from other data on the track. */
int TrackOneFormatB(char *buf_str_ptr)
{
char track1_account_number[20]; /* Max of 20 chars for Credit/Debit Card */
char *trk1_acct_num_ptr;
char track1_username[30]; /* 26 chars max for card holder name */
char *trk1_uname_ptr;
char track1_expiry_date[5]; /* Expiration Date in MM/YY format */
char *trk1_exp_date_ptr;
char track1_service_code[4]; /* Service Code Value (3 chars max) */
char *trk1_srv_code_ptr;
char track1_discret_data[5]; /* Discretionary Data for track 1 */
char *trk1_discret_data_ptr;
char track1_lrc[5]; /* Longitudinal redundancy check (LRC) */
char *trk1_lrc_ptr;
char trk1_s_sentinel; /* placeholder for track 1 start sentinel */
char trk1_e_sentinel; /* placeholder for track 1 end sentinel */
char trk1_format_code; /* placeholder for track 1 format code */
int i; /* used in for/while loops */
size_t buffer_len; /* length of buffer */
int srv_code_result;
/* Initialize Character Arrays via memset() */
memset(track1_account_number, 0x00, sizeof(track1_account_number));
memset(track1_username, 0x00, sizeof(track1_username));
memset(track1_expiry_date, 0x00, sizeof(track1_expiry_date));
memset(track1_service_code, 0x00, sizeof(track1_service_code));
memset(track1_discret_data, 0x00, sizeof(track1_discret_data));
memset(track1_lrc, 0x00, sizeof(track1_lrc));
/* get total length of buffer passed to this function */
buffer_len = strlen(buf_str_ptr);
printf("\nIn function TrackOneFormatB()\n");
printf("\nLength of buffer is (not counting NULL terminator): %d\n", (int)(buffer_len-1));
/* check for starting sentinel */
if (*buf_str_ptr != track1_start_sentinel) {
fprintf(stderr, "starting sentinel is not '%c'...exiting\n", track1_start_sentinel);
(void)fflush(stdout);
return(EXIT_FAILURE);
}
trk1_s_sentinel = *buf_str_ptr;
printf("\ncurrent value of starting sentinel is: %c\n", trk1_s_sentinel);
buf_str_ptr++; /* point to next character in bubber */
/* check for format code, shoule be 'B' or 'b' */
trk1_format_code = *buf_str_ptr;
if (*buf_str_ptr != track1_format_code) {
fprintf(stderr, "Mag stripe track 1, format B code is not letter 'B' or 'b'...exiting\n");
(void)fflush(stdout);
return(EXIT_FAILURE);
}
buf_str_ptr++;
printf("\nCurrent value of track 1 format code is: %c\n", trk1_format_code);
/* grab credit/debit card account number from buffer */
trk1_acct_num_ptr = &track1_account_number[0];
while (*buf_str_ptr != track1_field_separator) {
*trk1_acct_num_ptr = *buf_str_ptr;
trk1_acct_num_ptr++;
buf_str_ptr++;
}
*trk1_acct_num_ptr = '\0'; /* terminate the account number buffer */
buf_str_ptr++; /* bump pointer to skip field separator */
printf("\nThe Account Number is: %s\n", track1_account_number);
(void)fflush(stdout);
/* At this point call Snort SDF CC/DC check for validity */
/* or ClamAV DLP processor for validity check */
/* Grab Card Holder Name from buffer */
trk1_uname_ptr = &track1_username[0];
while (*buf_str_ptr != track1_field_separator) {
*trk1_uname_ptr = *buf_str_ptr;
trk1_uname_ptr++;
buf_str_ptr++;
}
*trk1_uname_ptr = '\0'; /* terminate the track 1 user name buffer */
buf_str_ptr++;
printf("\nThe Card Holder Name is: %s\n", track1_username);
(void)fflush(stdout);
/* Get Expiration Date from buffer */
trk1_exp_date_ptr = &track1_expiry_date[0];
for (i = 0; i < 4; i++) {
*trk1_exp_date_ptr = *buf_str_ptr;
trk1_exp_date_ptr++;
buf_str_ptr++;
}
*trk1_exp_date_ptr = '\0'; /* terminate the expiration date buffer */
printf("\nThe Credit/Debit Card Expiration Date is: %s\n", track1_expiry_date);
(void)fflush(stdout);
/* Get service code information from buffer */
trk1_srv_code_ptr = &track1_service_code[0];
for (i = 0; i < 3; i++) {
*trk1_srv_code_ptr = *buf_str_ptr;
trk1_srv_code_ptr++;
buf_str_ptr++;
}
*trk1_srv_code_ptr = '\0'; /* terminate the service code buffer */
/* call function to validate service code */
srv_code_result = service_code_valid(track1_service_code);
if (srv_code_result == 1 || srv_code_result == 2 || srv_code_result == 3) {
printf("\nWarning: Invalid service code found...\n");
printf("\nInvalid code found in position: %d\n", srv_code_result);
return(EXIT_FAILURE);
}
/* Get PVKI/PVV/CVV/CVC data from buffer (1 to 4 chars max) */
trk1_discret_data_ptr = &track1_discret_data[0];
while (*buf_str_ptr != track12_end_sentinel) {
*trk1_discret_data_ptr = *buf_str_ptr;
trk1_discret_data_ptr++;
buf_str_ptr++;
}
*trk1_discret_data_ptr = '\0'; /* terminate the discretionary data buffer */
trk1_e_sentinel = *buf_str_ptr; /* grab ending sentinel value */
printf("\nTrack 1 or 2 end sentinel is: %c\n", trk1_e_sentinel);
buf_str_ptr++; /* bump pointer to skip end sentinel */
printf("\nThe Credit/Debit Card Discretionary Data is: %s\n", track1_discret_data);
(void)fflush(stdout);
/* Get Longitudinal redundancy check (LRC) value */
trk1_lrc_ptr = &track1_lrc[0];
while(*buf_str_ptr != '\0') { /* process buffer until we reach NULL */
*trk1_lrc_ptr = *buf_str_ptr;
buf_str_ptr++;
trk1_lrc_ptr++;
}
*trk1_lrc_ptr = '\0'; /* terminate the LRC buffer */
printf("\nThe Longitudinal redundancy check value is: %s\n", track1_lrc);
(void)fflush(stdout);
return 0;
}
/* Track 2: This format was developed by the banking industry (ABA). */
/* This track is written with a 5-bit scheme (4 data bits + 1 parity), */
/* which allows for sixteen possible characters, which are the numbers */
/* 0-9, plus the six characters : ; < = > ? . The selection of six */
/* punctuation symbols may seem odd, but in fact the sixteen codes */
/* simply map to the ASCII range 0x30 through 0x3f, which defines ten */
/* digit characters plus those six symbols. */
/* The data format is as follows: */
/* Start sentinel one character (generally ';') */
/* Primary account number (PAN) up to 19 characters. Usually, but */
/* not always, matches the credit card number printed on the front of */
/* the card. */
/* Separator one char (generally '=') */
/* Expiration date four characters in the form YYMM. */
/* Service code three digits. The first digit specifies the */
/* interchange rules, the second specifies authorization processing */
/* and the third specifies the range of services */
/* Discretionary data as in track one */
/* End sentinel one character (generally '?') */
/* Longitudinal redundancy check (LRC) it is one character and a */
/* validity character calculated from other data on the track. */
/* Most reader devices do not return this value when the card is */
/* swiped to the presentation layer, and use it only to verify the */
/* input internally to the reader. */
int TrackTwo(char *buf_str_ptr)
{
char track2_account_number[20]; /* Max of 20 chars for Credit/Debit Card */
char *trk2_acct_num_ptr;
char track2_expiry_date[5]; /* Expiration Date in MM/YY format */
char *trk2_exp_date_ptr;
char track2_service_code[4]; /* Service Code Value (3 chars max) */
char *trk2_srv_code_ptr;
char track2_discret_data[5]; /* Discretionary Data for track 2 */
char *trk2_discret_data_ptr;
char track2_lrc; /* Longitudinal redundancy check (LRC) */
char trk2_s_sentinel; /* starting sentinel for track 2 */
char trk2_e_sentinel; /* ending sentinel for track 2 */
int i; /* used in for/while loops */
size_t trk2_buffer_len; /* length of buffer */
int trk2_srv_code_result;
/* Initialize Character Arrays using memset() */
memset(track2_account_number, 0x00, sizeof(track2_account_number));
memset(track2_expiry_date, 0x00, sizeof(track2_expiry_date));
memset(track2_service_code, 0x00, sizeof(track2_service_code));
memset(track2_discret_data, 0x00, sizeof(track2_discret_data));
/* get total length of buffer passed to this function */
trk2_buffer_len = strlen(buf_str_ptr);
printf("\nIn function TrackTwo()\n");
printf("\nLength of buffer is (not counting NULL terminator): %d\n", (int)trk2_buffer_len-1);
/* check for starting sentinel */
if (*buf_str_ptr != track2_start_sentinel) {
fprintf(stderr, "starting sentinel for track 2 is not '%c'...exiting\n", track2_start_sentinel);
(void)fflush(stdout);
return(EXIT_FAILURE);
}
trk2_s_sentinel = *buf_str_ptr;
printf("\ncurrent value of starting sentinel is: %c\n", trk2_s_sentinel);
buf_str_ptr++; /* point to next character in bubber */
/* grab credit/debit card account number from buffer */
trk2_acct_num_ptr = &track2_account_number[0];
while (*buf_str_ptr != track2_field_separator) {
*trk2_acct_num_ptr = *buf_str_ptr;
trk2_acct_num_ptr++;
buf_str_ptr++;
}
*trk2_acct_num_ptr = '\0'; /* terminate the account number buffer */
buf_str_ptr++; /* bump pointer to skip field separator */
printf("\nThe Account Number is: %s\n", track2_account_number);
(void)fflush(stdout);
/* At this point call Snort SDF CC/DC check for validity */
/* or ClamAV DLP processor for validity check */
/* Get Expiration Date from buffer */
trk2_exp_date_ptr = &track2_expiry_date[0];
for (i = 0; i < 4; i++) {
*trk2_exp_date_ptr = *buf_str_ptr;
trk2_exp_date_ptr++;
buf_str_ptr++;
}
*trk2_exp_date_ptr = '\0'; /* terminate the expiration date buffer */
printf("\nThe Credit/Debit Card Expiration Date is: %s\n", track2_expiry_date);
(void)fflush(stdout);
/* Get service code information from buffer */
trk2_srv_code_ptr = &track2_service_code[0];
for (i = 0; i < 3; i++) {
*trk2_srv_code_ptr = *buf_str_ptr;
trk2_srv_code_ptr++;
buf_str_ptr++;
}
*trk2_srv_code_ptr = '\0'; /* terminate the service code buffer */
/* call function to validate service code */
trk2_srv_code_result = service_code_valid(track2_service_code);
if (trk2_srv_code_result == 1 || trk2_srv_code_result == 2 || trk2_srv_code_result == 3) {
printf("\nWarning: Invalid service code found...\n");
printf("\nInvalid code found in position: %d\n", trk2_srv_code_result);
return(EXIT_FAILURE);
}
/* Get PVKI/PVV/CVV/CVC data from buffer (1 to 4 chars max) */
trk2_discret_data_ptr = &track2_discret_data[0];
while (*buf_str_ptr != track12_end_sentinel) {
*trk2_discret_data_ptr = *buf_str_ptr;
trk2_discret_data_ptr++;
buf_str_ptr++;
}
*trk2_discret_data_ptr = '\0'; /* terminate the discretionary data buffer */
trk2_e_sentinel = *buf_str_ptr; /* grab ending sentinel value */
printf("\nTrack 1 or 2 end sentinel is: %c\n", trk2_e_sentinel);
buf_str_ptr++; /* bump pointer to skip end sentinel */
printf("\nThe Credit/Debit Card Discretionary Data is: %s\n", track2_discret_data);
(void)fflush(stdout);
track2_lrc = *buf_str_ptr;
printf("\nThe Longitudinal redundancy check Data is: %c\n", track2_lrc);
return 0;
}
int main()
{
char sbuffer[101]; /* Buffer for Mag Stripe Line */
char *sbuf_ptr; /* Start Buffer Pointer */
char *ebuf_ptr; /* End Buffer Pointer */
size_t buf_len; /* Length of buffer after input */
int track1_result;
int track2_result;
printf("Enter Line for CC/DC Mag Stripe Testing: ");
(void)fflush(stdout);
(void)fgets(sbuffer, (int)sizeof(sbuffer), stdin);
printf("\nThe Line Entered was: %s\n", sbuffer);
(void)fflush(stdout);
/* check line for initial minimum length requirement (65 chars min) */
buf_len = strlen(sbuffer);
printf("\nLength of Buffer entered is: %d\n\n", (int)buf_len);
(void)fflush(stdout);
sbuf_ptr = &sbuffer[0];
ebuf_ptr = sbuf_ptr + (buf_len-1); /* Get last character in buffer (usually CR or LF */
#if NDEBUG
printf("\nFirst Character in BUFFER is: %c ASCII value is: %d\n", *sbuf_ptr, (int)*sbuf_ptr);
printf("\nLast Character in BUFFER is: %c ASCII value is: %d\n", *ebuf_ptr, (int)*ebuf_ptr);
#endif // NDEBUG
StringToUpper(sbuf_ptr); /* convert buffer to upper case */
#if NDEBUG
printf("Buffer after conversion to upper case is: %s\n", sbuffer);
(void)fflush(stdout);
#endif // NDEBUG
/* Let user know we're checking for track 1 data... */
track1_result = TrackOneFormatB(&sbuffer[0]);
printf("Enter Line for CC/DC Mag Stripe Testing: ");
(void)fflush(stdout);
(void)fgets(sbuffer, (int)sizeof(sbuffer), stdin);
printf("\nThe Line Entered was: %s\n", sbuffer);
(void)fflush(stdout);
/* check line for initial minimum length requirement (65 chars min) */
buf_len = strlen(sbuffer);
#if NDEBUG
printf("\nLength of Buffer entered is: %d\n\n", (int)buf_len);
(void)fflush(stdout);
#endif // NDEBUG
sbuf_ptr = &sbuffer[0];
ebuf_ptr = sbuf_ptr + (buf_len-1); /* Get last character in buffer (usually CR or LF */
#if NDEBUG
printf("\nFirst Character in BUFFER is: %c\tASCII value is: %d\n", *sbuf_ptr, (int)*sbuf_ptr);
printf("\nLast Character in BUFFER is: %c\tASCII value is: %d\n", *ebuf_ptr, (int)*ebuf_ptr);
#endif // NDEBUG
StringToUpper(sbuf_ptr); /* convert buffer to upper case */
#if NDEBUG
printf("Buffer after conversion to upper case is: %s\n", sbuffer);
(void)fflush(stdout);
#endif // NDEBUG
track2_result = TrackTwo(&sbuffer[0]);
return 0;
}
new_magstripe.h
(text/x-chdr, 2.7 KB)
/* useful macros */
#ifndef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif
/* function prototypes */
void StringToLower(char *);
void StringToUpper(char *);
void ReverseString(char *);
int service_code_valid(char *);
int TrackOneFormatB(char *);
int TrackTwo(char *);
/* structure definitions */
typedef struct SERVICE_CODE
{
int digit; /* value of first digit */
char *message; /* result message */
} SERVICE_CODE;
SERVICE_CODE first_table[] =
{
{0, "(reserved for future use)"}, /* Not in use */
{1, "International interchange OK"},
{2, "(reserved for future use)"}, /* Not in use */
{3, "(reserved for future use)"}, /* Not in use */
{4, "(reserved for future use)"}, /* Not in use */
{5, "National interchange only except under bilateral agreement"},
{6, "National interchange only except under bilateral agreement, use IC (chip) where feasible"},
{7, "o interchange except under bilateral agreement (closed loop)"},
{8, "(reserved for future use)"}, /* Not in use */
{9, "Test"}
}; /* end of definitions for first_table */
SERVICE_CODE second_table[] =
{
{0, "Normal"},
{1, "(reserved for future use)"}, /* Not in use */
{2, "Contact issuer via online means"},
{3, "(reserved for future use)"}, /* Not in use */
{4, "Contact issuer via online means except under bilateral agreement"},
{5, "(reserved for future use)"}, /* Not in use */
{6, "(reserved for future use)"}, /* Not in use */
{7, "(reserved for future use)"}, /* Not in use */
{8, "(reserved for future use)"}, /* Not in use */
{9, "(reserved for future use)"} /* Not in use */
}; /* end of definitions for second_table */
SERVICE_CODE third_table[] =
{
{0, "No restrictions, PIN required"},
{1, "No restrictions"},
{2, "Goods and services only (no cash)"},
{3, "ATM only, PIN required"},
{4, "Cash Only"},
{5, "Goods and services only (no cash), PIN required"},
{6, "No restrictions, use PIN where feasible"},
{7, "Goods and services only (no cash), use PIN where feasible"},
{8, "(reserved for future use)"}, /* Not in use */
{9, "(reserved for future use)"} /* Not in use */
}; /* end of definitions for third_table */
const char track1_start_sentinel = '%';
const char track2_start_sentinel = ';';
const char track12_end_sentinel = '?';
const char track1_format_code = 'B';
const char track1_field_separator = '^';
const char track2_field_separator = '=';
results-release.txt
(text/plain, 1.5 KB)
Enter Line for CC/DC Mag Stripe Testing: The Line Entered was: %b1234567890123456789^AbCdEfGhIjKlmnopQRStuvwxyz^11171270874?LRC Length of Buffer entered is: 65 In function TrackOneFormatB() Length of buffer is (not counting NULL terminator): 64 current value of starting sentinel is: % Current value of track 1 format code is: B The Account Number is: 1234567890123456789 The Card Holder Name is: ABCDEFGHIJKLMNOPQRSTUVWXYZ The Credit/Debit Card Expiration Date is: 1117 Service Code 1st digit is: 1 Message: International interchange OK Service Code 2nd digit is: 2 Message: Contact issuer via online means Service Code 3rd digit is: 7 Message: Goods and services only (no cash), use PIN where feasible Track 1 or 2 end sentinel is: ? The Credit/Debit Card Discretionary Data is: 0874 The Longitudinal redundancy check value is: LRC Enter Line for CC/DC Mag Stripe Testing: The Line Entered was: ;1234567890123456789=06211010874?x In function TrackTwo() Length of buffer is (not counting NULL terminator): 34 current value of starting sentinel is: ; The Account Number is: 1234567890123456789 The Credit/Debit Card Expiration Date is: 0621 Service Code 1st digit is: 1 Message: International interchange OK Service Code 2nd digit is: 0 Message: Normal Service Code 3rd digit is: 1 Message: No restrictions Track 1 or 2 end sentinel is: ? The Credit/Debit Card Discretionary Data is: 0874 The Longitudinal redundancy check Data is: X
testdata.txt
(text/plain, 102 B)
%b1234567890123456789^AbCdEfGhIjKlmnopQRStuvwxyz^11171270874?LRC ;1234567890123456789=06211010874?x