The Gold Card

This is an adapted, translated, and updated version of an article that appeared earlier in Hack-Tic, the Dutch hacker magazine, issue 24-25.

In Holland the phone company is called PTT-Telecom, and they are mighty proud of their new card-phones.  And they should be: they take the old-style optical cards, the newer chipcards as well as magnetic cards of all sorts.  The phones are built by a firm called Landis+Gyr and they look nice too.

This article deals with the prepaid chipcards as they are being used in a number of countries world-wide.  To make these cards cheap they had to make them dumb.  Very, very, very dumb.  In fact there is not much more on these cards than a little EPROM or EEPROM and a counter.

There are two types of prepaid chipcards for telephones, and one type is actually a little bit more intelligent than the other.  Here is what the cards do.

    

Cards of Type 1

This is the oldest type of card.  It comes in two varieties.  One is being used in France and Monaco, the other in Sweden, Spain, Norway, Andorra, Ireland, Portugal, The Czech Republic, Gabon, and Finland.  The phone talks to the cards using a synchronous protocol and they are built using NMOS technology.  They contain a 256-bit EPROM of which 96-bits are write protected using a hardware fuse.  The chip uses 85 mW when it's being read, needs 21 volts to program and has a 500 ns access time.

Chip Position

The chip could be in two different places on the card.  The first position is called AFNOR, and it's the old position the French used to use.  The new position is an International Standards Organization (ISO) norm, and therefore we'll call it the "ISO Position."  If you decide to build your own reader-writer you'll probably only need to worry about the ISO Position: even the French have switched to the ISO Position, so AFNOR cards are becoming rare.

To read the drawings: the cards are being held with the chip in the upper-left corner, contacts facing up.

What They Do

The next drawing is a timing diagram, which shows you what the communication with the card should look like.  If you read it you'll see that if Reset is pulled low and Clock is pulsed, then the card's internal counter resets.  If reset is then brought high you can "clock out" the data bits to the output pin one by one.

If you raise Not-Read-Write and put the programming voltage on the Vpp pin and pulse the Clock, you program the bit that you jumped to using only the clock.  This bit will go from 1 to 0.  

A few things to keep in mind: all signals in this drawing except Vpp are TTL-level.  That means a low is 0 volts, a high is 5 volts.  The cards of this type that we tested with all run perfectly fine off the 3.3 volts coming out of a notebook's printer port.

The Reset, Clock, and R/W input pins can be directly connected to a PC's parallel port.  Vpp is switched between 5 and 21 volts.  The t1 and t2 time durations in the timing diagram must both be between 10 and 50 ms.  When reading the card, Vpp and Fuse must be at 5 volts.

The next two drawings show the memory contents of this card's two varieties.

        

Security

The chip on the card does not let you write bits back to 1, so raising the value of your card through normal interaction does not work.  Because the whole chip is EPROM you could try to erase it.  This is going to be tough, because the plastic that the chip is embedded in is totally opaque at ultraviolet wavelength.  If you do succeed you'll have to re-write the first 96-bits containing country-code, card-type, etc.  This is also not easy, because the card has a hardware fuse that is quite literally burned.

Conclusion: filling up empty cards is not easy.

Cards of Type 2

Of the two outdated systems, this is the newest one.  Cards are being used in Holland, Germany, and Greece.  They don't need 21 volts anymore and they're just a little smarter than the Type 1 cards.  The chips are always in the ISO Position.

What They Do

When looking at the timing diagrams you'll notice the internal counter going back to zero when a clock pulse happens within a reset pulse.  As soon as Reset goes low, the corresponding memory bit is output through the output pin.  Every rising flank on the clock pin increases the internal address counter, but the corresponding bit does not appear on the output pin until clock goes low again (Part A of the drawing).

The number of units left on the card is stored in five bytes that work as an abacus.  The amount is stored octally, and the value of a byte is determined by the number of bits at the 1 position, regardless of their position in the byte.  The bits in the counter can be written to zero.  A whole byte can be written back to $FF, but only if a bit in the higher-value byte is erased at the same time.  At best the value of the card stays the same, it never goes up.

