Dewi (dewimorgan) wrote,
Dewi
dewimorgan

Decoding magnetic strips

[Edit: much kudos to anfractuosity for taking this idea and running with it, effectively making OCR software to read dusted magstripes :D]

I've recently become interested in how magnetic strips are encoded.

Most credit for this should go to an Australian chap going by the name anaglyph, who made a post on his blog pointing out that rust particles could be used to view magstripes.

He was investigating claims by a company that "tags", with magstripes on them, could be used to repel insect pests. I noticed that some pattern was available in his photo of the rust-dusted magstripe, and the data itself could be decoded with the naked eye.

I leave it to him to document the specifics of the tags, but what follows is a summary of my discoveries about decoding magstripes. Mostly so that I've got it in one place and can reproduce it in years to come if I need to :)

Converting magnetism to bits

Normally, data is stored by "magnetic flux reversal". Sure, there are other ways: sometimes it's stored as an analog sound wave like on audio tape, or some such. But pretty much every single card you're ever likely to see in use will use some variation of the following.

A completely blank card contains no data at all, not even zeroes. It has the magstripe magnetised as if a magnet had swiped past it (which is probably exactly what happened), so one end of the stripe is north, the other is south, and it's like a single large weak magnet.

That is, the strip's magnetisation will look something like:
  NnnnnnnnnnnnnnnnnnnnnnnnnsssssssssssssssssssssssS

Dusting a blank card with rust would give a fairly even covering, with slightly more clumped at the ends of the strip, because the magnetic flux is strongest at discontinuities (so I used capitals there).

A card encoded card with all zeroes, however, has the magnetisation of the card swapped once for each bit, so five consecutive bits would be encoded as five small sections of magnet with similar poles together:
  NnnnnsssS SssssnnnN NnnnnsssS SssssnnnN NnnnnsssS
      0         0         0         0         0

Ones are just like zeroes, but they change polarity exactly twice as often:
  NnsS SsnN NnsS SsnN NnsS SsnN NnsS SsnN NnsS SsnN
      1         1         1         1         1

That is, the little magnets for "1" are half the size of the ones for "0", so there's two of them for each "1".
A bunch of ones and zeroes will look like:
  NnsS SsnN SssssnnnN NnnnnsssS NnsS SsnN NnsS SsnN
      1         0         0         1         1

Now, the gaps I've shown between those magnets aren't really there, they squidge right up against each other, but they're to draw your attention to the points on each of those magnets where the magnetic flux is strongest.

Rust isn't picky about north or south, but it is picky about field strength. It sticks best where the field's strong. So what you get from the above bit pattern is dust that clumps something like:
  NnsS SsnN NnnnnsssN SssssnnnN NnsS SsnN NnsS SsnN
      1         0         0         1         1
  #==###==###=======###=======###==###==###==###==#
or if you're using slightly less fine dust:
  ############=====#####=====######################


So zeroes look like "gaps", and ones look like "blobs". The size of these can be read by comparing them to the "clocking bits", which are nice and easy to read.

Converting bits to bytes

So now you know how to read ones and zeroes, how do you convert those into values? How they're encoded varies, but there's a surprising amount of standardisation.

