Change in osmo-sim-auth[master]: pycodestyle: remove extra space characters

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Ludovic Rousseau gerrit-no-reply at lists.osmocom.org
Sun Oct 25 13:36:57 UTC 2020


Ludovic Rousseau has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-sim-auth/+/20909 )


Change subject: pycodestyle: remove extra space characters
......................................................................

pycodestyle: remove extra space characters

ICC.py:707:1: W293 blank line contains whitespace
ICC.py:715:57: W291 trailing whitespace
etc.

Change-Id: Ie8a5fc47775fe7d7fe0e19f7378ffda104fa6112
---
M card/ICC.py
M card/SIM.py
M card/USIM.py
M card/utils.py
4 files changed, 390 insertions(+), 395 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-sim-auth refs/changes/09/20909/1

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

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-sim-auth/+/20909
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-sim-auth
Gerrit-Branch: master
Gerrit-Change-Id: Ie8a5fc47775fe7d7fe0e19f7378ffda104fa6112
Gerrit-Change-Number: 20909
Gerrit-PatchSet: 1
Gerrit-Owner: Ludovic Rousseau <ludovic.rousseau+osmocom at free.fr>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201025/d9ffd25a/attachment.htm>


More information about the gerrit-log mailing list