Podorozhnik - metrodroid/metrodroid GitHub Wiki

Podorozhnik card image

Podorozhnik (Подорожник) is the ticketing system used in Saint Petersburg, Russia. It uses MIFARE Classic 4K cards, and some cards also act as Troika.

Support for this card is added in Metrodroid 2.9.35.

These cards store data in sector 4, which has a fixed key common to every card. You will need to acquire this key and install it into Metrodroid. Metrodroid identifies these cards by the key.

All numbers on the card are stored as little-endian. Record lengths are shown in bytes, inclusive of the first and last bytes, unless otherwise specified.

Serial number

The serial number follows ISO7812. Its layout goes as follows

Number of digits Value
1 9 = assigned by national body
3 643 = Russia
4 3078 = Assignment for Podorozhnik
17 Little-endian of tag ID
1 Luhn checksum

Block layout

Terminology: filler sector is sector filled with zeros and key being ffffffffffff, supposedly those are unused

For standard card:

Sector Block Content
0 0 Manufacturing data/UID
0 1-2 zero-filled
1-3 0-2 filler
4 0 Balance data (valueblock)
4 1 Balance data (valueblock copy of block 0)
4 2 Topup data
5 0 Validation data
5 1 Transport data
5 2 Transport data (copy of block 1)
6-7 0-2 filler
8 0-2 unknown
9 0-2 trip counters valueblock
10 0 const
10 1 unknown
10 2 zero filled
11 0-1 empty valueblock
11 2 zero-filled
12 0-2 unknown, somehow related to bus
13-15 0-2 filler
16-39 0-2 zero filled

For card combined with Troika there are following changes:

  • Sectors 1-3,6-9,13-15 are used for Troika, same way as normal Troika
  • Sectors 4-5`,10-12 stay the same
  • Sectors 8 and 9 are relocated to sectors 30 and 31 respectively
  • Keys for sectors 16-29, 32-33 and 36-39 are unknown
  • Sectors 34-35 are additional sectors for Troika

Balance data (sector 4, blocks 0 and 1)

This block is MIFARE value block storing card balance

First Last Length Field description
0 3 4 Card balance, in kopeyka (0.01 RUB)
4 7 4 Binary-not of card balance
8 11 4 Card balance (copy)
12 15 4 Const 00ff00ff

block 1 is verbatim copy of block 0

Topup data (sector 4, block 2)

First Last Length Field description
0 1 2 Const fc00
2 4 3 Last topup timestamp, in minutes after 2010-01-01
5 5 1 Topup agency
6 7 2 Topup machine ID
8 10 3 Last topup, in kopeyka (0.01 RUB)
11 11 1 Const 01 if topup ever happened
12 15 4 Hash

Validation data (sector 5, blocks 0)

First Last Length Field description
0 2 3 Last spend timestamp, in minutes after 2010-01-01
3 3 1 Last transport (1 = subway, 4 = bus)
4 5 2 Last validator
6 9 4 Last spend, in kopeyka (0.01 RUB)
10 13 4 Always zero
14 15 2 Hash

Transport data (sector 5, blocks 1 and 2)

First Last Length Field description
0 0 1 Subway trips counter
1 1 1 Ground trips counter
2 4 3 Last trip timestamp, in minutes after 2010-01-01
5 5 1 Always zero
6 9 4 Hash
10 15 6 Always zero

block 2 is verbatim copy of block 1

Trip counters Value blocks (sector 9 [pure] or 31 [hybrid])

Doesn't give any data other than already available in 5.1 and 5.2

This sector is relocated to 31 in hybrid cards

This is a Mifare value block

Block 2:

First Last Length Field description
0 2 3 Subway trips counter
3 3 1 Month/Year in months since January 2018
4 7 4 not of 0-3
8 11 4 copy of 0-3
12 15 4 Const 00ff00ff