The first byte of the counter contains only four usable bits, the first bit (64) is a card-enable that is zeroed-out when the card initializes.  The next three bits (65-67) are sometimes used for tests in the counter-area during production.

The maximal value for the card thus becomes 5 * 4096 = 20480 units.

In Holland a unit is a cent (Guilder/100), in Germany it's a Pfennig (Mark/100), and in Greece they are actual telephone cost-pulses.

If the phone booth wants to write a bit to zero it clocks there and then it does a reset pulse followed by a clock pulse.  The reset pulse means a write-operation is in progress and the next clock pulse should not be used to increment the internal counter, but to do the actual write instead (B in timing diagram).

The phone could also write a bit and write all the bits in the byte below that back to 1.  This is done by just going through the write operation twice.  The first time it does the write time, the second time signals the card to set the byte below the current one to $FF (C in timing diagram).  This operation is called "erase" in all the documentation we have.  Both during write and erase the clock should be on for at least 10 milliseconds.

The next drawing shows the memory content for this card type.  The issuer code is always $80 in Holland.  The byte with "Specific Data" is EEPROM that can only be written to by the manufacturer.  The documentation is cryptic, but it's rumored to have to do with chip testing.  The byte is $FF in all cards we've seen so far.  The five bytes that are issuer-determined could be anything.

In Holland the first one gives you the manufacturer ($CA Gemplus, $2A Solaic).  The second byte is the value when bought.  $22 is 10 guilders (1000 units), $42 is 500 units (5 guilders), and $62 is the 25 guilder card.  There can be no more units on the card than this maximum.

Manufacturing

The data that we have on this type of chip tells a few things about the state in which the PTT's get the cards.  The cards are locked for transportation using a "transport code" of three bytes.  Only if you know these three bytes can you program the chip and turn it on to become a phonecard.

The memory map in the "transport state" is as follows: 0-23 are static, 24-71 cannot be erased, there is "enable memory" (?) in bits 72-79 and the transport code is in bits 80-103.  These bits cannot be read however.  It seems the code has to be clocked-in (!) though the output pin and the chip compares and acts accordingly.

Security

Although this card does allow you to set bits back to 1 again, the card is smart enough not to let you do that unless you reset a bit in a higher register, so the effect is neutral at best.  We tried to fool the card, but all the obvious stuff doesn't work.  Maybe something works using UV-light, but it's not very likely.

We have no idea how to enter the transport code after production.  It is well possible that the card can be reprogrammed after entering the code.  There may well be hacking potential here.  By the way, not all the cards have a different serial number in the five telco bytes: each batch of 100 cards is electronically identical.

Building Your Own Reader/Writer

You can have your computer play payphone.

Using the schematic below you can build a reader/writer that can read cards of Type 1 and 2 and write to cards of Type 2.  If you wish to write to Type 1 cards you can add in the 21 volt part yourself.

There is very little hardware to build as you can see.  The software to go with this is PHONE.EXE.  Just hook this up to your PC's parallel port and you're set.  Note that cards of Type 2 will not run off the 3.3 volts often found on notebook printer ports.  The Card Detect contact can be left out.

Our software will also think a card is inserted when you press a key.

At the end of this article there is a source called: phone.c

If that is compiled using Borland C++ with options -O2 -2 or with Microsoft C 6.0 with options -G2r -Ozax then you can do everything the phone can: read the entire card (-v for more information), writing (-w [bit]) or erasing (-e [bit]) bits.

You could of course modify the program so that a new (lower) value is programmed in just one step, but that is left as an exercise to the reader.

Phone -t brings you in a test mode: keys "p", "r", "c", and "f" toggle Power, Reset, Clock, and French Reset respectively.

A real phone reads the card in a rather peculiar way.  Option -r simulates this behavior.

Listening In

