Smartair data format
The intention of this repo is to document how the data format of cards are in SmartAir
The installation gets programmed with an "Entry point" to the User sector in the card using the programming tool.
The rest is defined by the data in the card.
User sector format
| X | 0xX0 | 0xX1 | 0xX2 | 0xX3 | 0xX4 | 0xX5 | 0xX6 | 0xX7 | 0xX8 | 0xX9 | 0xXA | 0xXB | 0xXC | 0xXD | 0xXE | 0xXF |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0x0X | Card Config | LICSENSE? | SITE ID | .. | .. | .. | ? | User ID | .. | 00 | Encoding Time | .. | .. | .. | 00 | Valid From |
| 0x1X | .. | .. | Valid Until | .. | .. | Pin code | .. | .. | CardConfig | UOC Block ADDR | .. | .. | Grants | .. | .. | .. |
| 0x2X | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
Decoded
CardConfig:
[Enchanced encryptage info](Enhanced Encryptage.md)
0: Enhanced encryptage
1: ?
2: ?
3: ?
4: ?
5: ?
6: ?
7: ?
Licsense? We don't know but we assume it's config based on the licsense given from Tesa
SiteID: The site id which is embedded in the licsense from Tesa
UserID: A 2 Byte sequential increasing number which increases for each cardholder added in the TS1000 software
Encoding time 4 Bytes with 1 minute accuracy
Valid from/until: 3 Byte dates with 10 minute resolution
Time formats
Year = 2000 + uint7(Bit 0-6)
Month = uint4(7-9)
Day = uint5(11-15)
Hour = uint4(16-20)
Minutes can be with 10 or 1 minute resolution 1 minute is used for encoding time while 10 for valid from/to
Minutes *10 = uint3(21-24[23 if low accuracy])
Minutes *1 = uint3(25-27)
Some issues with minutes handling will likely fix later but for now not a priority
[{"op":"From Hex","args":["Auto"]},{"op":"To Binary","args":["None",8]},{"op":"Regular expression","args":["User defined","^([0|1]{7})([0|1]{4})([0|1]{5})([0|1]{4})(([0|1]{4})|([0|1]{3})([0|1]{4}).*)$",true,true,false,false,false,false,"List capture groups"]},{"op":"Find / Replace","args":[{"option":"Regex","string":"([0|1]{8}\\n)"},"\\n",true,false,true,false]},{"op":"Find / Replace","args":[{"option":"Regex","string":"(undefined\\n)"},"",true,false,false,false]},{"op":"Fork","args":["\\n",",",false]},{"op":"From Binary","args":["Space",8]},{"op":"To Decimal","args":["Space",false]},{"op":"Merge","args":[true]},{"op":"Find / Replace","args":[{"option":"Regex","string":"^(.*)$"},"Year,Month,Day,Hour,Minute*10,Minute*1\\n$1",true,false,true,false]},{"op":"To Table","args":[",","\\r\\n",false,"ASCII"]}]
PinCode: 3 bytes with the users pin code terminated with FF if the pin is only 4 digits
Card Config(0x18): Seems to act somewhat like "User flags" or similar
0: ?
1: Disabled user(Extended opening time)
2: ?
3: Audit 1?
4: ?
5: ?
6: Audit 2?
7: ?
Audit 1/2 are assumptions they seem to be related to the "Cardholder collects audit trail" and "Do not open if audit is full"
UOC Block:
Reversed endianess of the location where the Update on card config block is located
00 c0 = 00 0c = 12 = Block 0 Sector 3
Grants: Each grant is assigned a bit position so a reader configured to accept grants just checks expirations of the card and that the bit configured has been set on the card presented used for things like Pool access, Elevator floors or other generic functions you want to allow many people with a credential to do without keeping a big locking plan in the lock
Mifare KEYS
For mifare classic the cards use a Site Specific key as keyA the last 4 bytes of the key is the SiteID and the readers auth with KeyA making it possible to mint a valid credential by using mfkey32 on a reader.
key B is static and the same across all sites E7 31 68 53 E7 31