Firstly, the magstripe is almost always located on the back of the card, and goes along it lengthways, 0.223 inches (5.56 mm) from the closest edge (which I'll call the "top"), and is almost always 0.375 inches (9.52 mm) wide.

The data is almost always recorded in three parallel "tracks", each 0.110 inches (2.79 mm) wide. In some cards, track 3 is missing, and a correspondingly narrower magstripe is used... but the reader typically won't know that, and will treat track 3 as still existing and just containing no data.

The bits are usually recorded at one of two densities: 210 bits per inch, or 75 bits per inch. Sometimes, different tracks use different densities, in which case normally tracks 1 and 3 are high density, and track 2 is low density.

If you look at the back of any credit card or other magstripe card, in "landscape" orientation, with the magstripe facing towards you, and closest to the "top" edge of the card, then track 1 is the row at the top of the magstripe, track 2 in the middle, and track 3 at the bottom, if it's there at all.

Each track can either contain 7-bit alphanumeric characters stored as DEC-SIXBIT plus one bit of odd parity, or 5-bit numeric characters stored as four-bit BCD plus one bit of odd parity. Most commonly (always, for financial cards), track 1 is 7-bit, tracks 2 and 3 are 5-bit.

But what does that mean, for us card-decoders? Well, parity makes life easy for us. It means we know what to do once we've read in a line of values like (read from left to right on the magstripe):
00000000101000101001010000100110010001001010000100110010011001000110010101001010100100011010111111110110000000000

Parity means that one bit in each group (of 5 or 7) is either set to 1 or 0, in order to make sure there's always an odd number of 1s in the group. And looking at the above list of 1s and zeroes, there's only one way to split it. There's no way to split it into groups of 5 so that every group has either 1, 3, or 5 "1"s, and there's only a single way to split it into groups of seven:
1010001 0100101 0000100 1100100 0100101 0000100 1100100 1100100 0110010 1010010 1010010 0011010 1111111 1011000

Note that all those leading and trailing zeroes weren't grouped together to have odd parity, so we ignore them: if they were DATA zeroes, and part of the data, then they'd have had a 1 in them for the parity bit. Their actual purpose is as individual "clocking bits", to let the card reader calculate the speed the card's being swiped, and synch with that.

Converting bytes to characters

To convert the bytes to characters, first, ignore the last bit of each byte: it's the "parity" bit, which has already served its purpose.
101000 010010 000010 110010 010010 000010 110010 110010 011001 101001 101001 001101 111111 101100

Then, swap those bytes around: currently, they're stored least-significant-bit first, and we're used to reading numbers the other way round (this and the next steps can be done as a single step using a script).
000101 010010 010000 010011 010010 010000 010011 010011 100110 100101 100101 101100 111111 001101

Then, convert them to numbers (wincalc can do this for you, or just do it in your head).
5 18 16 19 18 16 19 19 38 37 37 44 63 13

Add 0x20 (32) to each value for 7-bit tracks, or 0x30 (48) for 5-bit tracks.
37 50 48 51 50 48 51 51 70 69 69 76 95 45

That gives you the ascii value, so convert that to characters.
% 2 0 3 2 0 3 3 F E E L _ -


Converting characters to values

But what does it *mean*?

Well, that depends on the data format. Once again, there's a fair bit of standardisation.


Sentinel characters

Sentinel characters are the "framing characters" that let the reader know when the swiping has begun and ended, so they are at the beginning and end of the data. They ideally also let the reader uniquely know which WAY the card was swiped, so it can properly decode the data. Because of this, their values are typically chosen so that the start sentinel cannot be confused with a reversed end sentinel.

5-bit tracks normally begin with a '%' (1010001) as the start sentinel, then have the data, then '?' (1111100) as the end sentinel, possibly followed by one last character.

7-bit tracks normally begin with ';' (11010) as the start sentinel, then have the data, then '?' (11111) as the end sentinel, possibly followed by one last character.


LRC characters

That "one last character" mentioned above is also considered part of the "framing characters", and like the start and end sentinel, is typically discarded by reading software. It's called the Longitudinal Redundancy Check (LRC) character, and is used to verify that the data is correct. For each bit in this character (other than the parity bit, which is worked out for this character as normal), it is set to 1 if there are an odd number of other bytes (including sentinels) that have that bit set, and 0 of there's an even number. This is most easily generated by XORing all the other characters together.


Separator characters

Since each track may store multiple fields of varying length, the fields need to be separated. The usual characters for this are '$' and '^' (7-bit tracks) and '=' (both 5 and 7-bit tracks).

What these fields MEAN, though, depends on the card, and is a topic for another post.

Further reading and references:

Whole bunch of magstripe docs
Track format of magnetic stripe cards - L. Padilla
Wikipedia page
Card-O-Rama: Magnetic Stripe Technology and Beyond by Count Zero, Phrack 37.
Tags: cards, creditcard, geeky, hacking, magstripe
Subscribe

Posts from This Journal “hacking” Tag

  • Modding the Pip-Boy

    [This post is a work in progress, will be edited whenever I make progress... I expect this project to never be fully "finished".] So I've been…

  • NatWest card readers - what's the deal?

    How hackable are they? NatWest has been sending out free card readers, which it requires you to have in order to do certain online banking things.…

  • Dragonwars savegame format

    Been playing DragonWars a little lately. Nice enough game, but... I think I'll give up on it. In order to play all 4 games I intended to (Dragon…

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 10 comments