With the help of this "snooper" schematic, you can get your PC to listen in on the conversation between a card and a phone.

You can write a program to monitor what happens on the printer port bits in real-time.  Takes at least an i386 to be fast enough to see what is going on.  This will work also on notebooks with the 3.3 volt printer port.

The left part of the schematic is hooked up in parallel with the phone and card, the right goes to the printer port on the PC.

Gold Card

Many countries have these nasty steel doors that close behind the card as you insert it.  The Dutch, being naturally paranoid and miserly, only insert their card in the phone if they can still see it.  So the Dutch phonecards stay in sight during the conversation.  This makes it very possible to build a fake chipcard that has wires coming out in the back and then simulating the entire chipcard from a notebook computer.  This potentially gives you an "always full" phonecard.

The program must however do exactly the same thing as the real card.  We made a fake chipcard by peeling the chip out of an empty card and soldering (careful, not too hot!) thin transformer wires to the contacts.  The program we made is called KPN-GOLD.EXE, and it reads a dumpfile in the same format as made by PHONE.EXE.  Of course the program also participates in the whole abacus countdown routine.  But as soon as power drops (card removed from telephone), the card goes back to its original value.  You can also use this combination of fake chipcard and software to test your own chipcard reader-writer.  We have been playing with three PCs.  One as phone, one as card, and one as snooper, to tap the conversation.

The V+ in the emulator schematic is attached to Pin 1 of the CD4049 and Pin 16 of the CD4053.  Pins 14 and 8 of the CD4049 and Pins 3, 4, 5, 6, 7, 8, and 9 of the CD4053 are attached to ground.  In the vicinity of the chips you put a 100 nF (0.1 µF) capacitor between V+ and ground.

Security Logic?

Supposedly the cards have a special "security mechanism" that keeps the phone from accepting an emulator as the real card.  We only read about this mechanism after we had successfully emulated the card, but we did notice something funny.

At the end of the first reading cycle the phone issues a very fast reset of only a few microseconds, and it expects the card to do the correct behavior.  We solved this by having the entire reset behavior done by a bit of hardware in the emulator.  Maybe we hacked the "security mechanism" this way.  Ah well...

More Intelligent Cards

There are also chipcards out there that have complete microprocessors with RAM and EEPROM on them.  These cards are used in the new PAN-European GSM mobile telephone system for instance.

In Germany these cellular telephony cards also work in payphones: the call shows up on your cellular phone bill.

All the Dutch phones can do this too, and rumor has it that there will be a whole range of specialized chipcards.  There may be cards that can only call one number (nice business card).  This type of card can be secured much better with the use of challenge-response tricks and cryptography.

Maybe we'll write about all this in a future issue.

The Law

In most countries the use of the emulator to make free calls would be against a law or two.

Phone companies are said not be amused by it either.  We published this information to show that all the "secure systems" that they are so proud of turn out to be flaky every time you take a closer look.

Because the PTT tends to deny this type of thing if you just say it, we did it.  No, we don't spread KPN-GOLD.C or KPN-GOLD.EXE, don't even ask.

Update

Since we published this in August, the PTT did something to the phones that makes them able to distinguish between our emulator and the real card.

They were real amused to have done it a week before Hack-Tic came out.  I guess we talked too much about this whole project before it was in print.

In a future issue, we'll tell you what they did to secure it.  Remember, these cards are so dumb, it can't be hard to fool the phone.

phone.c:

#include <stdio.h>
#include <bios.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>

/* outputs:  */
#define DETECT 0x10
#define POWER 0x08
#define ISO_RESET 0x04
#define R_W 0x04
#define CLOCK 0x02
#define FRENCH_RESET 0x01

/*  inputs: */
#define I_O 0x80
#define CARD 0x20

unsigned int pp;
unsigned char data[32];
unsigned char bits[256];

int num_data;
int one = 0;
int verbose = 0;
int silent = 0;
int go = 0;

struct card_country {
  unsigned char num;
  char *name;
  unsigned char type;
};

