mirror of
https://github.com/RfidResearchGroup/ChameleonMini.git
synced 2026-05-12 11:20:37 -07:00
Add decoding ATS in sniffing mode
(cherry picked from commit 1ef1af2)
This commit is contained in:
+107
-26
@@ -1,11 +1,19 @@
|
||||
import binascii
|
||||
import crcmod
|
||||
|
||||
from enum import Enum
|
||||
# Parameters for CRC_A
|
||||
CRC_INIT = 0x6363
|
||||
POLY = 0x11021
|
||||
CRC_A_func = crcmod.mkCrcFun(POLY, initCrc=CRC_INIT, xorOut=0)
|
||||
|
||||
|
||||
class ReaderCMD(Enum):
|
||||
NONE = 0
|
||||
RATS = 1
|
||||
PPS = 2
|
||||
|
||||
readerCMD = ReaderCMD.NONE
|
||||
|
||||
ReaderTrafficTypes = {
|
||||
"SEL":{
|
||||
0x93: "SEL_CL1 ",
|
||||
@@ -38,8 +46,20 @@ ReaderTrafficTypes = {
|
||||
CardTrafficTypes = {
|
||||
"SAK":{
|
||||
0x04: "UID NOT Complete ",
|
||||
0x24: "UID NOT Complete, PICC compliant with 14443-4",
|
||||
0x20: "UID complete, PICC compliant with 14443-4 ",
|
||||
0x00: "UID complete, PICC NOT compliant with 14443-4"
|
||||
},
|
||||
"FSCI": {
|
||||
0x0: "FSCC:16 ",
|
||||
0x1: "FSC:24 ",
|
||||
0x2: "FSC:32 ",
|
||||
0x3: "FSC:40 ",
|
||||
0x4: "FSC:48 ",
|
||||
0x5: "FSC:64 ",
|
||||
0x6: "FSC:96 ",
|
||||
0x7: "FSC:128 ",
|
||||
0x8: "FSC:256 "
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,66 +78,77 @@ def CRC_A_check(data):
|
||||
else:
|
||||
return False
|
||||
|
||||
def parseReader(data):
|
||||
def parseReader_3(data):
|
||||
byteCount = len(data)
|
||||
note = ""
|
||||
|
||||
# short frame commands
|
||||
if (byteCount == 1 and data[0] in ReaderTrafficTypes["SHORTFRAME"]):
|
||||
note += ReaderTrafficTypes["SHORTFRAME"][data[0]]
|
||||
note += ReaderTrafficTypes["SHORTFRAME"][data[0]]
|
||||
|
||||
# ANTICOLLISION command
|
||||
elif (byteCount<9 and byteCount > 1 and data[0] in ReaderTrafficTypes["SEL"] and data[1] & 0x88 == 0 ):
|
||||
elif (byteCount < 9 and byteCount > 1 and data[0] in ReaderTrafficTypes["SEL"] and data[1] & 0x88 == 0):
|
||||
note += "ATCOLI - "
|
||||
note += ReaderTrafficTypes["SEL"][data[0]]
|
||||
# note += "UID_CLn:" + binascii.hexlify(data[2:7]).decode() + " "
|
||||
# note += str((data[1] >> 4) & 0x0f) + "bytes + " + str(data[1] & 0x0f) + "bits "
|
||||
|
||||
# SELECT Command
|
||||
elif (byteCount== 9 and data[0] in ReaderTrafficTypes["SEL"] and data[1] == 0x70):
|
||||
elif (byteCount == 9 and data[0] in ReaderTrafficTypes["SEL"] and data[1] == 0x70):
|
||||
# TODO: distinguish CT+uid012+BCC and uid0123+BCC
|
||||
note += "SELECT - "
|
||||
note += ReaderTrafficTypes["SEL"][data[0]]
|
||||
note += "UID_CLn:" + binascii.hexlify(data[2:6]).decode() + " "
|
||||
# Check CRC for SELECT
|
||||
if(not CRC_A_check(data)):
|
||||
note+=" WRONG CRC "
|
||||
if (not CRC_A_check(data)):
|
||||
note += " WRONG CRC "
|
||||
# note += "7bytes + 0bits "
|
||||
# note += "CRC_A:"+data[7:9]
|
||||
# HALT Command
|
||||
elif (byteCount == 4 and data[0] == 0x50 and data[1] == 0x00):
|
||||
note += "HALT"
|
||||
|
||||
return note
|
||||
|
||||
def parseReader_4(data):
|
||||
byteCount = len(data)
|
||||
note = ""
|
||||
|
||||
# RATS
|
||||
elif (byteCount == 4 and data[0] == 0xe0 and ((data[1] & 0x0f) < 15) and ((data[1] & 0xf0 >> 8) in ReaderTrafficTypes["FSDI"])):
|
||||
if (byteCount == 4 and data[0] == 0xe0 and ((data[1] & 0x0f) < 15) and (
|
||||
(data[1] & 0xf0 >> 8) in ReaderTrafficTypes["FSDI"])):
|
||||
note += "RATS - "
|
||||
note += ReaderTrafficTypes["FSDI"][data[1]>>8]
|
||||
note += "CID:" + str(data[1]&0x0f) + " "
|
||||
if(not CRC_A_check(data)):
|
||||
note+=" WRONG CRC "
|
||||
note += ReaderTrafficTypes["FSDI"][data[1] >> 8]
|
||||
note += "CID:" + str(data[1] & 0x0f) + " "
|
||||
if (not CRC_A_check(data)):
|
||||
note += " WRONG CRC "
|
||||
else:
|
||||
readerCMD = ReaderCMD.RATS
|
||||
|
||||
# PPS Protocol and parameter selection request
|
||||
# PSS0 only
|
||||
elif (byteCount == 4 and (data[0]&0xf0 == 0xd0) and (data[1] == 0x01)):
|
||||
elif (byteCount == 4 and (data[0] & 0xf0 == 0xd0) and (data[1] == 0x01)):
|
||||
note += "PSS0 - "
|
||||
note += "CID:"+str(data[1]&0x0f) + " "
|
||||
note += "CID:" + str(data[1] & 0x0f) + " "
|
||||
readerCMD = ReaderCMD.PPS
|
||||
# PSS0+1
|
||||
elif (byteCount == 5 and (data[0]&0xf0 == 0xd0) and (data[1] == 0x11) and (data[2]&0xf0 == 0x00)):
|
||||
elif (byteCount == 5 and (data[0] & 0xf0 == 0xd0) and (data[1] == 0x11) and (data[2] & 0xf0 == 0x00)):
|
||||
note += "PSS0+1 - "
|
||||
note += "CID:"+str(data[1]&0x0f) + " "
|
||||
note += "DSI:"+str(pow(2,(data[2]>>2)&0x03)) + " "
|
||||
note += "DRI:"+str(pow(2,data[2]&0x03)) + " "
|
||||
# BLOCK S-block PCB DESELECT
|
||||
note += "CID:" + str(data[1] & 0x0f) + " "
|
||||
note += "DSI:" + str(pow(2, (data[2] >> 2) & 0x03)) + " "
|
||||
note += "DRI:" + str(pow(2, data[2] & 0x03)) + " "
|
||||
# BLOCK S-block PCB DESELECT
|
||||
# Without CID
|
||||
elif (byteCount == 3 and data[0] == 0xc2):
|
||||
note += "DESEL"
|
||||
# With CID
|
||||
elif (byteCount == 4 and data[0] == 0xca and data[1]&0x30 == 0x00):
|
||||
elif (byteCount == 4 and data[0] == 0xca and data[1] & 0x30 == 0x00):
|
||||
note += "DESEL - "
|
||||
note += "CID:"+ str(data[1]&0x0f) + " "
|
||||
|
||||
note += "CID:" + str(data[1] & 0x0f) + " "
|
||||
|
||||
return note
|
||||
|
||||
def parseCard(data):
|
||||
|
||||
def parseCard_3(data):
|
||||
byteCount = len(data)
|
||||
note = ""
|
||||
|
||||
@@ -126,7 +157,7 @@ def parseCard(data):
|
||||
note += "ATQA - "
|
||||
note += binascii.hexlify(data).decode()
|
||||
# SAK
|
||||
elif (byteCount == 3 and (data[0] & (~0x24)) == 0x00):
|
||||
elif (byteCount == 3 and ((data[0] & (0x24)) in CardTrafficTypes["SAK"])):
|
||||
note += "SAK - "
|
||||
note += CardTrafficTypes["SAK"][(data[2] & 0x24)]
|
||||
if not CRC_A_check(data):
|
||||
@@ -137,4 +168,54 @@ def parseCard(data):
|
||||
|
||||
return note
|
||||
|
||||
pass
|
||||
def parseCard_4(data):
|
||||
byteCount = len(data)
|
||||
note = ""
|
||||
|
||||
# ATS
|
||||
# TL + T0 + TA + TB + TC + T1 ... + CRC
|
||||
# TL: length without CRC
|
||||
# ATS without data
|
||||
if(byteCount == 3 and data[0] == (byteCount-2)):
|
||||
note += "ATS - NO DATA"
|
||||
# ATS with data mush have T0, T0 b8=0
|
||||
elif (byteCount > 3 and data[0] == (byteCount-2)
|
||||
and data[1] & 0x80 == 0x00
|
||||
and data[1] & 0x0f in CardTrafficTypes["FSCI"]):
|
||||
# Decode T0
|
||||
hasTA = data[1] & 0x10
|
||||
hasTB = data[1] & 0x20
|
||||
hasTC = data[1] & 0x40
|
||||
note += CardTrafficTypes["FSCI"][data[1] & 0x0f]
|
||||
|
||||
# Which byte to decode next
|
||||
byteNext = 2 # T0 Decoded, next is TA/TB/TC
|
||||
# TA b4=0
|
||||
if (hasTA and data[byteNext] & 0x08 == 0x00):
|
||||
note += "TA:" + hex(data[byteNext]) + " "
|
||||
byteNext += 1
|
||||
|
||||
if (hasTB):
|
||||
note += "TB:" + hex(data[byteNext]) + " "
|
||||
byteNext += 1
|
||||
|
||||
# TC b3-8=0
|
||||
if (hasTC and data[byteNext] & 0xFC == 0x00):
|
||||
note += "TC:" + hex(data[byteNext]) + " "
|
||||
byteNext += 1
|
||||
|
||||
# TODO: decode historical bytes
|
||||
|
||||
# Check CRC_A
|
||||
if not CRC_A_check(data):
|
||||
note += " WRONG CRC "
|
||||
|
||||
elif ():
|
||||
pass
|
||||
return note
|
||||
|
||||
def parseReader(data):
|
||||
return parseReader_3(data) + parseReader_4(data)
|
||||
|
||||
def parseCard(data):
|
||||
return parseCard_3(data) + parseCard_4(data)
|
||||
|
||||
@@ -137,13 +137,14 @@ def parseBinary(binaryStream, decode=False):
|
||||
deltaTimestamp += TIMESTAMP_MAX;
|
||||
|
||||
note = ""
|
||||
# If we need to decode the data
|
||||
if (decode):
|
||||
# If we need to decode the data and paritybit check success
|
||||
if (decode and logData[-1] != '!'):
|
||||
# Decode the data from Reader
|
||||
if(event == 0x44 or event == 0x45):
|
||||
note = iso14443_3.parseReader(binascii.a2b_hex(logData))
|
||||
elif (event == 0x46 or event == 0x47):
|
||||
note = iso14443_3.parseCard(binascii.a2b_hex(logData))
|
||||
|
||||
# Create log entry as dict and append it to event list
|
||||
logEntry = {
|
||||
'eventName': eventTypes[event]['name'],
|
||||
|
||||
Reference in New Issue
Block a user