import pycsc, string, binascii, sys _myprintable = " " + string.letters + string.digits + string.punctuation def hexdump(data, indent = 0, short = False): r"""Generates a nice hexdump of data and returns it. Consecutive lines will be indented with indent spaces. When short is true, will instead generate hexdump without adresses and on one line. Examples: hexdump('\x00\x41') -> \ '0000: 00 41 .A ' hexdump('\x00\x41', short=True) -> '00 41 (.A)'""" def hexable(data): return " ".join([binascii.b2a_hex(a) for a in data]) def printable(data): return "".join([e in _myprintable and e or "." for e in data]) if short: return "%s (%s)" % (hexable(data), printable(data)) result = "" (head, tail) = (data[:16], data[16:]) pos = 0 while len(head) > 0: if pos > 0: result = result + "\n%s" % (' ' * indent) result = result + "%04x: %-48s %-16s" % (pos, hexable(head), printable(head)) pos = pos + len(head) (head, tail) = (tail[:16], tail[16:]) return result LIFE_CYCLES = {0x01: "Load file = loaded", 0x03: "Applet instance / security domain = Installed", 0x07: "Card manager = Initialized; Applet instance / security domain = Selectable", 0x0F: "Card manager = Secured; Applet instance / security domain = Personalized", 0x7F: "Card manager = Locked; Applet instance / security domain = Blocked", 0xFF: "Applet instance = Locked"} def parse_status(data): """Parses the Response APDU of a GetStatus command.""" def parse_segment(segment): def parse_privileges(privileges): if privileges == 0x0: return "N/A" else: privs = [] if privileges & (1<<7): privs.append("security domain") if privileges & (1<<6): privs.append("DAP DES verification") if privileges & (1<<5): privs.append("delegated management") if privileges & (1<<4): privs.append("card locking") if privileges & (1<<3): privs.append("card termination") if privileges & (1<<2): privs.append("default selected") if privileges & (1<<1): privs.append("global PIN modification") if privileges & (1<<0): privs.append("mandated DAP verification") return ", ".join(privs) lgth = ord(segment[0]) aid = segment[1:1+lgth] lifecycle = ord(segment[1+lgth]) privileges = ord(segment[1+lgth+1]) print "aid length: %i (%x)" % (lgth, lgth) print "aid: %s" % hexdump(aid, indent = 18, short=True) print "life cycle state: %x (%s)" % (lifecycle, LIFE_CYCLES.get(lifecycle, "unknown or invalid state")) print "privileges: %x (%s)\n" % (privileges, parse_privileges(privileges)) pos = 0 while pos < len(data): lgth = ord(data[pos])+3 segment = data[pos:pos+lgth] parse_segment(segment) pos = pos + lgth def _unformat_hexdump(dump): hexdump = " ".join([line[7:54] for line in dump.splitlines()]) return binascii.a2b_hex("".join([e != " " and e or "" for e in hexdump])) if __name__ == "__main__": response = """ 0000: 07 A0 00 00 00 03 00 00 07 00 07 A0 00 00 00 62 ...............b 0010: 00 01 01 00 07 A0 00 00 00 62 01 01 01 00 07 A0 .........b...... 0020: 00 00 00 62 01 02 01 00 07 A0 00 00 00 62 02 01 ...b.........b.. 0030: 01 00 07 A0 00 00 00 03 00 00 01 00 0E A0 00 00 ................ 0040: 00 30 00 00 90 07 81 32 10 00 00 01 00 0E A0 00 .0.....2........ 0050: 00 00 30 00 00 90 07 81 42 10 00 00 01 00 0E A0 ..0.....B....... 0060: 00 00 00 30 00 00 90 07 81 41 10 00 00 07 00 0E ...0.....A...... 0070: A0 00 00 00 30 00 00 90 07 81 12 10 00 00 01 00 ....0........... 0080: 09 53 4C 42 43 52 59 50 54 4F 07 00 90 00 .SLBCRYPTO.... """ # 64kv1 vorher response = """ 0000: 07 A0 00 00 00 03 00 00 0F 00 07 A0 00 00 00 62 ...............b 0010: 00 01 01 00 07 A0 00 00 00 62 01 01 01 00 07 A0 .........b...... 0020: 00 00 00 62 01 02 01 00 07 A0 00 00 00 62 02 01 ...b.........b.. 0030: 01 00 07 A0 00 00 00 03 00 00 01 00 08 A0 00 00 ................ 0040: 00 30 00 CA 10 01 00 0E A0 00 00 00 30 00 00 90 .0..........0... 0050: 07 81 32 10 00 00 01 00 0E A0 00 00 00 30 00 00 ..2..........0.. 0060: 90 07 81 42 10 00 00 01 00 0E A0 00 00 00 30 00 ...B..........0. 0070: 00 90 07 81 41 10 00 00 07 00 0E A0 00 00 00 30 ....A..........0 0080: 00 00 90 07 81 12 10 00 00 01 00 09 53 4C 42 43 ............SLBC 0090: 52 59 50 54 4F 07 00 90 00 RYPTO.... """ # komische Karte response = """ 0000: 07 A0 00 00 00 03 00 00 07 00 07 A0 00 00 00 62 ...............b 0010: 00 01 01 00 07 A0 00 00 00 62 01 01 01 00 07 A0 .........b...... 0020: 00 00 00 62 01 02 01 00 07 A0 00 00 00 62 02 01 ...b.........b.. 0030: 01 00 07 A0 00 00 00 03 00 00 01 00 0E A0 00 00 ................ 0040: 00 30 00 00 90 07 81 32 10 00 00 01 00 0E A0 00 .0.....2........ 0050: 00 00 30 00 00 90 07 81 42 10 00 00 01 00 0E A0 ..0.....B....... 0060: 00 00 00 30 00 00 90 07 81 41 10 00 00 07 00 0E ...0.....A...... 0070: A0 00 00 00 30 00 00 90 07 81 12 10 00 00 01 00 ....0........... 0080: 09 53 4C 42 43 52 59 50 54 4F 07 00 05 A0 00 00 .SLBCRYPTO...... 0090: 00 01 01 00 90 00 ...... """ # 64kv1 nachher response = """ 0000: 07 A0 00 00 00 03 00 00 07 00 07 A0 00 00 00 62 ...............b 0010: 00 01 01 00 07 A0 00 00 00 62 01 01 01 00 07 A0 .........b...... 0020: 00 00 00 62 01 02 01 00 07 A0 00 00 00 62 02 01 ...b.........b.. 0030: 01 00 07 A0 00 00 00 03 00 00 01 00 0E A0 00 00 ................ 0040: 00 30 00 00 90 07 81 32 10 00 00 01 00 0E A0 00 .0.....2........ 0050: 00 00 30 00 00 90 07 81 42 10 00 00 01 00 0E A0 ..0.....B....... 0060: 00 00 00 30 00 00 90 07 81 41 10 00 00 07 00 0E ...0.....A...... 0070: A0 00 00 00 30 00 00 90 07 81 12 10 00 00 01 00 ....0........... 0080: 09 53 4C 42 43 52 59 50 54 4F 07 00 05 A0 00 00 .SLBCRYPTO...... 0090: 00 01 01 00 06 A0 00 00 00 01 01 07 02 90 00 ............... """ # 64k1 nach setup response = sys.stdin.read() parse_status(_unformat_hexdump(response)[:-2])