struct card_country cc[] = {
  { 0x01, "Demoland", 1 },
  { 0x03, "France", 0 },
  { 0x1E, "Sweden", 1 },
  { 0x2F, "Germany", 2 },
  { 0x30, "Norway", 1 },
  { 0x33, "Andorra", 1 },
  { 0x3B, "Greece", 2 },
  { 0x3C, "Ireland", 1 },
  { 0x47, "Portugal", 1 },
  { 0x55, "Czech Republic", 1 },
  { 0x5F, "Gabon", 1 },
  { 0x65, "Finland", 1 },
  { 0x77, "Netherlands", 2 },
  { 0, "Country unknown", -1 }
};

struct card_country *country(unsigned char val)
{
  struct card_country *ccp = cc;
  while (ccp->num && ccp->num != val)
    ccp++;
  return (ccp);
}

unsigned char _bits(unsigned char val)
{
  unsigned char mask = Ox80, count = 0;
  for (; mask; mask >>= 1)
    if (val & mask)
      count++;
  return (count);
}

void initbits(void)
{
  int i;
  for (i = 0; i < 256; i++)
    bits[i] = _bits(i);
}

unsigned int bcd(unsigned char hi, unsigned char lo)
{
  return ((lo & 0xF) + (lo >> 4) * 10 + (hi & 0x0F) * 100 + (hi >> 4) * 1000);
}

void delay(unsigned int ms)
{
  unsigned long tmp = 2000L * ms;
  while (tmp--);
}

void output(unsigned char val)
{
  outp(pp, val);
  delay(1);
}

unsigned char input_bit(void)
{
  return ((inp(pp + 1) & I_O) ? !one : one);
}

#define input_byte() (inp(pp+1) & (I_O|CARD))

unsigned char card_in(void)
{
  return ((inp(pp + 1) & CARD) ? 0 : 1);
}

const unsigned char val[] = {
  128, 64, 32, 16, 8, 4, 2, 1
};

void read_data(int how)
{
  unsigned int i, j;

  /* reset card */
  output(POWER);
  delay(10);
  output(POWER | ISO_RESSET);
  output(POWER | ISO_RESET | CLOCK);
  output(POWER | ISO_RESET);
  delay(10);
  output(POWER | FRENCH_RESET);

  /* clock bits in */
  for (i = 0; i < num_data / 8; i++) {
    data[i] = 0;
    for (j = 0; j < 8; j++) {
      if (input_bit())
        data[i] |= val[j];
      /* clock next bit */
      output(POWER | CLOCK | FRENCH_RESET);
      output(POWER | FRENCH_RESET);
    }
  }
  output(0);
}

void write_bit_iso(unsigned int index)
{
  unsigned int i;
  /* reset card */
  output(POWER);
  delay(10);
  output(POWER | ISO_RESET);
  output(POWER | CLOCK | ISO_RESET);
  output(POWER | ISO_RESET);
  output(POWER);

  /* clock bits in */
  for (i = 0; i < num_data; i++) {
    if (i == index) {
      if (!(data[i / 8] & (0x80 >> (i & 7))))
        printf("wiping 0 bit!\n");
      output(POWER | ISO_RESET);
      delay(10);
      output(POWER);
      delay(10);
      output(POWER | CLOCK);
      delay(200);
      output(POWER);
    }
    /* clock next bit */
    output(POWER | CLOCK);
    output(POWER);
  }
  output(0);
}

void erase(unsigned int index)
{
  unsigned int i;

  /* reset card */
  output(POWER);
  delay(10);
  output(POWER | ISO_RESET);
  output(POWER | CLOCK | ISO_RESET);
  output(POWER | ISO_RESET);
  output(POWER);

  /* clock bits in */
  for (i = 0; i < num_data; i++) {
    if (i == index) {
      if (!(data[i / 8] & (0x80 >> (i & 7))))
        printf("erasing 0 bit'\n");

      output(POWER | ISO_RESET);
      delay(10);
      output(POWER);
      delay(10);
      output(POWER | CLOCK);
      delay(200);
      output(POWER);
      delay(10);
      output(POWER | ISO_RESET);
      delay(10);
      output(POWER);
      delay(10);
      output(POWER | CLOCK);
      delay(200);
      output(POWER);
      delay(10);
    }
    /* clock next bit */
    output(POWER | CLOCK);
    output(POWER);
  }
  output(0);
}

