<p>Ludovic Rousseau has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sim-auth/+/20909">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pycodestyle: remove extra space characters<br><br>ICC.py:707:1: W293 blank line contains whitespace<br>ICC.py:715:57: W291 trailing whitespace<br>etc.<br><br>Change-Id: Ie8a5fc47775fe7d7fe0e19f7378ffda104fa6112<br>---<br>M card/ICC.py<br>M card/SIM.py<br>M card/USIM.py<br>M card/utils.py<br>4 files changed, 390 insertions(+), 395 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-sim-auth refs/changes/09/20909/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/card/ICC.py b/card/ICC.py</span><br><span>index 4a2ba0e..729dbc0 100644</span><br><span>--- a/card/ICC.py</span><br><span>+++ b/card/ICC.py</span><br><span>@@ -41,23 +41,23 @@</span><br><span> from smartcard.util import toHexString</span><br><span> </span><br><span> from card.utils import *</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ###########################################################</span><br><span style="color: hsl(0, 100%, 40%);">-# ISO7816 class with attributes and methods as defined </span><br><span style="color: hsl(0, 100%, 40%);">-# by ISO-7816 part 4 standard for smartcard </span><br><span style="color: hsl(120, 100%, 40%);">+# ISO7816 class with attributes and methods as defined</span><br><span style="color: hsl(120, 100%, 40%);">+# by ISO-7816 part 4 standard for smartcard</span><br><span> ###########################################################</span><br><span> </span><br><span> class ISO7816(object):</span><br><span>     '''</span><br><span>     define attributes, methods and facilities for ISO-7816-4 standard smartcard</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     use self.dbg = 1 or more to print live debugging information</span><br><span>     standard instructions codes available in "INS_dic" class dictionnary</span><br><span>     standard file tags available in "file_tags" class dictionnary</span><br><span>     '''</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     dbg = 0</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     INS_dic = {</span><br><span>         0x04 : 'DEACTIVATE FILE',</span><br><span>         0x0C : 'ERASE RECORD(S)',</span><br><span>@@ -114,7 +114,7 @@</span><br><span>         0xF2 : 'STATUS',</span><br><span>         0xFE : 'TERMINATE CARD USAGE',</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-               </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     file_tags = {</span><br><span>         0x80 : 'Size',</span><br><span>         0x81 : 'Length',</span><br><span>@@ -135,13 +135,13 @@</span><br><span>         0xA2 : 'DO Pairs',</span><br><span>         0xA5 : 'Proprietary BERTLV',</span><br><span>         0xAB : 'Security Attribute expanded',</span><br><span style="color: hsl(0, 100%, 40%);">-        }     </span><br><span style="color: hsl(0, 100%, 40%);">-               </span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def __init__(self, CLA=0x00):</span><br><span>         '''</span><br><span>         connect smartcard and defines class CLA code for communication</span><br><span>         uses "pyscard" library services</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         creates self.CLA attribute with CLA code</span><br><span>         and self.coms attribute with associated "apdu_stack" instance</span><br><span>         '''</span><br><span>@@ -151,32 +151,32 @@</span><br><span>         self.cardservice.connection.connect()</span><br><span>         self.reader = self.cardservice.connection.getReader()</span><br><span>         self.ATR = self.cardservice.connection.getATR()</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.CLA = CLA</span><br><span>         self.coms = apdu_stack()</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def disconnect(self):</span><br><span>         '''</span><br><span>         disconnect smartcard: stops the session</span><br><span>         uses "pyscard" library service</span><br><span>         '''</span><br><span>         self.cardservice.connection.disconnect()</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def define_class(self, CLA=0x00):</span><br><span>         '''</span><br><span>         define smartcard class attribute for APDU command</span><br><span>         override CLA value defined in class initialization</span><br><span>         '''</span><br><span>         self.CLA = CLA</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def ATR_scan(self, smlist_file="/usr/local/share/pcsc/smartcard_list.txt"):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        print smartcard info retrieved from AnswerToReset </span><br><span style="color: hsl(120, 100%, 40%);">+        print smartcard info retrieved from AnswerToReset</span><br><span>         thanks to pyscard routine</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         if pcsc_scan is installed,</span><br><span>         use the signature file passed as argument for guessing the card</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         check also the more complete "parseATR" tool</span><br><span>         '''</span><br><span>         print('\nsmartcard reader: ', self.reader)</span><br><span>@@ -198,7 +198,7 @@</span><br><span>                 ATRfinger = ''</span><br><span>                 j = 1</span><br><span>                 for i in range(len(smlist)):</span><br><span style="color: hsl(0, 100%, 40%);">-                    if ATRre.match(smlist[i]):       </span><br><span style="color: hsl(120, 100%, 40%);">+                    if ATRre.match(smlist[i]):</span><br><span>                         if re.compile(smlist[i][:len(smlist[i])-1]).\</span><br><span>                         match(toHexString(self.ATR)):</span><br><span>                             while re.compile('\t.{1,}').match(smlist[i+j]):</span><br><span>@@ -210,17 +210,17 @@</span><br><span>                     print("smartcard ATR fingerprint:\n%s" % ATRfinger)</span><br><span>             else:</span><br><span>                 print("%s file not found" % smlist_file)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def sw_status(self, sw1, sw2):</span><br><span>         '''</span><br><span>         sw_status(sw1=int, sw2=int) -> string</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         SW status bytes interpretation as defined in ISO-7816 part 4 standard</span><br><span>         helps to speak and understand with the smartcard!</span><br><span>         '''</span><br><span>         status = 'undefined status'</span><br><span>         if sw1 == 0x90 and sw2 == 0x00: status = 'normal processing: ' \</span><br><span style="color: hsl(0, 100%, 40%);">-            'command accepted: no further qualification'       </span><br><span style="color: hsl(120, 100%, 40%);">+            'command accepted: no further qualification'</span><br><span>         elif sw1 == 0x61: status = 'normal processing: %i bytes ' \</span><br><span>             'still available' % sw2</span><br><span>         elif sw1 == 0x62:</span><br><span>@@ -230,7 +230,7 @@</span><br><span>             elif sw2 == 0x81: status += ': part of returned data may' \</span><br><span>                 'be corrupted'</span><br><span>             elif sw2 == 0x82: status += ': end of file/record reached ' \</span><br><span style="color: hsl(0, 100%, 40%);">-                'before reading Le bytes' </span><br><span style="color: hsl(120, 100%, 40%);">+                'before reading Le bytes'</span><br><span>             elif sw2 == 0x83: status += ': selected file invalidated'</span><br><span>             elif sw2 == 0x84: status += ': FCI not formatted'</span><br><span>             elif sw2 == 0x85: status += ': selected file in termination state'</span><br><span>@@ -303,7 +303,7 @@</span><br><span>         elif sw1 == 0x6B and sw2 == 0x00: status = 'checking error: '\</span><br><span>             'wrong parameter(s) P1-P2'</span><br><span>         elif sw1 == 0x6C: status = 'checking error: wrong length Le: ' \</span><br><span style="color: hsl(0, 100%, 40%);">-            'exact length is %s' % toHexString([sw2])        </span><br><span style="color: hsl(120, 100%, 40%);">+            'exact length is %s' % toHexString([sw2])</span><br><span>         elif sw1 == 0x6D and sw2 == 0x00: status = 'checking error: ' \</span><br><span>             'instruction code not supported or invalid'</span><br><span>         elif sw1 == 0x6E and sw2 == 0x00: status = 'checking error: ' \</span><br><span>@@ -311,20 +311,20 @@</span><br><span>         elif sw1 == 0x6F and sw2 == 0x00: status = 'checking error: ' \</span><br><span>             'no precise diagnosis'</span><br><span>         return status</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def sr_apdu(self, apdu, force=False):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        sr_apdu(apdu=[0x.., 0x.., ...]) -> </span><br><span style="color: hsl(120, 100%, 40%);">+        sr_apdu(apdu=[0x.., 0x.., ...]) -></span><br><span>             list   [ string(apdu sent information),</span><br><span>                      string(SW codes interpretation),</span><br><span>                      2-tuple(sw1, sw2),</span><br><span>                      list(response bytes) ]</span><br><span style="color: hsl(0, 100%, 40%);">-                     </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         generic function to send apdu, receive and interpret response</span><br><span>         force: force card reconnection if pyscard transmission fails</span><br><span>         '''</span><br><span>         if force:</span><br><span style="color: hsl(0, 100%, 40%);">-            try: </span><br><span style="color: hsl(120, 100%, 40%);">+            try:</span><br><span>                 data, sw1, sw2 = self.cardservice.connection.transmit(apdu)</span><br><span>             except CardConnectionException:</span><br><span>                 ISO7816.__init__(self, CLA = self.CLA)</span><br><span>@@ -332,115 +332,115 @@</span><br><span>         else:</span><br><span>             data, sw1, sw2 = self.cardservice.connection.transmit(apdu)</span><br><span>         # replaces INS code by strings when available</span><br><span style="color: hsl(0, 100%, 40%);">-        if apdu[1] in list(self.INS_dic.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+        if apdu[1] in list(self.INS_dic.keys()):</span><br><span>             apdu_name =  self.INS_dic[apdu[1]] + ' '</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             apdu_name = ''</span><br><span>         sw_stat = self.sw_status(sw1, sw2)</span><br><span>         return ['%sapdu: %s' % (apdu_name, toHexString(apdu)),</span><br><span>                 'sw1, sw2: %s - %s' % ( toHexString([sw1, sw2]), sw_stat ),</span><br><span>                 (sw1, sw2),</span><br><span>                 data ]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def bf_cla(self, start=0, param=[0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00]):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        bf_cla( start=int(starting CLA), </span><br><span style="color: hsl(120, 100%, 40%);">+        bf_cla( start=int(starting CLA),</span><br><span>                 param=list(bytes for selecting file 0x3F, 0x00) ) -></span><br><span>             list( CLA which could be supported )</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         tries all classes CLA codes to check the possibly supported ones</span><br><span>         prints CLA suspected to be supported</span><br><span>         returns the list of those CLA codes</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        WARNING: </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        WARNING:</span><br><span>         can block the card definitively</span><br><span>         Do not do it with your own VISA / MASTERCARD</span><br><span>         '''</span><br><span>         clist = []</span><br><span>         for i in range(start, 256):</span><br><span>             ret = self.sr_apdu([i] + param)</span><br><span style="color: hsl(0, 100%, 40%);">-            if ret[2] != (0x6E, 0x00): </span><br><span style="color: hsl(120, 100%, 40%);">+            if ret[2] != (0x6E, 0x00):</span><br><span>                 print(ret)</span><br><span>                 clist.append(i)</span><br><span>         return clist</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def bf_ins(self, start=0):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        bf_cla( start=int(starting INS) ) </span><br><span style="color: hsl(120, 100%, 40%);">+        bf_cla( start=int(starting INS) )</span><br><span>             -> list( INS which could be supported )</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         tries all instructions INS codes to check the supported ones</span><br><span>         prints INS suspected to be supported</span><br><span>         returns the list of those INS codes</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        WARNING: </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        WARNING:</span><br><span>         can block the card definitively</span><br><span>         Do not do it with your own VISA / MASTERCARD</span><br><span>         '''</span><br><span>         ilist = []</span><br><span>         for i in range(start, 256):</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg > 1: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg > 1:</span><br><span>                 print('DEBUG: testing %d for INS code with %d CLA code' \</span><br><span>                       % (i, self.CLA))</span><br><span>             ret = self.sr_apdu([self.CLA, i, 0x00, 0x00])</span><br><span style="color: hsl(0, 100%, 40%);">-            if ret[2] != (0x6D, 0x00): </span><br><span style="color: hsl(120, 100%, 40%);">+            if ret[2] != (0x6D, 0x00):</span><br><span>                 print(ret)</span><br><span>                 ilist.append(i)</span><br><span>         return ilist</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     ###</span><br><span>     # Below is defined a list of standard commands to be used with (U)SIM cards</span><br><span style="color: hsl(0, 100%, 40%);">-    # They are mainly defined and described in </span><br><span style="color: hsl(120, 100%, 40%);">+    # They are mainly defined and described in</span><br><span>     # ISO 7816 and described further in ETSI 101.221</span><br><span>     ###</span><br><span>     def READ_BINARY(self, P1=0x00, P2=0x00, Le=0x01):</span><br><span>         '''</span><br><span>         APDU command to read the content of EF file with transparent structure</span><br><span>         Le: length of data bytes to be read</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         READ_BINARY = [self.CLA, 0xB0, P1, P2, Le]</span><br><span>         return self.sr_apdu(READ_BINARY)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def WRITE_BINARY(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to write the content of EF file with transparent structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         Data: list of data bytes to be written</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         WRITE_BINARY = [self.CLA, 0xD0, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(WRITE_BINARY)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def UPDATE_BINARY(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to update the content of EF file with transparent structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         Data: list of data bytes to be written</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         UPDATE_BINARY = [self.CLA, 0xD6, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(UPDATE_BINARY)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def ERASE_BINARY(self, P1=0x00, P2=0x00, Lc=None, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to erase the content of EF file with transparent structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         Lc: 'None' or '0x02'</span><br><span>         Data: list of data bytes to be written</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if Lc is None: </span><br><span style="color: hsl(120, 100%, 40%);">+        if Lc is None:</span><br><span>             ERASE_BINARY = [self.CLA, 0x0E, P1, P2]</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             ERASE_BINARY = [self.CLA, 0x0E, P1, P2, 0x02] + Data</span><br><span style="color: hsl(0, 100%, 40%);">-        return self.sr_apdu(ERASE_BINARY)        </span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+        return self.sr_apdu(ERASE_BINARY)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def READ_RECORD(self, P1=0x00, P2=0x00, Le=0x00):</span><br><span>         '''</span><br><span>         APDU command to read the content of EF file with record structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1: record number</span><br><span>         P2: reference control</span><br><span>         Le: length of data bytes to be read</span><br><span>@@ -448,11 +448,11 @@</span><br><span>         '''</span><br><span>         READ_RECORD = [self.CLA, 0xB2, P1, P2, Le]</span><br><span>         return self.sr_apdu(READ_RECORD)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def WRITE_RECORD(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to write the content of EF file with record structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1: record number</span><br><span>         P2: reference control</span><br><span>         Data: list of data bytes to be written in the record</span><br><span>@@ -460,22 +460,22 @@</span><br><span>         '''</span><br><span>         WRITE_RECORD = [self.CLA, 0xD2, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(WRITE_RECORD)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def APPEND_RECORD(self, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to append a record on EF file with record structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P2: reference control</span><br><span>         Data: list of data bytes to be appended on the record</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         APPEND_RECORD = [self.CLA, 0xE2, 0x00, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(APPEND_RECORD)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def UPDATE_RECORD(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to update the content of EF file with record structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1: record number</span><br><span>         P2: reference control</span><br><span>         Data: list of data bytes to update the record</span><br><span>@@ -483,40 +483,40 @@</span><br><span>         '''</span><br><span>         APPEND_RECORD = [self.CLA, 0xDC, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(APPEND_RECORD)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def GET_DATA(self, P1=0x00, P2=0x00, Le=0x01):</span><br><span>         '''</span><br><span>         APDU command to retrieve data object</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1 and P2: reference control for data object description</span><br><span>         Le: number of bytes expected in the response</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         GET_DATA = [self.CLA, 0xCA, P1, P2, Le]</span><br><span>         return self.sr_apdu(GET_DATA)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def PUT_DATA(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to store data object</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1 and P2: reference control for data object description</span><br><span>         Data: list of data bytes to put in the data object structure</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(Data) == 0: </span><br><span style="color: hsl(120, 100%, 40%);">+        if len(Data) == 0:</span><br><span>             PUT_DATA = [self.CLA, 0xDA, P1, P2]</span><br><span style="color: hsl(0, 100%, 40%);">-        elif 1 <= len(Data) <= 255: </span><br><span style="color: hsl(120, 100%, 40%);">+        elif 1 <= len(Data) <= 255:</span><br><span>             PUT_DATA = [self.CLA, 0xDA, P1, P2, len(Data)] + Data</span><br><span>         # should never be the case, however... who wants to try</span><br><span>         else:</span><br><span>             PUT_DATA = [self.CLA, 0xDA, P1, P2, 0xFF] + Data[0:255]</span><br><span style="color: hsl(0, 100%, 40%);">-        return self.sr_apdu(PUT_DATA)       </span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+        return self.sr_apdu(PUT_DATA)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def SELECT_FILE(self, P1=0x00, P2=0x00, Data=[0x3F, 0x00], \</span><br><span>                     with_length=True):</span><br><span>         '''</span><br><span>         APDU command to select file</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1 and P2: selection control</span><br><span>         Data: list of bytes describing the file identifier or address</span><br><span>         call sr_apdu method</span><br><span>@@ -525,107 +525,107 @@</span><br><span>             Data = [min(len(Data), 255)] + Data</span><br><span>         SELECT_FILE = [self.CLA, 0xA4, P1, P2] + Data</span><br><span>         return self.sr_apdu(SELECT_FILE)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def VERIFY(self, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to verify user PIN, password or security codes</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P2: reference control</span><br><span>         Data: list of bytes to be verified by the card</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(Data) == 0: </span><br><span style="color: hsl(120, 100%, 40%);">+        if len(Data) == 0:</span><br><span>             VERIFY = [self.CLA, 0x20, 0x00, P2]</span><br><span style="color: hsl(0, 100%, 40%);">-        elif 1 <= len(Data) <= 255: </span><br><span style="color: hsl(120, 100%, 40%);">+        elif 1 <= len(Data) <= 255:</span><br><span>             VERIFY = [self.CLA, 0x20, 0x00, P2, len(Data)] + Data</span><br><span>         # should never be the case, however... who wants to try</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             VERIFY = [self.CLA, 0x20, 0x00, P2, 0xFF] + Data[0:255]</span><br><span>         return self.sr_apdu(VERIFY)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def INTERNAL_AUTHENTICATE(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to run internal authentication algorithm</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1 and P2: reference control (algo, secret key selection...)</span><br><span>         Data: list of bytes containing the authentication challenge</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         INTERNAL_AUTHENTICATE = [self.CLA, 0x88, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(INTERNAL_AUTHENTICATE)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def EXTERNAL_AUTHENTICATE(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        APDU command to conditionally update the security status of the card </span><br><span style="color: hsl(120, 100%, 40%);">+        APDU command to conditionally update the security status of the card</span><br><span>         after getting a challenge from it</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1 and P2: reference control (algo, secret key selection...)</span><br><span>         Data: list of bytes containing the challenge response</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(Data) == 0: </span><br><span style="color: hsl(120, 100%, 40%);">+        if len(Data) == 0:</span><br><span>             EXTERNAL_AUTHENTICATE = [self.CLA, 0x82, P1, P2]</span><br><span style="color: hsl(0, 100%, 40%);">-        elif 1 <= len(Data) <= 255: </span><br><span style="color: hsl(120, 100%, 40%);">+        elif 1 <= len(Data) <= 255:</span><br><span>             EXTERNAL_AUTHENTICATE = [self.CLA, 0x82, P1, P2, len(Data)] + Data</span><br><span>         # should never be the case, however... who wants to try</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             EXTERNAL_AUTHENTICATE = [self.CLA, 0x82, P1, P2, 0xFF] + Data[0:255]</span><br><span style="color: hsl(0, 100%, 40%);">-        return self.sr_apdu(EXTERNAL_AUTHENTICATE)       </span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+        return self.sr_apdu(EXTERNAL_AUTHENTICATE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def GET_CHALLENGE(self):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        APDU command to get a challenge for external entity authentication </span><br><span style="color: hsl(120, 100%, 40%);">+        APDU command to get a challenge for external entity authentication</span><br><span>         to the card</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         GET_CHALLENGE = [self.CLA, 0x84, 0x00, 0x00]</span><br><span>         return self.sr_apdu(GET_CHALLENGE)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def MANAGE_CHANNEL(self, P1=0x00, P2=0x00):</span><br><span>         '''</span><br><span>         APDU to open and close supplementary logical channels</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1=0x00 to open, 0x80 to close</span><br><span>         P2=0x00, 1, 2 or 3 to ask for logical channel number</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if (P1, P2) == (0x00, 0x00): </span><br><span style="color: hsl(120, 100%, 40%);">+        if (P1, P2) == (0x00, 0x00):</span><br><span>             MANAGE_CHANNEL = [self.CLA, 0x70, P1, P2, 0x01]</span><br><span style="color: hsl(0, 100%, 40%);">-        else:  </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             MANAGE_CHANNEL = [self.CLA, 0x70, P1, P2]</span><br><span>         return self.sr_apdu(MANAGE_CHANNEL)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def GET_RESPONSE(self, Le=0x01):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        APDU command to retrieve data after selection </span><br><span style="color: hsl(120, 100%, 40%);">+        APDU command to retrieve data after selection</span><br><span>         or other kind of request that should get an extensive reply</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         Le: expected length of data</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span>         GET_RESPONSE = [self.CLA, 0xC0, 0x00, 0x00, Le]</span><br><span>         return self.sr_apdu(GET_RESPONSE)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def ENVELOPPE(self, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to encapsulate data (APDU or other...)</span><br><span>         check ETSI TS 102.221 for some examples...</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         Data: list of bytes</span><br><span>         call sr_apdu method</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(Data) == 0: </span><br><span style="color: hsl(120, 100%, 40%);">+        if len(Data) == 0:</span><br><span>             ENVELOPPE = [self.CLA, 0xC2, 0x00, 0x00]</span><br><span style="color: hsl(0, 100%, 40%);">-        elif 1 <= len(Data) <= 255: </span><br><span style="color: hsl(120, 100%, 40%);">+        elif 1 <= len(Data) <= 255:</span><br><span>             ENVELOPPE = [self.CLA, 0xC2, 0x00, 0x00, len(Data)] + Data</span><br><span>         return self.sr_apdu(ENVELOPPE)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def SEARCH_RECORD(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        APDU command to seach pattern in the current EF file </span><br><span style="color: hsl(120, 100%, 40%);">+        APDU command to seach pattern in the current EF file</span><br><span>         with record structure</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1: record number</span><br><span>         P2: type of search</span><br><span>         Data: list of bytes describing a pattern to search for</span><br><span>@@ -633,11 +633,11 @@</span><br><span>         '''</span><br><span>         SEARCH_RECORD = [self.CLA, 0xA2, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(SEARCH_RECORD)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def DISABLE_CHV(self, P1=0x00, P2=0x00, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to disable CHV verification (such as PIN or password...)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P1: let to 0x00... or read ISO and ETSI specifications</span><br><span>         P2: type of CHV to disable</span><br><span>         Data: list of bytes for CHV value</span><br><span>@@ -645,24 +645,24 @@</span><br><span>         '''</span><br><span>         DISABLE_CHV = [self.CLA, 0x26, P1, P2, len(Data)] + Data</span><br><span>         return self.sr_apdu(DISABLE_CHV)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def UNBLOCK_CHV(self, P2=0x00, Lc=None, Data=[]):</span><br><span>         '''</span><br><span>         APDU command to unblock CHV code (e.g. with PUK for deblocking PIN)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         P2: type of CHV to unblock</span><br><span>         Lc: Empty or 0x10</span><br><span>         Data: if Lc=0x10, UNBLOCK_CHV value and new CHV value to set</span><br><span>         call sr_apdu method</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         TODO: check the exact coding for the Data</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        if Lc is None: </span><br><span style="color: hsl(120, 100%, 40%);">+        if Lc is None:</span><br><span>             UNBLOCK_CHV = [self.CLA, 0x2C, 0x00, P2]</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             UNBLOCK_CHV = [self.CLA, 0x2C, 0x00, P2, 0x10] + Data</span><br><span style="color: hsl(0, 100%, 40%);">-        return self.sr_apdu(UNBLOCK_CHV) </span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+        return self.sr_apdu(UNBLOCK_CHV)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     ##########################</span><br><span>     # evolved "macro" method for ISO7816 card</span><br><span>     # need the "coms" attribute being an apdu_stack()</span><br><span>@@ -670,9 +670,9 @@</span><br><span>     def parse_file(self, Data=[]):</span><br><span>         '''</span><br><span>         parse_file(self, Data) -> Dict()</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         parses a list of bytes returned when selecting a file</span><br><span style="color: hsl(0, 100%, 40%);">-        interprets the content of some informative bytes </span><br><span style="color: hsl(120, 100%, 40%);">+        interprets the content of some informative bytes</span><br><span>         for file structure and parsing method...</span><br><span>         '''</span><br><span>         ber = BERTLV_parser( Data )</span><br><span>@@ -681,54 +681,54 @@</span><br><span>         if len(ber) > 1:</span><br><span>             # TODO: implements recursive BER object parsing</span><br><span>             print('[WNG] more than 1 BER object: %s' % ber)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # for FCP control structure, precise parsing is done</span><br><span>         # this structure seems to be the most used for (U)SIM cards</span><br><span style="color: hsl(0, 100%, 40%);">-        if ber[0][0][2] == 0x2: </span><br><span style="color: hsl(120, 100%, 40%);">+        if ber[0][0][2] == 0x2:</span><br><span>             fil = self.parse_FCP( ber[0][2] )</span><br><span>             fil['Control'] = 'FCP'</span><br><span>             return fil</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # for other control structure, DIY</span><br><span>         fil = {}</span><br><span style="color: hsl(0, 100%, 40%);">-        if ber[0][0][2] == 0x4: </span><br><span style="color: hsl(120, 100%, 40%);">+        if ber[0][0][2] == 0x4:</span><br><span>             fil['Control'] = 'FMD'</span><br><span>             if self.dbg:</span><br><span>                 print('[WNG] FMD file structure parsing not implemented')</span><br><span style="color: hsl(0, 100%, 40%);">-        elif ber[0][0][2] == 0xF: </span><br><span style="color: hsl(120, 100%, 40%);">+        elif ber[0][0][2] == 0xF:</span><br><span>             fil['Control'] = 'FCI'</span><br><span>             if self.dbg:</span><br><span>                 print('[WNG] FCI file structure parsing not implemented')</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             fil['Control'] = ber[0][0]</span><br><span>             if self.dbg:</span><br><span>                 print('[WNG] unknown file structure')</span><br><span>         fil['Data'] = ber[0][2]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def parse_FCP(self, Data=[]):</span><br><span>         '''</span><br><span>         parse_FCP(Data) -> Dict()</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         parses a list of bytes returned when selecting a file</span><br><span style="color: hsl(0, 100%, 40%);">-        interprets the content of some informative bytes </span><br><span style="color: hsl(120, 100%, 40%);">+        interprets the content of some informative bytes</span><br><span>         for file structure and parsing method...</span><br><span>         '''</span><br><span>         fil = {}</span><br><span>         # loop on the Data bytes to parse TLV'style attributes</span><br><span>         toProcess = Data</span><br><span>         while len(toProcess) > 0:</span><br><span style="color: hsl(0, 100%, 40%);">-            # TODO: seemd full compliancy </span><br><span style="color: hsl(120, 100%, 40%);">+            # TODO: seemd full compliancy</span><br><span>             # would require to work with the BERTLV parser...</span><br><span>             [T, L, V] = first_TLV_parser(toProcess)</span><br><span>             if self.dbg > 2:</span><br><span style="color: hsl(0, 100%, 40%);">-                if T in list(self.file_tags.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+                if T in list(self.file_tags.keys()):</span><br><span>                     Tag = self.file_tags[T]</span><br><span style="color: hsl(0, 100%, 40%);">-                else: </span><br><span style="color: hsl(120, 100%, 40%);">+                else:</span><br><span>                     Tag = T</span><br><span>                 print('[DBG] %s / %s: %s' % (T, Tag, V))</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             # do extra processing here</span><br><span>             # File ID, DF name, Short file id</span><br><span>             if T in (0x83, 0x84, 0x88):</span><br><span>@@ -739,8 +739,8 @@</span><br><span>                 fil = self.parse_security_attribute_compact(V, fil)</span><br><span>             # Security Attributes</span><br><span>             elif T in (0x86, 0x8B, 0x8E, 0xA0, 0xA1, 0xAB):</span><br><span style="color: hsl(0, 100%, 40%);">-                fil[self.file_tags[T]] = V </span><br><span style="color: hsl(0, 100%, 40%);">-                # TODO: no concrete parsing at this time... </span><br><span style="color: hsl(120, 100%, 40%);">+                fil[self.file_tags[T]] = V</span><br><span style="color: hsl(120, 100%, 40%);">+                # TODO: no concrete parsing at this time...</span><br><span>                 fil = self.parse_security_attribute(V, fil)</span><br><span>             # file size or length</span><br><span>             elif T in (0x80, 0x81):</span><br><span>@@ -762,16 +762,16 @@</span><br><span>                     fil[self.file_tags[T]] = V</span><br><span>                 else:</span><br><span>                     fil[T] = V</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             # truncate the data to process and loop</span><br><span>             if L < 256:</span><br><span>                 toProcess = toProcess[L+2:]</span><br><span>             else:</span><br><span>                 toProcess = toProcess[L+4:]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        # and return the file </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # and return the file</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def parse_life_cycle(Data, fil):</span><br><span>         '''</span><br><span>@@ -790,7 +790,7 @@</span><br><span>         elif Data[0] >= 16: fil['Life Cycle Status'] = 'proprietary'</span><br><span>         else: fil['Life Cycle Status'] = 'RFU'</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def parse_file_descriptor(Data, fil):</span><br><span>         '''</span><br><span>@@ -821,21 +821,21 @@</span><br><span>         # type bits b4 to b6</span><br><span>         if   fd_type == 0: fil['Type'] = 'EF working'</span><br><span>         elif fd_type == 1: fil['Type'] = 'EF internal'</span><br><span style="color: hsl(0, 100%, 40%);">-        elif fd_type == 7: </span><br><span style="color: hsl(120, 100%, 40%);">+        elif fd_type == 7:</span><br><span>             fil['Type'] = 'DF'</span><br><span>             if   fd_struct == 1: fil['Structure'] = 'BER-TLV'</span><br><span>             elif fd_struct == 2: fil['Structure'] = 'TLV'</span><br><span>         else: fil['Type'] = 'EF proprietary'</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        # for linear and cyclic EF: </span><br><span style="color: hsl(0, 100%, 40%);">-        # the following is convenient for UICC, </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # for linear and cyclic EF:</span><br><span style="color: hsl(120, 100%, 40%);">+        # the following is convenient for UICC,</span><br><span>         # but looks not fully conform to ISO standard</span><br><span>         # see coding convention in ISO 7816-4 Table 87</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(Data) == 5: </span><br><span style="color: hsl(120, 100%, 40%);">+        if len(Data) == 5:</span><br><span>             fil['Record Length'], fil['Record Number'] = Data[3], Data[4]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def parse_proprietary(Data, fil):</span><br><span>         '''</span><br><span>@@ -856,11 +856,11 @@</span><br><span>             }</span><br><span>         while len(Data) > 0:</span><br><span>             [T, L, V] = first_TLV_parser( Data )</span><br><span style="color: hsl(0, 100%, 40%);">-            if T in list(propr_tags.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+            if T in list(propr_tags.keys()):</span><br><span>                 fil[propr_tags[T]] = V</span><br><span>             Data = Data[L+2:]</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def parse_security_attribute_compact(Data, fil):</span><br><span>         '''</span><br><span>@@ -872,7 +872,7 @@</span><br><span>         AM = Data[0]</span><br><span>         SC = Data[1:]</span><br><span>         sec = '#'</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         if 'Type' in list(fil.keys()):</span><br><span>             # DF parsing</span><br><span>             if fil['Type'] == 'DF':</span><br><span>@@ -894,7 +894,7 @@</span><br><span>                 if AM & 0b00000100: sec += ' WRITE / APPEND #'</span><br><span>                 if AM & 0b00000010: sec += ' UPDATE / ERASE #'</span><br><span>                 if AM & 0b00000001: sec += ' READ / SEARCH #'</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             # loop on SC:</span><br><span>             for cond in SC:</span><br><span>                 if   cond == 0   : sec += ' Always #'</span><br><span>@@ -906,28 +906,28 @@</span><br><span>                     if cond & 0b01000000: sec += ' secure messaging #'</span><br><span>                     if cond & 0b00100000: sec += ' external authentication #'</span><br><span>                     if cond & 0b00010000: sec += ' user authentication #'</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             #file['Security Attributes raw'] = Data</span><br><span>             fil['Security Attributes'] = sec</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def parse_security_attribute(Data, fil):</span><br><span>         '''</span><br><span>         TODO: to implement...</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         need to work further on how to do it (with ref to EF_ARR)</span><br><span>         '''</span><br><span>         # See ISO-IEC 7816-4 section 5.4.3, with compact and expanded format</span><br><span>         #if self.dbg:</span><br><span>         #    print '[DBG] parse_security_attribute() not implemented'</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def read_EF(self, fil):</span><br><span>         '''</span><br><span>         interprets the content of file parameters (Structure, Size, Length...)</span><br><span>         and enriches the file dictionnary passed as argument</span><br><span style="color: hsl(0, 100%, 40%);">-        with "Data" key and corresponding </span><br><span style="color: hsl(120, 100%, 40%);">+        with "Data" key and corresponding</span><br><span>         - list of bytes for EF transparent</span><br><span>         - list of list of bytes for cyclic or linear EF</span><br><span>         '''</span><br><span>@@ -935,11 +935,11 @@</span><br><span>         if fil['Structure'] == 'transparent':</span><br><span>             self.coms.push( self.READ_BINARY(Le=fil['Size']) )</span><br><span>             if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(0, 100%, 40%);">-                if self.dbg > 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                if self.dbg > 1:</span><br><span>                     print('[DBG] %s' % self.coms())</span><br><span>                 return fil</span><br><span>             fil['Data'] = self.coms()[3]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # read EF cyclic / linear all records data</span><br><span>         elif fil['Structure'] != 'transparent':</span><br><span>             fil['Data'] = []</span><br><span>@@ -949,7 +949,7 @@</span><br><span>                 self.coms.push( self.READ_RECORD(P1=i+1, P2=0x04, \</span><br><span>                     Le=fil['Record Length']) )</span><br><span>                 if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(0, 100%, 40%);">-                    # should mean there is an issue </span><br><span style="color: hsl(120, 100%, 40%);">+                    # should mean there is an issue</span><br><span>                     # somewhere in the file parsing process</span><br><span>                     if self.dbg:</span><br><span>                         print('[WNG] error in iterating the RECORD parsing at' \</span><br><span>@@ -958,18 +958,18 @@</span><br><span>                 if self.coms()[3][1:] == len(self.coms()[3][1:]) * [255]:</span><br><span>                     # record is empty, contains padding only</span><br><span>                     pass</span><br><span style="color: hsl(0, 100%, 40%);">-                else: </span><br><span style="color: hsl(120, 100%, 40%);">+                else:</span><br><span>                     fil['Data'].append(self.coms()[3])</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        # return the [Data] for transparent or </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # return the [Data] for transparent or</span><br><span>         # [[Record1],[Record2]...] for cyclic / linear</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def select(self, Data=[0x3F, 0x00], typ="fid", with_length=True):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        self.select(Data=[0x.., 0x..], typ="fid", with_length=True) </span><br><span style="color: hsl(120, 100%, 40%);">+        self.select(Data=[0x.., 0x..], typ="fid", with_length=True)</span><br><span>             -> dict(file) on success, None on error</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         selects the file</span><br><span>         if error, returns None</span><br><span>         if processing correct: gets response with info on the file</span><br><span>@@ -977,89 +977,89 @@</span><br><span>             works in USIM fashion</span><br><span>         else returns the data dictionnary: check parse_file_(U)SIM methods</span><br><span>         last apdu available from the attribute self.coms</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         different types of file selection are possible:</span><br><span style="color: hsl(0, 100%, 40%);">-        "fid": select by file id, only the direct child or </span><br><span style="color: hsl(120, 100%, 40%);">+        "fid": select by file id, only the direct child or</span><br><span>                parent files of the last selected MF / DF / ADF</span><br><span>         "pmf": select by path from MF</span><br><span style="color: hsl(0, 100%, 40%);">-        "pdf": select by path from last selected MF / DF / ADF </span><br><span style="color: hsl(120, 100%, 40%);">+        "pdf": select by path from last selected MF / DF / ADF</span><br><span>                (or relative path)</span><br><span>         "aid": select by ADF (Application) name</span><br><span>         '''</span><br><span>         # get the UICC trigger</span><br><span>         is_UICC = isinstance(self, UICC)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # handle type of selection:</span><br><span>         if   typ == "pmf": P1 = 0x08</span><br><span>         elif typ == "pdf": P1 = 0x09</span><br><span>         elif typ == "aid": P1 = 0x04</span><br><span>         # the case of selection by "fid":</span><br><span style="color: hsl(0, 100%, 40%);">-        else: P1 = 0x00 </span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+        else: P1 = 0x00</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # for UICC instance</span><br><span>         # ask the return of the FCP template for the selected file:</span><br><span>         if is_UICC:</span><br><span>             P2 = 0x04</span><br><span>         else:</span><br><span>             P2 = 0x00</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # used to get back to MF without getting MF attributes:</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(Data) == 0: </span><br><span style="color: hsl(120, 100%, 40%);">+        if len(Data) == 0:</span><br><span>             P1, P2 = 0x00, 0x0C</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # select file and check SW; if error, returns None, else get response</span><br><span>         self.coms.push(self.SELECT_FILE(P1=P1, P2=P2, Data=Data, \</span><br><span>             with_length=with_length))</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # different SW codes for UICC and old ISO card (e.g. SIM)</span><br><span>         if is_UICC and self.coms()[2][0] != 0x61 \</span><br><span>         or not is_UICC and self.coms()[2][0] != 0x9F:</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg > 1: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg > 1:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(0, 100%, 40%);">-        # get response and check SW: </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # get response and check SW:</span><br><span>         # if error, return None, else parse file info</span><br><span>         self.coms.push(self.GET_RESPONSE(Le=self.coms()[2][1]))</span><br><span>         if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg > 1: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg > 1:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         data = self.coms()[3]</span><br><span>         # take the `parse_file()' method from the instance:</span><br><span>         # ISO7816, UICC or SIM</span><br><span>         fil = self.parse_file(data)</span><br><span>         if fil['Type'][0:2] == 'EF':</span><br><span>             fil = self.read_EF(fil)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        # finally returns the whole file dictionnary, </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # finally returns the whole file dictionnary,</span><br><span>         # containing the ['Data'] key for EF file</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     #</span><br><span>     ###############</span><br><span>     # TODO:</span><br><span>     # improve all of the following...</span><br><span>     ###############</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def flat_files_bf(self, path=[], under_AID=0, \</span><br><span>                       hi_addr=(0, 0xff), lo_addr=(0, 0xff)):</span><br><span>         '''</span><br><span>         flat_files_bf(self, path=[], under_AID=0, \</span><br><span>                       hi_addr=(0, 0xff), lo_addr=(0, 0xff))</span><br><span>             -> list(files), list(DF_to_explore)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         path: path of the DF under MF or AID to brute force</span><br><span>         under_AID: if > 0, select the AID number to init the brute force</span><br><span>             only available for UICC instance</span><br><span>         hi_addr: 8 MSB of the file address to brute force</span><br><span>         lo_addr: 8 LSB of the file address to brute force</span><br><span>         with_select_length: use the length parameter with SELECT instruction</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         brute force file addresses of direct child under a given DF</span><br><span>         get information on existing files, and discovered DF</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         WARNING: not very tested yet...</span><br><span>         '''</span><br><span>         # init return variables</span><br><span>@@ -1068,7 +1068,7 @@</span><br><span>         MF, sel_type = [0x3F, 0x00], 'fid'</span><br><span>         if isinstance(self, UICC):</span><br><span>             sel_type = 'pdf'</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # start by selecting MF</span><br><span>         try:</span><br><span>             r = self.select(MF)</span><br><span>@@ -1078,7 +1078,7 @@</span><br><span>         if r == None:</span><br><span>             print('[ERR] MF not found!')</span><br><span>             return</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         #if needed, select AID</span><br><span>         if isinstance(self, UICC) and under_AID:</span><br><span>             try:</span><br><span>@@ -1090,7 +1090,7 @@</span><br><span>             if r == None:</span><br><span>                 print('[ERR] AID not found')</span><br><span>                 return</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # place on the DF path to bf</span><br><span>         # select it by 'path from last selected DF'</span><br><span>         if len(path) > 0:</span><br><span>@@ -1102,7 +1102,7 @@</span><br><span>             if path_init == None:</span><br><span>                 print('[ERR] path not found: %s' % path)</span><br><span>                 return</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # Dany'style programming</span><br><span>         def reinit():</span><br><span>             self.select(MF)</span><br><span>@@ -1110,7 +1110,7 @@</span><br><span>                 self.select_by_aid(under_AID)</span><br><span>             if len(path) > 0:</span><br><span>                 self.select(path, sel_type)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # loop over the address space to brute force files</span><br><span>         i, j = 0, 0</span><br><span>         for i in range(hi_addr[0], hi_addr[1]):</span><br><span>@@ -1135,19 +1135,19 @@</span><br><span>                         reinit()</span><br><span>                         if 'Absolut Path' in list(fil.keys()):</span><br><span>                             DF_to_explore.append(fil['Absolut Path'])</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # re-initialize at MF and return</span><br><span>         self.select(MF)</span><br><span>         return FS, DF_to_explore</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def init_FS(self):</span><br><span>         self.FS = []</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def recu_files_bf(self, path=[], under_AID=0):</span><br><span>         '''</span><br><span>         recu_files_bf(self, path=[], under_AID=0)</span><br><span>             -> void</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         fills self.FS attribute with all files and DF discovered</span><br><span>         recursively</span><br><span>         '''</span><br><span>@@ -1159,13 +1159,13 @@</span><br><span>             '[ERR] FS not initialized: %s' % type(self.FS)</span><br><span>             return</span><br><span>         DF = ret[1]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # recursive method call</span><br><span>         # DF contains absolut path</span><br><span>         for addr in DF:</span><br><span>             print('[DBG] path: %s' % addr)</span><br><span>             self.recu_files_bf(path=addr, under_AID=under_AID)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def __write_dict(dict, fd):</span><br><span>         keys = list(dict.keys())</span><br><span>@@ -1173,31 +1173,31 @@</span><br><span>         fd.write('\n')</span><br><span>         for k in keys:</span><br><span>             fd.write('%s: %s\n' % (k, dict[k]))</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def scan_fs(self, filename='card_fs', stdout=False):</span><br><span>         '''</span><br><span>         bf_files_under_MF(self, output='card_fs', stdout=True)</span><br><span>             -> void</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         filename: file to write found information in</span><br><span>         stdout: print information on stdout too</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         brute force all file addresses from MF and found AID</span><br><span>         recursively (until no more DF are found)</span><br><span style="color: hsl(0, 100%, 40%);">-        write information on existing file on the output, </span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+        write information on existing file on the output,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         WARNING: not very tested either...</span><br><span>         '''</span><br><span>         fd = open(filename, 'w')</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.init_FS()</span><br><span>         self.recu_files_bf()</span><br><span>         fd.write('\n### MF ###\n')</span><br><span>         for f in self.FS:</span><br><span>             self.__write_dict(f, fd)</span><br><span>             fd.write('\n')</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # TODO: loop that</span><br><span>         #self.init_FS()</span><br><span>         #self.recu_files_bf(under_AID=1)</span><br><span>@@ -1205,7 +1205,7 @@</span><br><span>         #for f in self.FS:</span><br><span>         #    self.__write_dict(f, fd)</span><br><span>         #    fd.write('\n')</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         fd.close()</span><br><span> #</span><br><span> </span><br><span>@@ -1217,7 +1217,7 @@</span><br><span>     '''</span><br><span>     define attributes, methods and facilities for ETSI UICC card</span><br><span>     check UICC specifications mainly in ETSI TS 102.221</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     inherits (eventually overrides) methods and objects from ISO7816 class</span><br><span>     use self.dbg = 1 or more to print live debugging information</span><br><span>     '''</span><br><span>@@ -1254,7 +1254,7 @@</span><br><span>         (0xFF, 0x44): 'United Kingdom',</span><br><span>         (0xFF, 0x49): 'Germany',</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     pin_status = {</span><br><span>         0x01 : "PIN Appl 1",</span><br><span>         0x02 : "PIN Appl 2",</span><br><span>@@ -1286,7 +1286,7 @@</span><br><span>         0x8D : "ADM9",</span><br><span>         0x8E : "ADM10",</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     files = [</span><br><span>         ([0x3F, 0x00], 'MF', 'MF'),</span><br><span>         ([0x2F, 0x00], 'EF', 'EF_DIR'),</span><br><span>@@ -1308,48 +1308,48 @@</span><br><span>         ([0x7F, 0x90], 'DF', 'DF_TETRA'),</span><br><span>         ([0x7F, 0x31], 'DF', 'DF_iDEN'),</span><br><span>         ]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def __init__(self):</span><br><span>         '''</span><br><span>         initializes like an ISO7816-4 card with CLA=0x00</span><br><span>         and check available AID (Application ID) read from EF_DIR</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         initializes on the MF</span><br><span>         '''</span><br><span>         ISO7816.__init__(self, CLA=0x00)</span><br><span>         self.AID = []</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         if self.dbg:</span><br><span>             print('[DBG] type definition: %s' % type(self))</span><br><span>             print('[DBG] CLA definition: %s' % hex(self.CLA))</span><br><span>             #print '[DBG] EF_DIR file selection and reading...'</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def parse_file(self, Data=[]):</span><br><span>         '''</span><br><span>         parse_file(Data=[0x12, 0x34, 0x56, 0x89]) -> dict(file)</span><br><span>         mainly based on the ISO7816 parsing style</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         parses a list of bytes returned when selecting a file</span><br><span style="color: hsl(0, 100%, 40%);">-        interprets the content of some informative bytes for right accesses, </span><br><span style="color: hsl(120, 100%, 40%);">+        interprets the content of some informative bytes for right accesses,</span><br><span>         type / format of file... see TS 102.221</span><br><span>         works over the UICC file structure (quite different from e.g. SIM card)</span><br><span>         '''</span><br><span>         # First ISO7816 parsing</span><br><span>         fil = ISO7816.parse_file(self, Data)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # Then UICC extra attributes parsing</span><br><span>         if 0xC6 in list(fil.keys()):</span><br><span>             fil = self.parse_pin_status(fil[0xC6], fil)</span><br><span>             del fil[0xC6]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         if 'File Identifier' in list(fil.keys()):</span><br><span>             for ref in self.files:</span><br><span>                 if fil['File Identifier'] == ref[0]:</span><br><span>                     fil['Name'] = ref[2]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        # return the enriched file </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # return the enriched file</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     @staticmethod</span><br><span>     def parse_pin_status(Data, fil):</span><br><span>         '''</span><br><span>@@ -1364,106 +1364,106 @@</span><br><span>             [T, L, V] = first_TLV_parser(Data)</span><br><span>             assert( T in (0x83, 0x95) )</span><br><span>             if T == 0x95: # PIN usage</span><br><span style="color: hsl(0, 100%, 40%);">-                if (V[0] << 7) & 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                if (V[0] << 7) & 1:</span><br><span>                     PIN_status += '#use verification / encipherment ' \</span><br><span>                                   '/ external authentication: '</span><br><span style="color: hsl(0, 100%, 40%);">-                elif (V[0] << 6) & 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                elif (V[0] << 6) & 1:</span><br><span>                     PIN_status += '#use computation / decipherment ' \</span><br><span>                                   '/ internal authentication: '</span><br><span style="color: hsl(0, 100%, 40%);">-                elif (V[0] << 5) & 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                elif (V[0] << 5) & 1:</span><br><span>                     PIN_status += '#use SM response: '</span><br><span style="color: hsl(0, 100%, 40%);">-                elif (V[0] << 4) & 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                elif (V[0] << 4) & 1:</span><br><span>                     PIN_status += '#use SM command: '</span><br><span style="color: hsl(0, 100%, 40%);">-                elif (V[0] << 3) & 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                elif (V[0] << 3) & 1:</span><br><span>                     PIN_status += '#use PIN verification: '</span><br><span style="color: hsl(0, 100%, 40%);">-                elif (V[0] << 3) & 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                elif (V[0] << 3) & 1:</span><br><span>                     PIN_status += '#use biometric user verification: '</span><br><span style="color: hsl(0, 100%, 40%);">-                elif  V[0] == 0: </span><br><span style="color: hsl(120, 100%, 40%);">+                elif  V[0] == 0:</span><br><span>                     PIN_status += '#verification not required: '</span><br><span>             elif T == 0x83: # PIN status</span><br><span>                 if len(PIN_status) == 0: PIN_status = '#'</span><br><span style="color: hsl(0, 100%, 40%);">-                if 0x00 <  V[0] < 0x12 or   0x81 <= V[0] < 0x90: </span><br><span style="color: hsl(120, 100%, 40%);">+                if 0x00 <  V[0] < 0x12 or   0x81 <= V[0] < 0x90:</span><br><span>                     PIN_status += UICC.pin_status[V[0]] + '#'</span><br><span>                 elif 0x12 <= V[0] < 0x1E:</span><br><span>                     PIN_status += 'RFU (Global)#'</span><br><span>                 elif 0x90 <= V[0] < 0x9F:</span><br><span>                     PIN_status += 'RFU (Local)#'</span><br><span style="color: hsl(0, 100%, 40%);">-                else: </span><br><span style="color: hsl(120, 100%, 40%);">+                else:</span><br><span>                     PIN_status += '#'</span><br><span style="color: hsl(0, 100%, 40%);">-            #if self.dbg >= 2: </span><br><span style="color: hsl(120, 100%, 40%);">+            #if self.dbg >= 2:</span><br><span>             #    print '[DBG] %s: %s; PIN status: %s' % (T, V, PIN_status)</span><br><span>             Data = Data[L+2:]</span><br><span>         fil['PIN Status'] = PIN_status</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_AID(self):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        checks EF_DIR at the MF level, </span><br><span style="color: hsl(120, 100%, 40%);">+        checks EF_DIR at the MF level,</span><br><span>         and available AID (Application ID) referenced</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         puts it into self.AID</span><br><span>         interprets and print the content of the self.AID list</span><br><span>         '''</span><br><span>         #go back to MF and select EF_DIR</span><br><span>         #self.select(Data=[])</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # EF_DIR is at the MF level and contains Application ID:</span><br><span>         EF_DIR = self.select([0x2F, 0x00], typ='pmf')</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.dbg:</span><br><span>             print('[DBG] EF_DIR: %s' % EF_DIR)</span><br><span style="color: hsl(0, 100%, 40%);">-        if EF_DIR is None: </span><br><span style="color: hsl(120, 100%, 40%);">+        if EF_DIR is None:</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # EF_DIR is an EF with linear fixed structure: contains records:</span><br><span>         for rec in EF_DIR['Data']:</span><br><span>             # check for a (new) AID:</span><br><span>             if (rec[0], rec[2]) == (0x61, 0x4F) and len(rec) > 6 \</span><br><span>             and rec[4:4+rec[3]] not in self.AID:</span><br><span>                 self.AID.append( rec[4:4+rec[3]] )</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         i = 1</span><br><span>         for aid in self.AID:</span><br><span>             aid_rid = tuple(aid[0:5])</span><br><span>             aid_app = tuple(aid[5:7])</span><br><span>             aid_country = tuple(aid[7:9])</span><br><span>             aid_provider = tuple(aid[9:11])</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             # get AID application code, depending on SDO...</span><br><span>             if aid_rid == (0xA0, 0x00, 0x00, 0x00, 0x09) \</span><br><span style="color: hsl(0, 100%, 40%);">-            and aid_app in list(self.ETSI_AID_app_code.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+            and aid_app in list(self.ETSI_AID_app_code.keys()):</span><br><span>                 aid_app = self.ETSI_AID_app_code[aid_app]</span><br><span>             if aid_rid == (0xA0, 0x00, 0x00, 0x00, 0x87) \</span><br><span style="color: hsl(0, 100%, 40%);">-            and aid_app in list(self.GPP_AID_app_code.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+            and aid_app in list(self.GPP_AID_app_code.keys()):</span><br><span>                 aid_app = self.GPP_AID_app_code[aid_app]</span><br><span>             if aid_rid == (0xA0, 0x00, 0x00, 0x03, 0x43) \</span><br><span style="color: hsl(0, 100%, 40%);">-            and aid_app in list(self.GPP2_AID_app_code.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+            and aid_app in list(self.GPP2_AID_app_code.keys()):</span><br><span>                 aid_app = self.GPP2_AID_app_code[aid_app]</span><br><span>             # get AID responsible SDO and country</span><br><span>             if aid_rid in list(self.AID_RID.keys()): aid_rid = self.AID_RID[aid_rid]</span><br><span style="color: hsl(0, 100%, 40%);">-            if aid_country in list(self.AID_country_code.keys()): </span><br><span style="color: hsl(120, 100%, 40%);">+            if aid_country in list(self.AID_country_code.keys()):</span><br><span>                 aid_country = self.AID_country_code[aid_country]</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             print('found [AID %s] %s || %s || %s || %s || %s' \</span><br><span>                   % (i, aid_rid, aid_app, aid_country, \</span><br><span>                      aid_provider, tuple(aid[11:]) ))</span><br><span>             i += 1</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_ICCID(self):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        check EF_ICCID at the MF level, </span><br><span style="color: hsl(0, 100%, 40%);">-        and returnq the ASCII value of the ICCID        </span><br><span style="color: hsl(120, 100%, 40%);">+        check EF_ICCID at the MF level,</span><br><span style="color: hsl(120, 100%, 40%);">+        and returnq the ASCII value of the ICCID</span><br><span>         '''</span><br><span>         #go back to MF and select EF_ICCID</span><br><span>         #self.select(Data=[])</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # EF_ICCID is at the MF level and contains Application ID:</span><br><span>         EF_ICCID = self.select([0x2F, 0xE2], typ='pmf')</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.dbg:</span><br><span>             print('[DBG] EF_ICCID: %s' % EF_ICCID)</span><br><span style="color: hsl(0, 100%, 40%);">-        if EF_ICCID is None: </span><br><span style="color: hsl(120, 100%, 40%);">+        if EF_ICCID is None:</span><br><span>             return None</span><br><span>         return decode_BCD( EF_ICCID['Data'] )</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def select_by_name(self, name=''):</span><br><span>         '''</span><br><span>         AID selection by name taken from UICC.files</span><br><span>@@ -1471,13 +1471,10 @@</span><br><span>         for i in range(len(self.files)):</span><br><span>             if name == self.files[i][2]:</span><br><span>                 return self.select( self.files[i][0], 'pmf' )</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def select_by_aid(self, aid_num=1):</span><br><span>         '''</span><br><span>         AID selection by index</span><br><span>         '''</span><br><span>         if len(self.AID) != 0:</span><br><span>             return self.select(self.AID[aid_num-1], 'aid')</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>diff --git a/card/SIM.py b/card/SIM.py</span><br><span>index 78864a7..555f0df 100644</span><br><span>--- a/card/SIM.py</span><br><span>+++ b/card/SIM.py</span><br><span>@@ -36,11 +36,11 @@</span><br><span>     '''</span><br><span>     define attributes, methods and facilities for ETSI / 3GPP SIM card</span><br><span>     check SIM specifications in ETSI TS 102.221 and 3GPP TS 51.011</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     inherit methods and objects from ISO7816 class</span><br><span>     use self.dbg = 1 or more to print live debugging information</span><br><span>     '''</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def __init__(self):</span><br><span>         '''</span><br><span>         initialize like an ISO7816-4 card with CLA=0xA0</span><br><span>@@ -50,7 +50,7 @@</span><br><span>         if self.dbg:</span><br><span>             print('[DBG] type definition: %s' % type(self))</span><br><span>             print('[DBG] CLA definition: %s' % hex(self.CLA))</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.caller = {</span><br><span>         'KC' : self.get_Kc,</span><br><span>         'IMSI' : self.get_imsi,</span><br><span>@@ -63,12 +63,12 @@</span><br><span>         'MSISDN' : self.get_msisdn,</span><br><span>         'SMSP' : self.get_smsp,</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def sw_status(self, sw1, sw2):</span><br><span>         '''</span><br><span>         sw_status(sw1=int, sw2=int) -> string</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        extends SW status bytes interpretation from ISO7816 </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        extends SW status bytes interpretation from ISO7816</span><br><span>         with ETSI / 3GPP SW codes</span><br><span>         helps to speak with the smartcard!</span><br><span>         '''</span><br><span>@@ -109,7 +109,7 @@</span><br><span>                 'application specific'</span><br><span>             elif sw2 == 0x63: status += ': security session expired'</span><br><span>         return status</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def verify_pin(self, pin='', pin_type=1):</span><br><span>         '''</span><br><span>         verify CHV1 (PIN code) or CHV2 with VERIFY APDU command</span><br><span>@@ -119,14 +119,14 @@</span><br><span>         len(pin) == 4 and 0 <= int(pin) < 10000:</span><br><span>             PIN = [ord(i) for i in pin] + [0xFF, 0xFF, 0xFF, 0xFF]</span><br><span>             self.coms.push( self.VERIFY(P2=pin_type, Data=PIN) )</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[WNG] bad parameters')</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def disable_pin(self, pin='', pin_type=1):</span><br><span>         '''</span><br><span>         disable CHV1 (PIN code) or CHV2 with DISABLE_CHV APDU command</span><br><span style="color: hsl(0, 100%, 40%);">-        TIP: do it as soon as you can when you are working </span><br><span style="color: hsl(120, 100%, 40%);">+        TIP: do it as soon as you can when you are working</span><br><span>         with a SIM / USIM card for which you know the PIN!</span><br><span>         call ISO7816 DISABLE method</span><br><span>         '''</span><br><span>@@ -135,22 +135,22 @@</span><br><span>             PIN = [ord(i) for i in pin] + [0xFF, 0xFF, 0xFF, 0xFF]</span><br><span>             self.coms.push( self.DISABLE_CHV(P2=pin_type, Data=PIN) )</span><br><span>         else:</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[WNG] bad parameters')</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def unblock_pin(self, pin_type=1, unblock_pin=''):</span><br><span>         '''</span><br><span>         WARNING: not correctly implemented!!!</span><br><span>             and PUK are in general 8 nums...</span><br><span>         TODO: make it correctly!</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        unblock CHV1 (PIN code) or CHV2 with UNBLOCK_CHV APDU command </span><br><span style="color: hsl(120, 100%, 40%);">+        unblock CHV1 (PIN code) or CHV2 with UNBLOCK_CHV APDU command</span><br><span>         and set 0000 value for new PIN</span><br><span>         call ISO7816 UNBLOCK_CHV method</span><br><span>         '''</span><br><span>         print('not correctly implemented')</span><br><span>         return</span><br><span style="color: hsl(0, 100%, 40%);">-        #if pin_type == 1: </span><br><span style="color: hsl(120, 100%, 40%);">+        #if pin_type == 1:</span><br><span>         #    pin_type = 0</span><br><span>         if pin_type in [0, 2] and type(unblock_pin) is str and \</span><br><span>         len(unblock_pin) == 4 and 0 <= int(unblock_pin) < 10000:</span><br><span>@@ -159,16 +159,16 @@</span><br><span>                             Data=UNBL_PIN + \</span><br><span>                             [0x30, 0x30, 0x30, 0x30, 0xFF, 0xFF, 0xFF, 0xFF]) )</span><br><span>         else:</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[WNG] bad parameters')</span><br><span>             #return self.UNBLOCK_CHV(P2=pin_type)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def parse_file(self, Data=[]):</span><br><span>         '''</span><br><span>         parse_file(Data=[0x12, 0x34, 0x56, 0x89]) -> dict(file)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         parses a list of bytes returned when selecting a file</span><br><span style="color: hsl(0, 100%, 40%);">-        interprets the content of some informative bytes for right accesses, </span><br><span style="color: hsl(120, 100%, 40%);">+        interprets the content of some informative bytes for right accesses,</span><br><span>         type / format of file... see TS 51.011</span><br><span>         works over the SIM file structure</span><br><span>         '''</span><br><span>@@ -193,10 +193,10 @@</span><br><span>             fil['unblock_CHV2'] = ('not initialized','initialized')\</span><br><span>                                   [(Data[21] & 0x80) // 0x80]\</span><br><span>                                 + ': %d attempts remain' % (Data[21] & 0x0F)</span><br><span style="color: hsl(0, 100%, 40%);">-            if len(Data) > 23: </span><br><span style="color: hsl(120, 100%, 40%);">+            if len(Data) > 23:</span><br><span>                 fil['Adm'] = Data[23:]</span><br><span>         elif fil['Type'] == 'EF':</span><br><span style="color: hsl(0, 100%, 40%);">-            cond = ('ALW', 'CHV1', 'CHV2', 'RFU', 'ADM_4', 'ADM_5', </span><br><span style="color: hsl(120, 100%, 40%);">+            cond = ('ALW', 'CHV1', 'CHV2', 'RFU', 'ADM_4', 'ADM_5',</span><br><span>                     'ADM_6', 'ADM_7', 'ADM_8', 'ADM_9', 'ADM_A',</span><br><span>                     'ADM_B', 'ADM_C', 'ADM_D', 'ADM_E', 'NEW')</span><br><span>             fil['UPDATE'] = cond[Data[8] & 0x0F]</span><br><span>@@ -204,77 +204,77 @@</span><br><span>             fil['INCREASE'] = cond[Data[9] >> 4]</span><br><span>             fil['INVALIDATE'] = cond[Data[10] & 0x0F]</span><br><span>             fil['REHABILITATE'] = cond[Data[10] >> 4]</span><br><span style="color: hsl(0, 100%, 40%);">-            fil['Status'] = ('not read/updatable when invalidated', </span><br><span style="color: hsl(120, 100%, 40%);">+            fil['Status'] = ('not read/updatable when invalidated',</span><br><span>                               'read/updatable when invalidated')\</span><br><span>                             [byteToBit(Data[11])[5]] \</span><br><span>                           + (': invalidated',': not invalidated')\</span><br><span>                             [byteToBit(Data[11])[7]]</span><br><span>             fil['Structure'] = ('transparent', 'linear fixed', '', 'cyclic')\</span><br><span>                                [Data[13]]</span><br><span style="color: hsl(0, 100%, 40%);">-            if fil['Structure'] == 'cyclic': </span><br><span style="color: hsl(120, 100%, 40%);">+            if fil['Structure'] == 'cyclic':</span><br><span>                 fil['INCREASE'] = byteToBit(Data[7])[1]</span><br><span style="color: hsl(0, 100%, 40%);">-            if len(Data) > 14: </span><br><span style="color: hsl(120, 100%, 40%);">+            if len(Data) > 14:</span><br><span>                 fil['Record Length'] = Data[14]</span><br><span>         return fil</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def run_gsm_alg(self, RAND=16*[0x00]):</span><br><span>         '''</span><br><span>         self.run_gsm_alg( RAND ) -> ( SRES, Kc )</span><br><span>             RAND : list of bytes, length 16</span><br><span>             SRES : list of bytes, length 4</span><br><span>             Kc : list of bytes, length 8</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(0, 100%, 40%);">-        run GSM authentication algorithm: </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        run GSM authentication algorithm:</span><br><span>             accepts any kind of RAND (old GSM fashion)</span><br><span>         feed with RAND 16 bytes value</span><br><span>         return a list with SRES and Kc, or None on error</span><br><span>         '''</span><br><span>         if len(RAND) != 16:</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[WNG] needs a 16 bytes input RAND value')</span><br><span>             return None</span><br><span>         # select DF_GSM directory</span><br><span>         self.select([0x7F, 0x20])</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.coms()[2] != (0x90, 0x00): </span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span>         # run authentication</span><br><span>         self.coms.push(self.INTERNAL_AUTHENTICATE(P1=0x00, P2=0x00, Data=RAND))</span><br><span>         if self.coms()[2][0] != 0x9F:</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span>         # get authentication response</span><br><span>         self.coms.push(self.GET_RESPONSE(Le=self.coms()[2][1]))</span><br><span>         if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span>         SRES, Kc = self.coms()[3][0:4], self.coms()[3][4:]</span><br><span>         return [ SRES, Kc ]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_imsi(self):</span><br><span>         '''</span><br><span>         self.get_imsi() -> string(IMSI)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         reads IMSI value at address [0x6F, 0x07]</span><br><span>         returns IMSI string on success or None on error</span><br><span>         '''</span><br><span>         # select DF_GSM for SIM card</span><br><span>         self.select([0x7F, 0x20])</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.coms()[2] != (0x90, 0x00): </span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # select IMSI file</span><br><span>         imsi = self.select([0x6F, 0x07])</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.coms()[2] != (0x90, 0x00): </span><br><span style="color: hsl(0, 100%, 40%);">-            if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.coms()[2] != (0x90, 0x00):</span><br><span style="color: hsl(120, 100%, 40%);">+            if self.dbg:</span><br><span>                 print('[DBG] %s' % self.coms())</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # and parse the received data into the IMSI structure</span><br><span>         if 'Data' in list(imsi.keys()) and len(imsi['Data']) == 9:</span><br><span> </span><br><span>@@ -282,9 +282,9 @@</span><br><span>                 print("[DBG] International Mobile Subscriber Identity (IMSI): %s " % decode_BCD(imsi['Data'])[3:])</span><br><span> </span><br><span>             return decode_BCD(imsi['Data'])[3:]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # if issue with the content of the DF_IMSI file</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.dbg:</span><br><span>             print('[DBG] %s' % self.coms())</span><br><span>         return None</span><br><span> </span><br><span>@@ -313,7 +313,7 @@</span><br><span>             return Kc['Data']</span><br><span>         else:</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     # EF loci contains location information</span><br><span>     # This conatins TMSI, LAI, TMSI TIME, and Location update status</span><br><span>     # and prints the information</span><br><span>@@ -590,4 +590,3 @@</span><br><span>             return iccid</span><br><span>         else:</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>diff --git a/card/USIM.py b/card/USIM.py</span><br><span>index fa20d1a..45c2a3e 100644</span><br><span>--- a/card/USIM.py</span><br><span>+++ b/card/USIM.py</span><br><span>@@ -37,16 +37,16 @@</span><br><span>     '''</span><br><span>     defines attributes, methods and facilities for ETSI / 3GPP USIM card</span><br><span>     check USIM specifications in 3GPP TS 31.102</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     inherits (eventually overrides) methods and objects from UICC class</span><br><span>     use self.dbg = 1 or more to print live debugging information</span><br><span>     '''</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def __init__(self):</span><br><span>         '''</span><br><span>         initializes like an ISO7816-4 card with CLA=0x00</span><br><span>         and checks available AID (Application ID) read from EF_DIR</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         initializes on the MF</span><br><span>         '''</span><br><span>         # initialize like a UICC</span><br><span>@@ -55,7 +55,7 @@</span><br><span>         if self.dbg:</span><br><span>             print('[DBG] type definition: %s' % type(self))</span><br><span>             print('[DBG] CLA definition: %s' % hex(self.CLA))</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # USIM selection from AID</span><br><span>         print('[+] UICC AID found:')</span><br><span>         self.get_AID()</span><br><span>@@ -63,37 +63,37 @@</span><br><span>             if  tuple(aid[0:5]) == (0xA0, 0x00, 0x00, 0x00, 0x87) \</span><br><span>             and tuple(aid[5:7]) == (0x10, 0x02) :</span><br><span>                 usim = self.select( Data=aid, typ='aid')</span><br><span style="color: hsl(0, 100%, 40%);">-                if usim is None: </span><br><span style="color: hsl(120, 100%, 40%);">+                if usim is None:</span><br><span>                     print('[+] USIM AID selection failed')</span><br><span style="color: hsl(0, 100%, 40%);">-                else: </span><br><span style="color: hsl(120, 100%, 40%);">+                else:</span><br><span>                     print('[+] USIM AID selection succeeded\n')</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_imsi(self):</span><br><span>         '''</span><br><span>         get_imsi() -> string(IMSI)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         reads IMSI value at address [0x6F, 0x07]</span><br><span>         returns IMSI string on success or None on error</span><br><span>         '''</span><br><span>         # select IMSI file</span><br><span>         imsi = self.select([0x6F, 0x07])</span><br><span style="color: hsl(0, 100%, 40%);">-        if imsi is None: </span><br><span style="color: hsl(120, 100%, 40%);">+        if imsi is None:</span><br><span>             return None</span><br><span>         # and parse the received data into the IMSI structure</span><br><span>         if 'Data' in list(imsi.keys()) and len(imsi['Data']) == 9:</span><br><span>             return decode_BCD(imsi['Data'])[3:]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # if issue with the content of the DF_IMSI file</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.dbg:</span><br><span>             print('[DBG] %s' % self.coms())</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_CS_keys(self):</span><br><span>         '''</span><br><span>         get_CS_keys() -> [KSI, CK, IK]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         reads CS UMTS keys at address [0x6F, 0x08]</span><br><span style="color: hsl(0, 100%, 40%);">-        returns list of 3 keys, each are list of bytes, on success </span><br><span style="color: hsl(120, 100%, 40%);">+        returns list of 3 keys, each are list of bytes, on success</span><br><span>             (or eventually the whole file dict if the format is strange)</span><br><span>         or None on error</span><br><span>         '''</span><br><span>@@ -105,39 +105,39 @@</span><br><span>                                 EF_KEYS['Data'][17:33])</span><br><span>                 print('[+] Successful CS keys selection: Get [KSI, CK, IK]')</span><br><span>                 return [KSI, CK, IK]</span><br><span style="color: hsl(0, 100%, 40%);">-            else: </span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span>                 return EF_KEYS</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_PS_keys(self):</span><br><span>         '''</span><br><span>         get_PS_keys() -> [KSI, CK_PS, IK_PS]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         reads PS UMTS keys at address [0x6F, 0x09]</span><br><span style="color: hsl(0, 100%, 40%);">-        returns list of 3 keys, each are list of bytes, on success </span><br><span style="color: hsl(120, 100%, 40%);">+        returns list of 3 keys, each are list of bytes, on success</span><br><span>             (or eventually the whole file dict if the format is strange)</span><br><span>         or None on error</span><br><span>         '''</span><br><span>         EF_KEYSPS = self.select( [0x6F, 0x09] )</span><br><span>         if self.coms()[2] == (0x90, 0x00):</span><br><span>             if len(EF_KEYSPS['Data']) == 33:</span><br><span style="color: hsl(0, 100%, 40%);">-                KSI, CK, IK = ( EF_KEYSPS['Data'][0:1], </span><br><span style="color: hsl(0, 100%, 40%);">-                                EF_KEYSPS['Data'][1:17], </span><br><span style="color: hsl(120, 100%, 40%);">+                KSI, CK, IK = ( EF_KEYSPS['Data'][0:1],</span><br><span style="color: hsl(120, 100%, 40%);">+                                EF_KEYSPS['Data'][1:17],</span><br><span>                                 EF_KEYSPS['Data'][17:33] )</span><br><span>                 print('[+] Successful PS keys selection: Get [KSI, CK, IK]')</span><br><span>                 return [KSI, CK, IK]</span><br><span style="color: hsl(0, 100%, 40%);">-            else: </span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span>                 return EF_KEYSPS</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_GBA_BP(self):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        get_GBA_BP() -> [[RAND, B-TID, KeyLifetime], ...], </span><br><span style="color: hsl(120, 100%, 40%);">+        get_GBA_BP() -> [[RAND, B-TID, KeyLifetime], ...],</span><br><span>         Length-Value parsing style</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        reads EF_GBABP file at address [0x6F, 0xD6], </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        reads EF_GBABP file at address [0x6F, 0xD6],</span><br><span>             containing RAND and associated B-TID and KeyLifetime</span><br><span style="color: hsl(0, 100%, 40%);">-        returns list of list of bytes on success </span><br><span style="color: hsl(120, 100%, 40%);">+        returns list of list of bytes on success</span><br><span>             (or eventually the whole file dict if the format is strange)</span><br><span>         or None on error</span><br><span>         '''</span><br><span>@@ -149,17 +149,17 @@</span><br><span>                       '[RAND, B-TID, KeyLifetime]')</span><br><span>                 #return (RAND, B_TID, Lifetime)</span><br><span>                 return LV_parser( EF_GBABP['Data'] )</span><br><span style="color: hsl(0, 100%, 40%);">-            else: </span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span>                 return EF_GBABP</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def update_GBA_BP(self, RAND, B_TID, key_lifetime):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        update_GBA_BP([RAND], [B_TID], [key_lifetime]) </span><br><span style="color: hsl(120, 100%, 40%);">+        update_GBA_BP([RAND], [B_TID], [key_lifetime])</span><br><span>             -> void (or EF_GBABP file dict if RAND not found)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         reads EF_GBABP file at address [0x6F, 0xD6],</span><br><span style="color: hsl(0, 100%, 40%);">-        checks if RAND provided is referenced, </span><br><span style="color: hsl(120, 100%, 40%);">+        checks if RAND provided is referenced,</span><br><span>         and updates the file structure with provided B-TID and KeyLifetime</span><br><span>         returns nothing (or eventually the whole file dict</span><br><span>         if the RAND is not found)</span><br><span>@@ -172,35 +172,35 @@</span><br><span>                 self.coms.push( self.UPDATE_BINARY( P2=len(RAND)+1,</span><br><span>                                 Data=[len(B_TID)] + B_TID + \</span><br><span>                                 [len(key_lifetime)] + key_lifetime ))</span><br><span style="color: hsl(0, 100%, 40%);">-                if self.dbg > 1: </span><br><span style="color: hsl(120, 100%, 40%);">+                if self.dbg > 1:</span><br><span>                     print('[DBG] %s' % self.coms())</span><br><span>                 if self.coms()[2] == 0x90 and self.dbg:</span><br><span>                     print('[+] Successful GBA_BP update with B-TID ' \</span><br><span>                           'and key lifetime')</span><br><span style="color: hsl(0, 100%, 40%);">-                if self.dbg > 2: </span><br><span style="color: hsl(120, 100%, 40%);">+                if self.dbg > 2:</span><br><span>                     print('[DBG] new value of EF_GBA_BP:\n%s' \</span><br><span>                           % self.get_GBA_BP())</span><br><span>             else:</span><br><span style="color: hsl(0, 100%, 40%);">-                if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+                if self.dbg:</span><br><span>                     print('[+] RAND not found in GBA_BP')</span><br><span>                 return GBA_BP</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def get_GBA_NL(self):</span><br><span>         '''</span><br><span>         get_GBA_NL() -> [[NAF_ID, B-TID], ...] , TLV parsing style</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         reads EF_GBANL file at address [0x6F, 0xDA], containing NAF_ID and B-TID</span><br><span style="color: hsl(0, 100%, 40%);">-        returns list of list of bytes vector on success </span><br><span style="color: hsl(120, 100%, 40%);">+        returns list of list of bytes vector on success</span><br><span>             (or eventually the whole file dict if the format is strange)</span><br><span>         or None on error</span><br><span>         '''</span><br><span>         EF_GBANL = self.select( [0x6F, 0xDA] )</span><br><span>         if self.coms()[2] == (0x90, 0x00):</span><br><span>             if len(EF_GBANL['Data'][0]) > 2:</span><br><span style="color: hsl(0, 100%, 40%);">-                # This is Tag-Length-Value parsing, </span><br><span style="color: hsl(120, 100%, 40%);">+                # This is Tag-Length-Value parsing,</span><br><span>                 # with 0x80 for NAF_ID and 0x81 for B-TID</span><br><span>                 values = []</span><br><span style="color: hsl(0, 100%, 40%);">-                </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                 for rec in EF_GBANL['Data']:</span><br><span>                     NAF_ID, B_TID = [], []</span><br><span>                     while len(rec) > 0:</span><br><span>@@ -209,26 +209,26 @@</span><br><span>                             rec = rec[ tlv[1]+4 : ]</span><br><span>                         else:</span><br><span>                             rec = rec[ tlv[1]+2 : ]</span><br><span style="color: hsl(0, 100%, 40%);">-                        if tlv[0] == 0x80: </span><br><span style="color: hsl(120, 100%, 40%);">+                        if tlv[0] == 0x80:</span><br><span>                             NAF_ID = tlv[2]</span><br><span style="color: hsl(0, 100%, 40%);">-                        elif tlv[0] == 0x81: </span><br><span style="color: hsl(120, 100%, 40%);">+                        elif tlv[0] == 0x81:</span><br><span>                             B_TID = tlv[2]</span><br><span>                     values.append( [NAF_ID, B_TID] )</span><br><span style="color: hsl(0, 100%, 40%);">-                </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                 print('[+] Successful GBA_NL selection: ' \</span><br><span>                       'Get list of [NAF_ID, B-TID]')</span><br><span>                 #return (NAF_ID, B_TID)</span><br><span>                 return values</span><br><span style="color: hsl(0, 100%, 40%);">-            else: </span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span>                 return EF_GBANL</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def authenticate(self, RAND=[], AUTN=[], ctx='3G'):</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        self.authenticate(RAND, AUTN, ctx='3G') -> [key1, key2...], </span><br><span style="color: hsl(120, 100%, 40%);">+        self.authenticate(RAND, AUTN, ctx='3G') -> [key1, key2...],</span><br><span>         LV parsing style</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        runs the INTERNAL AUTHENTICATE command in the USIM </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        runs the INTERNAL AUTHENTICATE command in the USIM</span><br><span>         with the right context:</span><br><span>             ctx = '2G', '3G', 'GBA' ('MBMS' or other not supported at this time)</span><br><span>             RAND and AUTN are list of bytes; for '2G' context, AUTN is not used</span><br><span>@@ -241,10 +241,10 @@</span><br><span>         '''</span><br><span>         # prepare input data for authentication</span><br><span>         if ctx in ('3G', 'VGCS', 'GBA', 'MBMS') and len(RAND) != 16 \</span><br><span style="color: hsl(0, 100%, 40%);">-        and len(AUTN) != 16: </span><br><span style="color: hsl(120, 100%, 40%);">+        and len(AUTN) != 16:</span><br><span>             print('[ERR] missing parameters or wrong length')</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         inp = []</span><br><span>         if ctx == '3G':</span><br><span>             P2 = 0x81</span><br><span>@@ -255,27 +255,27 @@</span><br><span>         elif ctx == 'MBMS':</span><br><span>             print('[+] Not implemented. Exit.')</span><br><span>             return None</span><br><span style="color: hsl(0, 100%, 40%);">-        elif ctx == 'GBA': </span><br><span style="color: hsl(120, 100%, 40%);">+        elif ctx == 'GBA':</span><br><span>             P2 = 0x84</span><br><span>             inp = [0xDD]</span><br><span>         inp.extend( [len(RAND)] + RAND + [len(AUTN)] + AUTN )</span><br><span style="color: hsl(0, 100%, 40%);">-        if ctx not in ['3G', 'VGCS', 'MBMS', 'GBA']: </span><br><span style="color: hsl(0, 100%, 40%);">-        # and also, if ctx == '2G'... the safe way </span><br><span style="color: hsl(120, 100%, 40%);">+        if ctx not in ['3G', 'VGCS', 'MBMS', 'GBA']:</span><br><span style="color: hsl(120, 100%, 40%);">+        # and also, if ctx == '2G'... the safe way</span><br><span>         # to avoid desynchronizing our USIM counter</span><br><span>             P2 = 0x80</span><br><span style="color: hsl(0, 100%, 40%);">-            if len(RAND) != 16: </span><br><span style="color: hsl(120, 100%, 40%);">+            if len(RAND) != 16:</span><br><span>                 print('[ERR] RAND has wrong length (%d, should be 16)' % len(RAND))</span><br><span>                 return None</span><br><span>             # override input value for 2G authent</span><br><span>             inp = [len(RAND)] + RAND</span><br><span style="color: hsl(0, 100%, 40%);">-            </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.coms.push( self.INTERNAL_AUTHENTICATE(P2=P2, Data=inp) )</span><br><span>         if self.coms()[2][0] in (0x9F, 0x61):</span><br><span>             self.coms.push( self.GET_RESPONSE(Le=self.coms()[2][1]) )</span><br><span>             if self.coms()[2] == (0x90, 0x00):</span><br><span>                 val = self.coms()[3]</span><br><span>                 if P2 == 0x80:</span><br><span style="color: hsl(0, 100%, 40%);">-                    if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+                    if self.dbg:</span><br><span>                         print('[+] Successful 2G authentication. Get [RES, Kc]')</span><br><span>                     values = LV_parser(val)</span><br><span>                     # returned values are (RES, Kc)</span><br><span>@@ -294,65 +294,65 @@</span><br><span>                     # returned values can be (RES, CK, IK) or (RES, CK, IK, Kc)</span><br><span>                     return values</span><br><span>                 elif val[0] == 0xDC:</span><br><span style="color: hsl(0, 100%, 40%);">-                    if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+                    if self.dbg:</span><br><span>                         print('[+] Synchronization failure. Get [AUTS]')</span><br><span>                     values = LV_parser(val[1:])</span><br><span>                     return values</span><br><span>                 elif self.dbg:</span><br><span>                     print('[+] response: %s' % hex(val))</span><br><span>         #else:</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.dbg:</span><br><span>             print('[+] authentication error: %s' % self.coms())</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def GBA_derivation(self, NAF_ID=[], IMPI=[]):</span><br><span>         '''</span><br><span>         self.GBA_derivation(NAF_ID, IMPI) -> [Ks_ext_naf]</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(0, 100%, 40%);">-        runs the INTERNAL AUTHENTICATE command in the USIM </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        runs the INTERNAL AUTHENTICATE command in the USIM</span><br><span>         with the GBA derivation context:</span><br><span>             NAF_ID is a list of bytes (use stringToByte())</span><br><span style="color: hsl(0, 100%, 40%);">-                "NAF domain name"||"security protocol id", </span><br><span style="color: hsl(120, 100%, 40%);">+                "NAF domain name"||"security protocol id",</span><br><span>                 eg: "application.org"||"0x010001000a" (> TLS with RSA and SHA)</span><br><span>             IMPI is a list of bytes</span><br><span>                 "IMSI@ims.mncXXX.mccYYY.3gppnetwork.org" if no IMS IMPI</span><br><span style="color: hsl(0, 100%, 40%);">-                is specifically defined in the USIM </span><br><span style="color: hsl(120, 100%, 40%);">+                is specifically defined in the USIM</span><br><span>         returns a list with GBA ext key (list of bytes) computed in the USIM:</span><br><span>             [Ks_ext_naf]</span><br><span style="color: hsl(0, 100%, 40%);">-            Ks_int_naf remains available in the USIM </span><br><span style="color: hsl(120, 100%, 40%);">+            Ks_int_naf remains available in the USIM</span><br><span>             for further GBA_U key derivation</span><br><span>         or None on error</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         see TS 33.220 for GBA specific formats</span><br><span>         '''</span><br><span style="color: hsl(0, 100%, 40%);">-        # need to run 1st an authenicate command with 'GBA' context, </span><br><span style="color: hsl(120, 100%, 40%);">+        # need to run 1st an authenicate command with 'GBA' context,</span><br><span>         # so to have the required keys in the USIM</span><br><span>         P2 = 0x84</span><br><span>         inp = [0xDE] + [len(NAF_ID)] + NAF_ID + [len(IMPI)] + IMPI</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.coms.push( self.INTERNAL_AUTHENTICATE(P2=P2, Data=inp) )</span><br><span>         if self.coms()[2][0] in (0x9F, 0x61):</span><br><span>             self.coms.push( self.GET_RESPONSE(Le=self.coms()[2][1]) )</span><br><span>             if self.coms()[2] == (0x90, 0x00):</span><br><span>                 val = self.coms()[3]</span><br><span>                 if val[0] == 0xDB: # not adapted to 2G context with Kc, RES</span><br><span style="color: hsl(0, 100%, 40%);">-                    if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+                    if self.dbg:</span><br><span>                         print('[+] Successful GBA derivation. Get [Ks_EXT_NAF]')</span><br><span>                     values = LV_parser(val[1:])</span><br><span>                     return values</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.dbg: </span><br><span style="color: hsl(120, 100%, 40%);">+        if self.dbg:</span><br><span>             print('[DBG] authentication failure: %s' % self.coms())</span><br><span>         return None</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(0, 100%, 40%);">-    def bf_FS_from_init( self, filename='bf_USIM', file_dict=USIM_app_FS, </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def bf_FS_from_init( self, filename='bf_USIM', file_dict=USIM_app_FS,</span><br><span>                          init_method='select_by_aid', init_args=[1] ):</span><br><span>         '''</span><br><span>         bruteforces the USIM filesystem at the application initialization level:</span><br><span>             thanks to UICC.select_by_aid(1)</span><br><span>             could be used another way...</span><br><span style="color: hsl(0, 100%, 40%);">-        stores the result in the file passed in argument </span><br><span style="color: hsl(120, 100%, 40%);">+        stores the result in the file passed in argument</span><br><span>         (file will be overwritten)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         TODO: does not manage file recursivity (when entering DF)</span><br><span>         only scan 1st level files</span><br><span>         '''</span><br><span>@@ -360,7 +360,7 @@</span><br><span>         # loop on all possible addresses</span><br><span>         for i in range(0x00, 0xff):</span><br><span>             for j in range(0x00, 0xff):</span><br><span style="color: hsl(0, 100%, 40%);">-                # here "ret" is useless, </span><br><span style="color: hsl(120, 100%, 40%);">+                # here "ret" is useless,</span><br><span>                 # but calling the method places the smartcard</span><br><span>                 # at the right address (by default: 1st AID)</span><br><span>                 ret = getattr(self, init_method)(*init_args)</span><br><span>@@ -387,10 +387,10 @@</span><br><span>                     fd.write('file exists at address: %s %s\n' \</span><br><span>                              % (hex(i)[2:], hex(j)[2:]))</span><br><span>                     fd.write('%s\n' % self.coms()[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                    </span><br><span style="color: hsl(0, 100%, 40%);">-                if self.dbg and (i % 0x10 == 0 and j % 0x40 == 0): </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if self.dbg and (i % 0x10 == 0 and j % 0x40 == 0):</span><br><span>                     print('[-] going over address %s %s' % (i, j))</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         fd.write('\n')</span><br><span>         fd.close()</span><br><span> </span><br><span>diff --git a/card/utils.py b/card/utils.py</span><br><span>index 9a04dcf..56d70fc 100644</span><br><span>--- a/card/utils.py</span><br><span>+++ b/card/utils.py</span><br><span>@@ -26,12 +26,12 @@</span><br><span> from smartcard.util import toBytes, toHexString, PACK</span><br><span> import sys</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# from python 2.6, format('b') allows to use 0b10010110 notation: </span><br><span style="color: hsl(120, 100%, 40%);">+# from python 2.6, format('b') allows to use 0b10010110 notation:</span><br><span> # much convinient</span><br><span> def byteToBit(byte):</span><br><span>     '''</span><br><span>     byteToBit(0xAB) -> [1, 0, 1, 0, 1, 0, 1, 1]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     converts a byte integer value into a list of bits</span><br><span>     '''</span><br><span>     bit = [0, 0, 0, 0, 0, 0, 0, 0]</span><br><span>@@ -46,7 +46,7 @@</span><br><span> def stringToByte(string):</span><br><span>     '''</span><br><span>     stringToByte('test') -> [116, 101, 115, 116]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     converts a string into a list of bytes</span><br><span>     '''</span><br><span>     bytelist = []</span><br><span>@@ -62,7 +62,7 @@</span><br><span> def byteToString(bytelist):</span><br><span>     '''</span><br><span>     byteToString([116, 101, 115, 116]) -> 'test'</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     converts a list of bytes into a string</span><br><span>     '''</span><br><span>     string = ''</span><br><span>@@ -82,7 +82,7 @@</span><br><span> def LV_parser(bytelist):</span><br><span>     '''</span><br><span>     LV_parser([0x02, 0xAB, 0xCD, 0x01, 0x12, 0x34]) -> [[171, 205], [18], []]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     parses Length-Value records in a list of bytes</span><br><span>     returns a list of list of bytes</span><br><span>     length coded on 1 byte</span><br><span>@@ -97,8 +97,8 @@</span><br><span> def first_TLV_parser(bytelist):</span><br><span>     '''</span><br><span>     first_TLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00]) -> (170, 2, [171, 205])</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(0, 100%, 40%);">-    parses first TLV format record in a list of bytelist </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    parses first TLV format record in a list of bytelist</span><br><span>     returns a 3-Tuple: Tag, Length, Value</span><br><span>     Value is a list of bytes</span><br><span>     parsing of length is ETSI'style 101.220</span><br><span>@@ -115,7 +115,7 @@</span><br><span> def TLV_parser(bytelist):</span><br><span>     '''</span><br><span>     TLV_parser([0xAA, ..., 0xFF]) -> [(T, L, [V]), (T, L, [V]), ...]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     loops on the input list of bytes with the "first_TLV_parser()" function</span><br><span>     returns a list of 3-Tuples</span><br><span>     '''</span><br><span>@@ -127,17 +127,17 @@</span><br><span>             break</span><br><span>         ret.append( (T, L, V) )</span><br><span>         # need to manage length of L</span><br><span style="color: hsl(0, 100%, 40%);">-        if L > 0xFE: </span><br><span style="color: hsl(120, 100%, 40%);">+        if L > 0xFE:</span><br><span>             bytelist = bytelist[ L+4 : ]</span><br><span style="color: hsl(0, 100%, 40%);">-        else: </span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span>             bytelist = bytelist[ L+2 : ]</span><br><span>     return ret</span><br><span> </span><br><span> def first_BERTLV_parser(bytelist):</span><br><span>     '''</span><br><span style="color: hsl(0, 100%, 40%);">-    first_BERTLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00]) </span><br><span style="color: hsl(120, 100%, 40%);">+    first_BERTLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00])</span><br><span>         -> ([1, 'contextual', 'constructed', 10], [1, 2], [171, 205])</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     parses first BER-TLV format record in a list of bytes</span><br><span>     returns a 3-Tuple: Tag, Length, Value</span><br><span>         Tag: [Tag class, Tag DO, Tag number]</span><br><span>@@ -170,12 +170,12 @@</span><br><span>     # Tag coded with 1 byte</span><br><span>     else:</span><br><span>         Tag_bits = byte0[3:8]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(0, 100%, 40%);">-    # Tag number calculation </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    # Tag number calculation</span><br><span>     Tag_num = 0</span><br><span>     for j in range(len(Tag_bits)):</span><br><span>         Tag_num += Tag_bits[len(Tag_bits)-j-1] * pow(2, j)</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     # Length coded with more than 1 byte</span><br><span>     if bytelist[i+1] & 0x80 > 0:</span><br><span>         Len_num = bytelist[i+1] - 0x80</span><br><span>@@ -196,14 +196,14 @@</span><br><span> def BERTLV_parser(bytelist):</span><br><span>     '''</span><br><span>     BERTLV_parser([0xAA, ..., 0xFF]) -> [([T], L, [V]), ([T], L, [V]), ...]</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     loops on the input bytes with the "first_BERTLV_parser()" function</span><br><span>     returns a list of 3-Tuples containing BERTLV records</span><br><span>     '''</span><br><span>     ret = []</span><br><span>     while len(bytelist) > 0:</span><br><span>         T, L, V = first_BERTLV_parser(bytelist)</span><br><span style="color: hsl(0, 100%, 40%);">-        #if T == 0xFF: </span><br><span style="color: hsl(120, 100%, 40%);">+        #if T == 0xFF:</span><br><span>         #    break # padding bytes</span><br><span>         ret.append( (T[1:], L[1], V) )</span><br><span>         # need to manage lengths of Tag and Length</span><br><span>@@ -213,14 +213,14 @@</span><br><span> def decode_BCD(data=[]):</span><br><span>     '''</span><br><span>     decode_BCD([0x21, 0xFE, 0xA3]) -> '121415310'</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     to decode serial number (IMSI, ICCID...) from list of bytes</span><br><span>     '''</span><br><span>     string = ''</span><br><span>     for B in data:</span><br><span>         string += str( B & 0x0F )</span><br><span>         string += str( B >> 4 )</span><br><span style="color: hsl(0, 100%, 40%);">-    return string </span><br><span style="color: hsl(120, 100%, 40%);">+    return string</span><br><span> </span><br><span> </span><br><span> #######################################################</span><br><span>@@ -230,10 +230,10 @@</span><br><span>     '''</span><br><span>     input / output wrapping class</span><br><span>     for APDU communications</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     allows to keep track of communications</span><br><span>     and exchanged commands</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     based on the python "deque" fifo-like object</span><br><span>     '''</span><br><span> </span><br><span>@@ -242,13 +242,13 @@</span><br><span>         initializes apdu_stack with the maximum of IO to keep track of</span><br><span>         '''</span><br><span>         self.apdu_stack  = deque([], limit)</span><br><span style="color: hsl(0, 100%, 40%);">-        </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def push(self, apdu_response):</span><br><span>         '''</span><br><span>         stacks the returned response into the apdu_stack</span><br><span>         '''</span><br><span>         self.apdu_stack.append( apdu_response )</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def __repr__(self):</span><br><span>         '''</span><br><span>         represents the whole stack of responses pushed on</span><br><span>@@ -257,10 +257,9 @@</span><br><span>         for apdu in self.apdu_stack:</span><br><span>             s += apdu.__repr__() + '\n'</span><br><span>         return s</span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def __call__(self):</span><br><span>         '''</span><br><span>         calling the apdu_stack returns the last response pushed on it</span><br><span>         '''</span><br><span>         return self.apdu_stack[-1]</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sim-auth/+/20909">change 20909</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-sim-auth/+/20909"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-sim-auth </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ie8a5fc47775fe7d7fe0e19f7378ffda104fa6112 </div>
<div style="display:none"> Gerrit-Change-Number: 20909 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Ludovic Rousseau <ludovic.rousseau+osmocom@free.fr> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>