Newsgroups: alt.2600Path: sundog.tiac.net!europa.eng.gtefsd.com!emory!swrinde!pipex!sunic!EU.net!uunet!iat.holonet.net!clafaveFrom: clafave@iat.holonet.net (Christopher R LaFave)Subject: Re: Hacking aTMMessage-ID: Organization: HoloNet National Internet Access System: 510-704-1058/modemReferences: <2v5ev9$53p@lucy.infi.net>Date: Sun, 3 Jul 1994 08:34:16 GMTLines: 510 Magnetic stripe technologyFigures and listings are at the end. Because of their widespread use, most magnetic cards adhere to well-definedstandards that describe the physical and magnetic characteristics for amagnetic stripe on a plastic card. These standards outline specifications for astorage format and information interchange. This does not preclude other encoding techniques or additional data tracks for specific applications, but inmost cases it makes sense to adhere to at least the basic constraints. Thisgives you the choice of using any commercially available magnetic encoders foryour application. The technique used for encoding magnetic cards is known as"Two-Frequency, Coherent Phase Recording". Allowing for the representation ofsingle-channel, self-clocking serial data, this methodology is generally referred to as F/2F. Self-clocking is achieved by combining data and clock bitstogether in a continuous, synchronous sequence. In this scheme, an intermediateflux transition signifies a one bit and the absence of an intermediate fluxtransition denotes a zero bit. Three data tracks defined for use on standard magnetic cards each possessdifferent bit densities and encoded character sets. The average bit density oftrack 1 is 210 bits per inch (bpi). Track 1 characters are made up of six databits and an odd parity bit, encoded with the least-significant bit first and the parity bit last, yielding a 64-character set. Taking the number of bits perinch and the number of bits per character, you can see track 1 has the capacityto hold 79 characters. Track 2 has a bit density of 75 bpi, and track 3 uses 210 bpi. Both of thesetracks allow the representation of a numeric-only character set. The charactersfor tracks 2 and 3 are encoded using a 4-bit binary-coded decimal subset withodd parity and, like track 1, are encoded with the least significant bit firstand the parity bit last. The lower density of track 2 allows up to 40 numericcharacters, where 107 numerics can be squeezed onto track 3. The actual numberof usable characters will be fewer since you also have the Start Sentinel, EndSentinel, and LRC characters. Though sometimes magnetic cards are moved past the read head mechanically,most applications rely on manually moving the card, either through a slottedreader or into an insertion-type reader. Typically the swipe rate is 5-20 inchesper second (ips), with 50 ips being the fastest most card readers can handle. Ofcourse, moving the card by hand will not only result in varying the absolutecard velocity but, will also introduce incremental speed changes as the cardaccelerates and decelerates past the pickup. The F/2F scheme is very forgivingof such speed fluctuations. For all 3 tracks, the fundamental data format is similar and consists of thefollowing elements: First, leading zero bits are encoded to indicate the presence of an encoded magnetic card and provide synchronization pulses to theread head electronics and ultimately to the controller. Next, the Start Sentinelcharacter is encoded which indicates the start of the actual data. The codeddata follows. Next, the End Sentinel terminates the data portion of the cardand followed by an LRC byte (used for error detection). The LRC is essentiallya horizontal parity calculated by an exclusive-OR of all the data bits from theStart Sentinel to the End Sentinel (inclusive). Finally, trailing zeros followthe LRC and fill out the remainder of the card. ANATOMY OF A MAGNETIC CARD The magnetic tracks have inherent characteristics based on details such as code set and bit and character densities. International organizations such asMastercard and VISA impose additional constraits for their participating membersand standards exist for bank debit cards and ATM cards as well. These rulesspecify the exact content and format of each data field in aech track as well asthe intended uses for the tracks. Naturally, for nonfinancial uses, it is notnecessary to comply with these standards. For dedicated uses such as access control, people tracking, and material tracking, adhering to the minimal standards is adequate. The most-often-used track is track 2, although it offers the lowest inform-ation density of the three. It contains all the information that is normallyused for credit card transactions. When a customer name is required, track 1must be used since it is the only track that permits alphanumeric data. Track 3is specified for numeric-only data, but is unique. It is intended for change-able data and consequently may not only be read but may be rewritten by thetransaction-handling equipment. A multitude of data fileds are contained inthese various tracks. Figure 1 shows a brief run-down of what is generally placed on tracks 1 and 2. REAL CARD READERSThe recovery of magnetically encoded F/2F data can be accomplished directlywith the use of just about any microcontroller. There are no particulardifficulties in deciphering the raw F/2F data stream and many early magneticread heads contained nothing more than signal amplifiers and line drivers.These are now artifacts since all modern magnetic read heads contain integ-rated F/2F bit recovery circuitry and interface with the host controller in astandard fashion using three wires: CARD PRESENT, CLOCK, and DATA. The readheads usually rely on a single chip to perform the linear signal conditioning,sychronization, and recovery of individual bits from the data stream. The Mag-Tek 21006505 IC is representative of this type of data recovery circuit and itsfunctionality is depicted in figure 2. Linear conditioning consists of raising the level of the magnetic pickup'sinput signal, rejecting common-mode noise, conditioning and detecting the signal, and finally providing a digital output for susequent processing. Theenable/disable counters provide initialization for the recovery section. Therecovery section locks onto the data rate and recovers the individual data bitsfrom the data stream. The oscillator section provides the clocks for the recov-ery section and for the enable/disable timers. Card present goes low after 8 or9 flux reversals are seen from the magnetic pickup and will return high about50 ms after the last flux reversal. The strobe line signals that data is validand is active low. The data pin indicates a one bit when it is low. Raw F/2Fdata can also be picked directly off the chip. The data rate for a high-density track scanned at 50 ips comes to 10500 bitsper second (bps). This results in a transfer rate of 1500 characters per secondfor the 7-bit elements used on track 1, and 2100 characters per second usingthe 5-bit elements of track 3. I either case, this translates to a new bit arriving at the controller just under every 100 us (microsecond). Even the mostanemic controller should be able to keep up. With resonably good coding techni-ques, there should be no problem handling the entire data sampling phase on aninterrupt-driven basis. The low-density (track 2) data flows at a more pedes-trian 3750 bps, yielding 750 5-bit characters per second, or a new bit every266 us. Since most dual-track read heads provide track 1 and track 2 data, thisindicates that handling both tracks simultaneously is feasible under interruptcontrol. Keep in mind that 50 ips is a rather fast scan rate; 20-30 ips isprobably a more realistic limit. MAGNETIC BIT STORMS When approaching a problem such as decoding magnetic cards, it pays to spendsome time looking at the overall picture before starting to write the code. Atfirst glance, it would seem that organizing the data into the prevailing elementsize during the sampling interval would make decoding easier. This could beeasily done by ignoring all the leading zeros, with actual data storage comm-encing with the first one bit. Of course, this approach assumes you're gettinggood data. The fact that the data recovery is handled using well-proven hard-ware makes this assumption valid. If all you need to do is decode the card in a forward direction, then goingabout things as I just described makes sense and reduces the coding effort to atrivial exercise. If you have to support reverse decoding then this is not theoptimal solution. Having considered the tradeoffs of being able to decode a magnetic card in both forward and reverse directions, I decided to structure theprogram to work equally well in either direction at the cost of a slight increase in initial complexity. The first step in decoding is to acquire the serial bit stream. This can be done using a dedicated sample loop or, with a little more work, using interruptprocessing. Since the idea is the same regardless of the details, I decided touse a sample loop in my demonstration program (listing 1). The code simplyrecords the incoming data stream and deposits the data in a sample buffer a byteat a time. Sampling begins when Card Present returns idle. Any incomplete bytethat has been partially assembled at the time when sampling terminates is simplydiscarded. The abundance of leading and trailing zeros allows losing some bitsat either end causing any problems. Once the sampling interval completes, control is transferred to the decodingalgorithm. Presented in listing 2, the track-1 decode algorithm consists of nothing more than some initialization and the essence of the decode logic.Limiting the gyrations contained in the main body of this routine not only makesthe logic easy to follow, but permits the same code to handle the decoding ineither a forward or reverse direction. The initial entry point assumes a forward decode attempt and sets up the necessary flags, pointers, and counters before jumping into the main initial-ization code. After initialization, the sample buffer is scanned for the firstone bit, at which time a 7-bit element is assembled. If the parity is correctand the character code checks out to be a Start Sentinel, the code proceeds andstarts pulling successive data elements from the sample buffer. If the data element is not an End Sentinel, the character is translated to ASCII and storedin the decode buffer. Should an End Sentinel be detected, the program extractsthe next character, which is assumed to be the LRC byte, and finally checks thecalculated LRC for a value of zero. The checks and balances included in the execution of this loop include thingssuch as parity, a cumulative LRC, and checking to make sure I haven't run out ofsamples. If everything checks out, the program terminates and returns with theDPTR pointing to the decoded data buffer and the character count contained inACC. Should a decode failure occur, a test is performed on the direction flagand if this is an attempt at a forward decode, the routine jumps to the reverseinitialization entry point. The reverse entry is similar to the forward decodeentry but sets up the sample pointer to the end of the sample buffer and sets the direction flag to indicate a reverse operation. The routines contained in the intermediate layer are shown in listing 3. Themeaning and operation of these routines should be apparent. The key routine inthis section is GET_BIT, which picks off the next bit from the sample buffer,essentially restoring the sequential nature of the initial magnetic bit stream.FIND_START is used to synchronize with the first one bit. GET_CHAR first checksto make sure it hasn't run out of samples, then assembles the next 7-bit dataelement while doing a parity test and LRC calculation. Any problems encounteredhere are sent back to the caller and are handled there. STORE_CHAR translatesand deposits the data character into its respective location in the decoded-databuffer and increments the character counter. Listing 4 shows the low-level code. These routines perform the most rudiment-ary functions and operate in accordance with the direction flag. INDEX_PTR either increments or decrements the sample pointer, POSITION_BIT likewise doeseither a right or left shift and LOCATE_BIT returns the state of the least- ormost- significant bit of the accumulator. GO AHEAD, TAKE A SWIPE Let me touch on a few additional points that may not be immediately apparentbefore signing off. Storing the sampled data in a continuous stream makes thesample routine work equally well with the various bit configurations used forthe different recording tracks. This would not be easily attained if you triedto generate a particular element format during sample time. Furthermore, if youlook at the differences between the encoded character sets and the bit formatsfor the different tracks, you will find that they differ in only a few areas.With a few minor changes, such as the defined Start Sentinel, number of bits perelement, and character translation method, the decode routine I've shown couldeasily be coerced to handle the decoding of any of the standard magnetic tracks. As a matter of fact, by recoding and redefining the hard-coded constants asvariables, these could be set up for the particular data track at executiontime before invoking the decode function. Doing so would not only save programmemory, but would also allow you to use a routine you were comfortable with. ******************************************************************************* FIGURE 1_____________________________________________________________________TRACK 1 |SS|FC| PAN |FS| NAME |FS| ADDITIONAL DATA |ES|LRC|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Notes: Track 1 is limited to 79 characters including SS, ES, and LRC.Mastercard PAN is variable up to 16 characters maximum. VISA is 13 or 16 characters, including mod-10 check digit. SS: Start sentinel (%)FC: Format code FS: Field separator ({)ES: End sentinel (?)LRC: Longitudinal redundency check characterPAN (primary account number): 19 digits max.NAME: 26 alphanumeric characters max.ADDITIONAL DATA: Expiration date 4 Restriction or type 3 Offset or PVN 5______________________________________________________________________TRACK 2 |SS|FC| PAN |FS| ADDITIONAL DATA |ES|LRC|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~SS: Start sentinel (;) (hex B)FS: Field separator (=) (hex D)ES: End sentinel (?) (hex F)LRC: Longitudinal redundency check characterPAN (primary account number): 19 digits max.ADDITIONAL DATA: Expiration date 4 Restriction or type 3 Offset or PVN 5***************************************************************************** FIGURE 2HEAD SIGNAL __/~\__ __/~\__ __/~\__ __/~\__ __/~\__ __/~\_______ `-` `-` `-` `-` `-` ____ _______ __________ ____CARD PRESENT |______________________________________________|____ ____ _____________________ ____ ____ _____READ DATA |____| |_________| |_________|____ ______ __________ __ __ __ __ __ __ __ __ __ __READ STROBE |__| |_| |_| |_| |_| |_| |_| |_| |_| |_| | | 0| 1| 0| 1| 1| 0| 1| 1| 0| 0| ___ HEAD 1-----X---X--------13 |MAG| 9--C2-R3 R1 C1 |TEK| | HEAD 2-----X---X--------12 | | 10-----X--X | | | | X---X------11 | | | R5 X-X R2 C6 | | 6------|--X | | X---X-------8 | | | +5VDC --------------X--R7--X--------X-|-----------------14 | | 7-----C3 | |+ | | | ____ R6 C5 | | | 16----DATA | X----------|------------------5 | | __________ _______ | | X------------------2 | | 15----STROBECARD PRESENT -------X------|-----------------------------1 | | | X----X-----3 | | | C4 R4----4 | |GND------------------------X------------------X |___|R=RESISTOR(Values weren't given)C=CAPACITOR(Values weren't given)X=CONNECTION BETWEEN WIRESMAG TEK is the Mag-Tek 21006505*****************************************************************************LISTING 1-- Using several externally defined routines, a sample program to read a stripe and store it in a buffer is very short. PUBLIC READ_MAG1 EXTERN MS1_BUF (XDATA) ;sample buffer EXTERN MS1_LIM (NUMBER) ;sample limit EXTERN MD1_BUF (XDATA) ;decode buffer EXTERN CP (BIT) ;card present bit EXTERN M1_CLK (BIT) ;clock bit EXTERN M1_DQ (BIT) ;data bit M1_SS EQU 5 ;start sentinelM1_ES EQU 1FH ;end sentinel; SEG CODE;Sample and decode magnetic track 1; output: ACC contains character count.; DPTR points to data bufferREAD_MAG1 PROC CALL MAG_SAMPLE JZ L?RM1 CALL MAG1_DECODEL?RM1: RET ENDPROC;General-purpose magnetic sampling routine; output: ACC contains sample countMAG_SAMPLE PROC MOV DPTR,#MS1_BUF MOV R1,#0 ;sample counterL?MS1: MOV R0,#8 ;bit counterL?MS2: JB CP,L?MS4 JB M1_CLK,L?MS2 MOV C,M1_DQL?MS3: JB CP,L?MS4 JNB M1_CLK,L?MS3 CPL C RRC A DJNZ R0,L?MS2 MOVX @DPTR,A INC DPTR INC R1 ;sample counter CJNE R1,#MS1_LIM,L?MS1L?MS4: MOV A,R1 ;final sample count RET ENDPROC *******************************************************************************LISTING 2-- Once the serial bit stream has been acquired, the decoding algorithm takes over.;Bidirectional magnetic track 1 decode routine;input: sample count in ACC, output: ACC contains character count; DPTR points to decoded data buffer;Reg. usage for this routine (includes subroutines) as follows:;R5: Direction flag, 0=forward;R4: Cumulative LRC register;R3: Decoded character counter;R2: Nondecrementing sample count;R1: Decrementing sample count;R0: Bit syncronizing counterMAG1_DECODE PROC ;1st pass, setup for forward decode attempt MOV R5,#0 ;indicate forward decode MOV DPTR,#MS1_BUF ;point to start of buffer MOV R1,A ;sample counter MOV R2,A ;sample count JMP L?M1D1 L?M1D0: ;2nd pass, setup for reverse decode attempt MOV R5,#1 ;indicate reverse decode MOV DPTR,#MS1_BUF MOV A,R2 ;sample count DEC A ADD A,DPL MOV DPL,A CLR A ADDC A,DPH MOV DPH,A ;point to end of buffer MOV R1,2 ;sample counterL?M1D1: ;decode initialization MOV R3,#0 ;character counter MOV R4,#0 ;inital LRC MOV R0,#0 ;bit syncronizer CALL FIND_START ;main decode loop JNC L?M1D5 ;start bit error CALL GET_CHAR ;Start Sentinel JB ACC.7,L?M1D5 ;format error CJNE A,#M1_SS,L?M1D5 ;start setinel errorL?M1D2: ;data byte or End Sentinel CALL GET_CHAR JB ACC.7,L?M1D5 ;format error CJNE A,#M1_ES,L?M1D3 ;end sentinel not found JMP L?M1D4L?M1D3: CALL STORE_CHAR ;data character JMP L?M1D2L?M1D4: ;LRC CALL GET_CHAR ;get LRC JB ACC.7,L?M1D5 ;format error MOV A,R4 JNZ L?M1D5 ;LRC error MOV DPTR,#MD1_BUF ;good return MOV A,R3 ;final character RETL?M1D5: ;decode error, check if 1st pass CJNE R5,#1,L?M1D0 ;check direction CLR A ;bad return RET ENDPROC*******************************************************************************LISTING 3-- The intermediate layer of software is one level removed from the nitty-gritty details.;Get the next bit from the sample buffer;output: C contains data bitGET_BIT PROC CJNE R0,#0,L?GB1 ;bit synchronizer MOV R0,#8 PUSH ACC MOVX A,@DPTR CALL INDEX_PTR MOV B,A POP ACC DEC R1 ;sample counterL?GB1: XCH A,B CALL POSITION_BIT XCH A,B DEC R0 ;bit synchronizer RET ENDPROC;;Find the first '1' bit in the sample buffer;output: C=1 if bit is foundFIND_START PROCL?FS1: CJNE R0,#0,L?FS2 ;bit synchronizer MOV R0,#8 MOVX A,@DPTR CALL INDEX_PTR DJNZ R1,L?FS2 ;sample counter JMP L?FS4 ;out of samplesL?FS2: CALL LOCATE_BIT ;test for a '1' bit JC L?FS3 CALL POSITION_BIT DEC R0 ;bit synchronizer JMP L?FS1L?FS3: ;good return MOV B,A ;save copy in B SETB C RETL?FS4: CLR C ;bad return RET ENDPROC;;Get the next 7 bit element from the sample buffer;output: ACC contains data element; error flag is ACC.7GET_CHAR PROC MOV A,R1 ;sample counter JZ L?GC2 ;out of samples MOV R7,#7 ;bit counter CLR AL?GC1: CALL GET_BIT ;next bit RRC A DJNZ R7,L?GC1 RR A JNB P,L?GC2 ;parity error ANL A,#3FH ;discard parity PUSH ACC XRL A,R4 ;calculate LRC MOV R4,A POP ACC ;good return RETL?GC2: SETB ACC.7 ;bad return RET ENDPROC;Translate and store the data character;input: ACC contains data characterSTORE_CHAR PROC PUSH DPL PUSH DPH PUSH ACC MOV DPTR,#MD1_BUF MOV A,R3 ;character counter ADD A,DPL MOV DPL,A CLR A ADDC A,DPH ;generate displacement MOV DPH,A POP ACC ADD A,#' ' ;translate MOVX @DPTR,A ;store POP DPH POP DPL INC R3 ;character counter RET ENDPROC *******************************************************************************LISTING 4-- The low-level routines get right down to the ground and take care of the gory details.;Index the sample pointer either forward or backwardINDEX_PTR PROC CJNE R5,#0,L?IP1 ;check direction INC DPTR ;forward RETL?IP1: PUSH ACC ;backward DEC DPL MOV A,DPL CJNE A,#-1,L?IP2 DEC DPHL?IP2: POP ACC RET ENDPROC;Position bit is in ACC into C in either a right or left shiftPOSITION_BIT PROC CJNE R5,#0,L?PB1 ;check direction RRC A ;forward RETL?PB1: RLC A RET ENDPROC ;Locate a 1 bit, either msb or lsb;output: C=1 if bit is a oneLOCATE_BIT PROC CJNE R5,#0,L?LB1 ;check direction MOV C,ACC.0 ;forward RETL?LB1: MOV C,ACC.7 ;backward RET ENDPROC *******************************************************************************Contact: Mag-Tek, Inc. 20725 S. Annalee Ave. Carson, CA 90746 (213) 631-8602 fax: (213) 631-3956*******************************************************************************-- _ __ | __ | ` __ __ clafave@holonet.net | | __| ~|~ __|| ||__| Beaverton, Oregon USA |__ |_ |__| | |__| \/ |__. GO BLAZERS!