char bitstring(unsigned char val)
{

  static char buf[9];
  char *s = buf;
  unsigned char mask = 0x80;
  for (; mask; mask >>= 1)
    if (val & mask)
      *s++ = '1';
    else
      *s++ = '0';
  *s = 0;
  return buf;
}

#define STEP 4
void print_data(void)
{
  int i, j;
  for (i = 0; i < num_data / 8; i += STEP) {
    if (verbose)
      printf("%3d - %3d\t", i * 8, min(num_data, (i + STEP) * 8) - 1);
    for (j = 0; j < STEP; j++)
      if (i + j < num_data / 8)
        printf("%s ", bitstring(data[i + j]));
      else
        printf(" ");
    printf("\t");
    for (j = 0; j < STEP && i + <num_data / 8; j++)
      printf("%02X ", data[i + j]);
    printf("\t");
    for (j = 0; j < STEP; j++)
      if (i + j < num_data / 8 && isprint(data[i + j]))
        printf("%c", data[i + j]);
      else
        printf(".");
    printf("\n");
  }
}

void show_units(unsigned int burn, unsigned int maxval, unsigned char *p)
{
  unsigned int val = 0;
  int i = 20;

  if (verbose)
    printf("Value area: \n");
  do {
    if (verbose)
      printf("%s (%02X)\t%3d\n", bitstring(*p), *p, bits[*p]);
    val += bits[*p];
  }
  while (*p++ == 0xFF && --i);
  if (verbose)
    printf("\t\t===\n\t\t%3d out of %d bits burned\n", val, maxval);

  printf("%u(+%u) units - %u units left\n", maxval - burn, burn, maxval - val);
}

void show_units2(unsigned char *p)
{
  unsigned long val = 0;
  int i = 5;
  unsigned long pow = 4096;
  if (verbose)
    printf("Value area:\n");
  for (; i; i--, pow /= 8) {
    if (verbose)
      printf("%s (%02X)\t%d * %4lu = %5lu\n", bitstring(*p), *p, bits[*p], pow, pow * bits[*p]);
    val += pow * bits[*p++];
  }
  if (verbose)
    printf("\t\t=====\n\t\t %5lu units\n", val);
  else
    printf("Value %lu units\n", val);
}

void print_type(void)
{
  unsigned int val;
  struct card_country *ccp;
  unsigned char cou;
  if ((cou = data[1]) == 0x83)
    cou = data[11];
  ccp = country(cou);
  printf("%s - ", ccp->name);

  switch (ccp->type) {
    case 0:
      switch (data[11]) {
        case 0x13:
          show_units(10, 130, data + 12);
          break;
        case 0x06:
          show_units(10, 60, data + 12);
          break;
        case 0x15:
          show_units(0, 40, data + 12);
          break;
        default:
          printf("value unknown\n");
      }
      break;
    case 1:
      val = bcd(data[2] & 0xF, data[3]);
      show_units(2, val, data + 12);
      break;
    case 2:
      show_units2(data + 8);
      break;
    default:
      printf("card type unknown\n");
      if (num_data == 128)
        show_units2(data + 8);
      else
        show_units(0, 0, data + 12);
  }
}

