@@ -36,7 +36,7 @@ def color(s, fg=None):
3636
3737class BridgePM3 :
3838 """Bridge class for communicating with Proxmark3 device."""
39-
39+
4040 def __init__ (self , hw_debug : bool , pm3 : Any = None ):
4141 self ._debug = hw_debug
4242 if pm3 is None :
@@ -48,7 +48,7 @@ def recv(self) -> bytes:
4848 """Receive data from PM3."""
4949 if self .recv_buff is None :
5050 raise ValueError ("No data in receive buffer" )
51-
51+
5252 ret_buff = bytes .fromhex (self .recv_buff )
5353
5454 if self ._debug :
@@ -62,15 +62,15 @@ def recv(self) -> bytes:
6262 def hw_reset (self ) -> None :
6363 """Reset the Proxmark3 hardware."""
6464 self .pm3 .console ("hw reset" )
65-
65+
6666 def send (self , data : bytes , select : bool = False ) -> None :
6767 """Send APDU command to card via PM3."""
6868
6969 exec_cmd = "hf 14a apdu -k"
7070
7171 if select :
7272 exec_cmd += "s" # activate field and select card
73-
73+
7474 exec_cmd += "d " # full APDU package
7575
7676 # Convert bytearray to string
@@ -113,7 +113,7 @@ def nfcGetRecData(self) -> bytes:
113113 if recvdata is None :
114114 raise ValueError ("Did not receive any data from PM3" )
115115 return recvdata
116-
116+
117117 def waitForCard (self , max_tries : int = MAX_CARD_POLL_TRIES ) -> bool :
118118 """Poll for a card up to max_tries. Return True if found, else False."""
119119 tries = 0
@@ -276,51 +276,51 @@ def parse_return_code(ret_code: Optional[bytes], console_print: bool = True) ->
276276def parse_tlv (data : bytes , tag_length : int ) -> List [Tuple [bytes , bytes ]]:
277277 """
278278 Parse TLV (Tag-Length-Value) structure.
279-
279+
280280 Args:
281281 data: bytes or bytearray containing TLV data
282282 tag_length: int, number of bytes for the tag field (must be > 0)
283-
283+
284284 Returns:
285285 list of tuples: [(tag, value), (tag, value), ...]
286286 """
287287 if tag_length <= 0 :
288288 raise ValueError (f"Invalid tag_length: { tag_length } , must be > 0" )
289-
289+
290290 result = []
291291 offset = 0
292-
292+
293293 while offset < len (data ):
294294 # Check if we have enough bytes for tag and length
295295 if offset + tag_length + 1 > len (data ):
296296 break
297-
297+
298298 # Extract tag
299299 tag = data [offset :offset + tag_length ]
300300 offset += tag_length
301-
301+
302302 # Extract length (assuming 1 byte for length)
303303 length = data [offset ]
304304 offset += 1
305-
305+
306306 # Check if we have enough bytes for value
307307 if offset + length > len (data ):
308308 break
309-
309+
310310 # Extract value
311311 value = data [offset :offset + length ]
312312 offset += length
313-
313+
314314 result .append ((tag , value ))
315-
315+
316316 return result
317317
318318# https://github.com/SocialSisterYi/T-Union_Master/blob/857ffec87d67413e759c5e055e6a410a93536b2e/src/protocol/t_union_poller_i.c#L88
319319def parse_tunion_meta (level : int , tlv_data : bytes ) -> None :
320320 """Parse T-Union card metadata from TLV data."""
321321 if len (tlv_data ) < 0x1C :
322322 raise ValueError (f"TLV data too short: { len (tlv_data )} bytes, expected at least 28" )
323-
323+
324324 card_type = tlv_data [0 ]
325325 city_id = int .from_bytes (tlv_data [1 :3 ], byteorder = 'big' )
326326 card_number = tlv_data [10 :20 ].hex ().upper ()
@@ -346,7 +346,7 @@ def decode_transaction(data: bytes) -> None:
346346 """Decode and display transaction record."""
347347 if len (data ) < 23 :
348348 raise ValueError (f"Transaction data too short: { len (data )} bytes, expected at least 23" )
349-
349+
350350 sequence = int .from_bytes (data [0 :2 ], byteorder = 'big' )
351351 money = int .from_bytes (data [5 :9 ], byteorder = 'big' )
352352 trans_type = data [9 ]
@@ -379,7 +379,7 @@ def decode_travel(data: bytes) -> None:
379379 """Decode and display travel record."""
380380 if len (data ) < 42 :
381381 raise ValueError (f"Travel data too short: { len (data )} bytes, expected at least 42" )
382-
382+
383383 travel_type = data [0 ]
384384 terminal_id = data [1 :9 ].hex ().upper ()
385385 sub_type = data [9 ]
@@ -456,10 +456,10 @@ def process_tlv(tlv_data: bytes) -> None:
456456 """Process TLV data after checking status word."""
457457 if DEBUG :
458458 print (f"[{ color ('+' , fg = 'green' )} ] Calling: { sys ._getframe (0 ).f_code .co_name } " )
459-
459+
460460 if len (tlv_data ) < 2 :
461461 raise ValueError ("TLV data too short" )
462-
462+
463463 SW1_SW2 = tlv_data [- 2 :]
464464 answer = tlv_data [:- 2 ]
465465
@@ -479,7 +479,7 @@ def strToint16(hex_str: str) -> List[int]:
479479 """
480480 if len (hex_str ) % 2 != 0 :
481481 raise ValueError (f"Hex string must have even length, got { len (hex_str )} " )
482-
482+
483483 return [int (hex_str [i :i + 2 ], 16 ) for i in range (0 , len (hex_str ), 2 )]
484484
485485def GetRecData (pm3_conn : BridgePM3 ) -> bytes :
@@ -492,7 +492,7 @@ def GetRecData(pm3_conn: BridgePM3) -> bytes:
492492 parse_return_code (nfcdata [- 2 :], DEBUG )
493493 return nfcdata
494494
495- def sendCommand (pm3_conn : BridgePM3 , cla : int , ins : int , p1 : int , p2 : int ,
495+ def sendCommand (pm3_conn : BridgePM3 , cla : int , ins : int , p1 : int , p2 : int ,
496496 Data : Optional [bytes ] = None , le : Optional [int ] = None ) -> bytes :
497497 """Send APDU command and receive response."""
498498 context = [cla , ins , p1 , p2 ]
@@ -514,7 +514,7 @@ def sendCommand(pm3_conn: BridgePM3, cla: int, ins: int, p1: int, p2: int,
514514 pm3_conn .sendToNfc (bytes (context ))
515515 recdata = GetRecData (pm3_conn )
516516 return recdata
517-
517+
518518def cmd_select (pm3_conn : BridgePM3 , fileID : Optional [str ] = None , name : Optional [bytes ] = None ) -> bytes :
519519 """Send SELECT command to card."""
520520 if DEBUG :
@@ -552,7 +552,7 @@ def cmd_get_balance(pm3_conn: BridgePM3) -> bytes:
552552 ins = 0x5C
553553 p1 = 0x00
554554 p2 = 0x02
555-
555+
556556 ret = sendCommand (pm3_conn , cla = cla , ins = ins , p1 = p1 , p2 = p2 , le = 4 )
557557 if DEBUG :
558558 print (f"[{ color ('=' , fg = 'yellow' )} ] GET_BALANCE => { bytes_to_hexstr (ret )} \n " )
@@ -562,7 +562,7 @@ def cmd_read_record(pm3_conn: BridgePM3, record_number: int, file_id: int) -> by
562562 """Read a record from a file on the card."""
563563 if DEBUG :
564564 print (f"[{ color ('+' , fg = 'green' )} ] Calling: { sys ._getframe (0 ).f_code .co_name } " )
565-
565+
566566 cla = 0x00
567567 ins = 0xB2
568568 p1 = record_number
@@ -597,7 +597,7 @@ def process_tunion_transit_card(pm3_conn: BridgePM3) -> None:
597597 except (AssertionError , ValueError ) as e :
598598 print (f" Error: { e } " )
599599 break
600-
600+
601601 print ("\n Reading Travel Records..." )
602602 for i in range (MAX_TRAVEL_RECORDS ):
603603 print (f"Reading Travel Record { i + 1 } ..." , end = "" )
@@ -624,7 +624,7 @@ def main() -> None:
624624 print ("\n Selecting DDF..." )
625625 ret = cmd_select (pm3_conn , name = DDF_PPSE )
626626 assert_success (ret )
627-
627+
628628 for aidl in [AID_PBOC_DEBIT_CREDIT , AID_TUNION_TRANSIT ]:
629629 print (f"\n Selecting AID: { aidl } " )
630630 ret = cmd_select (pm3_conn , name = bytes .fromhex (aidl ))
@@ -648,4 +648,4 @@ def main() -> None:
648648 pm3_conn .hw_reset ()
649649
650650if __name__ == "__main__" :
651- main ()
651+ main ()
0 commit comments