void dotestmode(void)
{
  unsigned char nw, ow = input_byte();
  unsigned char ov = DETECT;
  if (verbose)
    printf("Test mode: \n");
  while (1) {
    output(ov);
    printf("\r%s - %s - %s - %s : %s - %s",
           (ov & POWER) ? "Power" : "       ",
           (ov & CLOCK) ? "Clock" : "       ",
           (ov & ISO_RESET) ? "I Reset" : "      ",
           (ov & FRENCH_RESET) ? "F Reset" : "      ",
           (ow & CARD) ? "      " : "Card", (ow & I_O) ? "Output" : "      ");
    while ((nw = input_byte()) == ow && !_bios_keybrd(_KEYBRD_READY));
    if (nw == ow) {
      switch (_bios_keybrd(_KEYBRD_READ) & 0xFF) {
        case 'p':
          ov ^= POWER;
          break;
        case 'r':
          ov ^= ISO_RESET;
          break;
        case 'f':
          ov ^= FRENCH_RESET;
          break;
        case 'c':
          ov ^= CLOCK;
          break;
        case 27:
        case 'q':
          output(0);
          return;
      }
    } else
      ow = nw;
  }
}

void usage(void)
{
  printf("phone [-cdfhirstv] [-e<n>] [-w<n>] [<outputfile>] \n"
         "\t-c\tcontinuous read\n" "\t-d\tignore card detect\n"
         "\t-e<n>\twrite bit n and erase next byte\n"
         "\t-f\tforce french length\n" "\t-h,-?\tthis help\n"
         "\t-i\tinvert input bits\n" "\t-r\tread as a real phone\n"
         "\t-s\tsilent mode\n" "\t-t\ttest mode\n" "\t-v\tverbose mode\n"
         "\t-w<n>\twrite bit\n\n");

}

void main(int argc, char *argv[])
{
  int write_bit = 0;
  int erase_bit = 0;
  int wait_card = 0;
  int real_read = 0;
  char *of = NULL;
  int test = 0;
  char c;

  pp = *(unsigned int far *) 0x408;
  /*look up LPT1: */ num_data = 16 * 8;
  /* default 128 bit cards */

  while (argc-- > 1) {
    argv++;
    if (argv[0][0] == '-') {
      while ((c = *++(argv[0])) != 0) {
        switch (c) {
          case 'c':
            go = 1;
            break;
          case '?':
          case 'h':
            usage();
            return;
          case 'f':
            num_data = 32 * 8;
            break;
          case 'w':
            write_bit = atoi(argv[0] + 1);
            break;
          case 'd':
            wait_card = 1;
            break;
          case 'e':
            erase_bit = atoi(argv[0] + 1);
            break;
          case 'i':
            one = !one;
            break;
          case 'r':
            real_read = 1;
            break;
          case 's':
            silent = 1;
            break;
          case 't':
            test = 1;
            break;
          case 'v':
            verbose = 1;
            printf("Phone v1.0\t\t\t\t(C)opywrong 1994 by Hack-Tic magazine\n");
            break;
        }
      }
    } else
      of = argv[0];
  }
  if (verbose)
    printf("Reading on printer port 0x%X\n", pp);
  if (test) {
    dotestmode();
    return;
  }
  initbits();

  output(DETECT);
  while (wait_card && !_bios_keybrd(_KEYBRD_READY));
  while (!card_in() && !_bios_keybrd(_KEYBRD_READY));

  if (go) {
    while (inp(96) != 1)
      read_data(real_read);
  } else {
    delay(20);

    read_data(real_read);

    if (!silent)
      print_data();
    print_type();

    if (write_bit) {
      delay(20);

      write_bit_iso(write_bit);
      read_data(real_read);
      if (!silent)
        print_data();
      print_type();
    }
    if (erase_bit) {
      delay(20);
      erase(erase_bit);
      read_data(real_read);
      if (!silent)
        print_data();
      print_type();
    }
    if (of) {
      FILE *f;
      if ((f = fopen(of, "wb")) != NULL) {
        fwrite(data, 1, num_data / 8, f);
        fclose(f);
      } else
        perror(of);
    }
  }
  while (_bios_keybrd(_KEYBRD_READY))
    _bios_keybrd(_KEYBRD_ READ);
}

Code: phone.c

Return to $2600 Index