def change_chv(self, chv_no: int, pin_code: str, new_pin_code: str): """Change a given CHV (Card Holder Verification == PIN)""" fc = rpad(b2h(pin_code), 16) + rpad(b2h(new_pin_code), 16) data, sw = self._tp.send_apdu(self.cla_byte + '2400' + ('%02X' % chv_no) + '10' + fc) self._chv_process_sw('change', chv_no, pin_code, sw) return (data, sw)
def unblock_chv(self, chv_no: int, puk_code: str, pin_code: str): """Unblock a given CHV (Card Holder Verification == PIN)""" fc = rpad(b2h(puk_code), 16) + rpad(b2h(pin_code), 16) data, sw = self._tp.send_apdu(self.cla_byte + '2C00' + ('%02X' % chv_no) + '10' + fc) self._chv_process_sw('unblock', chv_no, pin_code, sw) return (data, sw)
def program(self, p): # Go to dir self._scc.select_file(['3f00', '7f4d']) # Home PLMN in PLMN_Sel format hplmn = enc_plmn(p['mcc'], p['mnc']) # Operator name ( 3f00/7f4d/8f0c ) self._scc.update_record(self._files['name'][0], 2, rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01' ) # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d ) v = '' # inline Ki if self._ki_file is None: v += p['ki'] # ICCID v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid']) # IMSI v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi']) # Ki if self._ki_file: v += self._ki_file + '10' + p['ki'] # PLMN_Sel v+= '6f30' + '18' + rpad(hplmn, 36) # ACC # This doesn't work with "fake" SuperSIM cards, # but will hopefully work with real SuperSIMs. if p.get('acc') is not None: v+= '6f78' + '02' + lpad(p['acc'], 4) self._scc.update_record(self._files['b_ef'][0], 1, rpad(v, self._files['b_ef'][1]*2) ) # SMSP ( 3f00/7f4d/8f0e ) # FIXME # Write PLMN_Sel forcefully as well r = self._scc.select_file(['3f00', '7f20', '6f30']) tl = int(r[-1][4:8], 16) hplmn = enc_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
def set_phonebook(slot, name, number, capability='ff'): num_records = sc.record_count(['3f00','7f10','6f3a']) record_size = sc.record_size(['3f00','7f10','6f3a']) record_num = int(slot) if (record_num < 1) or (record_num > num_records): raise RuntimeError("Invalid phonebook record number") encoded_name = rpad(b2h(name), (record_size - 14) * 2) if len(encoded_name) > ((record_size - 14) * 2): raise RuntimeError("Name is longer than %s bytes" % ((record_size-14))) if len(number) > 20: raise RuntimeError("Number is too long") encoded_number = swap_nibbles(rpad(number, 20)) record = encoded_name + ('%02x' % len(number)) + capability + encoded_number + 'ffff' sc.update_record(['3f00','7f10','6f3a'], record_num, record)
def update_record(self, ef, rec_no:int, data:str, force_len:bool=False, verify:bool=False, conserve:bool=False): res = self.select_path(ef) if force_len: # enforce the record length by the actual length of the given data input rec_length = len(data) // 2 else: # determine the record length from the select response of the file and pad # the input data with 0xFF if necessary. In cases where the input data # exceed we throw an exception. rec_length = self.__record_len(res) if (len(data) // 2 > rec_length): raise ValueError('Data length exceeds record length (expected max %d, got %d)' % (rec_length, len(data) // 2)) elif (len(data) // 2 < rec_length): data = rpad(data, rec_length * 2) # Save write cycles by reading+comparing before write if conserve: data_current, sw = self.read_record(ef, rec_no) data_current = data_current[0:rec_length*2] if data_current == data: return None, sw pdu = (self.cla_byte + 'dc%02x04%02x' % (rec_no, rec_length)) + data res = self._tp.send_apdu_checksw(pdu) if verify: self.verify_record(ef, rec_no, data) return res
def enable_chv(self, chv_no: int, pin_code: str): """Enable a given CHV (Card Holder Verification == PIN)""" fc = rpad(b2h(pin_code), 16) data, sw = self._tp.send_apdu(self.cla_byte + '2800' + ('%02X' % chv_no) + '08' + fc) self._chv_process_sw('enable', chv_no, pin_code, sw) return (data, sw)
def verify_chv(self, chv_no: int, code: str): """Verify a given CHV (Card Holder Verification == PIN)""" fc = rpad(b2h(code), 16) data, sw = self._tp.send_apdu(self.cla_byte + '2000' + ('%02X' % chv_no) + '08' + fc) self._chv_process_sw('verify', chv_no, code, sw) return (data, sw)
def read_params_csv(opts, imsi=None, iccid=None): row = _read_params_csv(opts, iccid=iccid, imsi=imsi) if row is not None: row['mcc'] = row.get('mcc', mcc_from_imsi(row.get('imsi'))) row['mnc'] = row.get('mnc', mnc_from_imsi(row.get('imsi'))) pin_adm = None # We need to escape the pin_adm we get from the csv if 'pin_adm' in row: pin_adm = ''.join(['%02x' % (ord(x)) for x in row['pin_adm']]) # Stay compatible to the odoo csv format elif 'adm1' in row: pin_adm = ''.join(['%02x' % (ord(x)) for x in row['adm1']]) if pin_adm: row['pin_adm'] = rpad(pin_adm, 16) # If the CSV-File defines a pin_adm_hex field use this field to # generate pin_adm from that. pin_adm_hex = row.get('pin_adm_hex') if pin_adm_hex: if len(pin_adm_hex) == 16: row['pin_adm'] = pin_adm_hex # Ensure that it's hex-encoded try: try_encode = h2b(pin_adm) except ValueError: raise ValueError( "pin_adm_hex needs to be hex encoded using this option" ) else: raise ValueError( "pin_adm_hex needs to be exactly 16 digits (hex encoded)") return row
def program(self, p): # Go to dir self._scc.select_file(['3f00', '7f4d']) # Home PLMN in PLMN_Sel format hplmn = self._e_plmn(p['mcc'], p['mnc']) # Operator name ( 3f00/7f4d/8f0c ) self._scc.update_record(self._files['name'][0], 2, rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01' ) # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d ) v = '' # inline Ki if self._ki_file is None: v += p['ki'] # ICCID v += '3f00' + '2fe2' + '0a' + self._e_iccid(p['iccid']) # IMSI v += '7f20' + '6f07' + '09' + self._e_imsi(p['imsi']) # Ki if self._ki_file: v += self._ki_file + '10' + p['ki'] # PLMN_Sel v+= '6f30' + '18' + rpad(hplmn, 36) self._scc.update_record(self._files['b_ef'][0], 1, rpad(v, self._files['b_ef'][1]*2) ) # SMSP ( 3f00/7f4d/8f0e ) # FIXME # Write PLMN_Sel forcefully as well r = self._scc.select_file(['3f00', '7f20', '6f30']) tl = int(r[-1][4:8], 16) hplmn = self._e_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
def verify_chv(self, chv_no, code): fc = rpad(b2h(code), 16) data, sw = self._tp.send_apdu(self.cla_byte + '2000' + ('%02X' % chv_no) + '08' + fc) if (sw != '9000'): raise RuntimeError( 'Failed to authenticate with ADM key %s, %i tries left.' % (code, int(sw[3]))) return (data, sw)
def program(self, p): # Go to dir self._scc.select_file(['3f00', '7f4d']) # Home PLMN in PLMN_Sel format hplmn = self._e_plmn(p['mcc'], p['mnc']) # Operator name ( 3f00/7f4d/8f0c ) self._scc.update_record( self._files['name'][0], 2, rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01') # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d ) v = '' # inline Ki if self._ki_file is None: v += p['ki'] # ICCID v += '3f00' + '2fe2' + '0a' + self._e_iccid(p['iccid']) # IMSI v += '7f20' + '6f07' + '09' + self._e_imsi(p['imsi']) # Ki if self._ki_file: v += self._ki_file + '10' + p['ki'] # PLMN_Sel v += '6f30' + '18' + rpad(hplmn, 36) self._scc.update_record(self._files['b_ef'][0], 1, rpad(v, self._files['b_ef'][1] * 2)) # SMSP ( 3f00/7f4d/8f0e ) # FIXME # Write PLMN_Sel forcefully as well r = self._scc.select_file(['3f00', '7f20', '6f30']) tl = int(r[-1][4:8], 16) hplmn = self._e_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (tl - 3))
def read_params_csv(opts, imsi=None, iccid=None): row = _read_params_csv(opts, iccid=iccid, imsi=imsi) if row is not None: row['mcc'] = int(row.get('mcc', row['imsi'][0:3])) row['mnc'] = int(row.get('mnc', row['imsi'][3:5])) pin_adm = None # We need to escape the pin_adm we get from the csv if 'pin_adm' in row: pin_adm = ''.join(['%02x'%(ord(x)) for x in row['pin_adm']]) # Stay compatible to the odoo csv format elif 'adm1' in row: pin_adm = ''.join(['%02x'%(ord(x)) for x in row['adm1']]) if pin_adm: row['pin_adm'] = rpad(pin_adm, 16) return row
def program(self, p): # Home PLMN r = self._scc.select_file(['3f00', '7f20', '6f30']) tl = int(r[-1][4:8], 16) hplmn = self._e_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (tl - 3)) # Get total number of entries and entry size rec_cnt, rec_len = self._get_infos() # Set first entry entry = ( '81' + # 1b Status: Valid & Active rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name self._e_iccid(p['iccid']) + # 10b ICCID self._e_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI p['ki'] + # 16b Ki lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed) ) self._scc.update_record('000c', 1, entry)
def program(self, p): # Home PLMN r = self._scc.select_file(['3f00', '7f20', '6f30']) tl = int(r[-1][4:8], 16) hplmn = self._e_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3)) # Get total number of entries and entry size rec_cnt, rec_len = self._get_infos() # Set first entry entry = ( '81' + # 1b Status: Valid & Active rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name self._e_iccid(p['iccid']) + # 10b ICCID self._e_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI p['ki'] + # 16b Ki lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed) ) self._scc.update_record('000c', 1, entry)
def verify_chv(self, chv_no, code): fc = rpad(b2h(code), 16) return self._tp.send_apdu_checksw(self.cla_byte + '2000' + ('%02X' % chv_no) + '08' + fc)
def _e_iccid(self, iccid): return swap_nibbles(rpad(iccid, 20))
sl.send_apdu_checksw('0026000108' + args.disable_pin.encode("hex") + 'ff' * (8 - len(args.disable_pin))) if args.dump_phonebook: num_records = sc.record_count(['3f00', '7f10', '6f3a']) print("Phonebook: %d records available" % num_records) for record_id in range(1, num_records + 1): print sc.read_record(['3f00', '7f10', '6f3a'], record_id) if args.set_phonebook_entry: num_records = sc.record_count(['3f00', '7f10', '6f3a']) record_size = sc.record_size(['3f00', '7f10', '6f3a']) record_num = int(args.set_phonebook_entry[0]) if (record_num < 1) or (record_num > num_records): raise RuntimeError("Invalid phonebook record number") encoded_name = rpad(b2h(args.set_phonebook_entry[1]), (record_size - 14) * 2) if len(encoded_name) > ((record_size - 14) * 2): raise RuntimeError("Name is too long") if len(args.set_phonebook_entry[2]) > 20: raise RuntimeError("Number is too long") encoded_number = swap_nibbles(rpad(args.set_phonebook_entry[2], 20)) record = encoded_name + ( '%02x' % len(args.set_phonebook_entry[2]) ) + args.set_phonebook_entry[3] + encoded_number + 'ffff' sc.update_record(['3f00', '7f10', '6f3a'], record_num, record) if args.list_applets: (data, status) = ac.send_wrapped_apdu_ram('80f21000024f0000c0000000') while status == '6310': (partData, status) = ac.send_wrapped_apdu_ram('80f21001024f0000c0000000')
def gen_parameters(opts): """Generates Name, ICCID, MCC, MNC, IMSI, SMSP, Ki, PIN-ADM from the options given by the user""" # MCC/MNC mcc = opts.mcc mnc = opts.mnc if not mcc.isdigit() or not mnc.isdigit(): raise ValueError('mcc & mnc must only contain decimal digits') if len(mcc) < 1 or len(mcc) > 3: raise ValueError('mcc must be between 1 .. 3 digits') if len(mnc) < 1 or len(mnc) > 3: raise ValueError('mnc must be between 1 .. 3 digits') # MCC always has 3 digits mcc = lpad(mcc, 3, "0") # MNC must be at least 2 digits mnc = lpad(mnc, 2, "0") # Digitize country code (2 or 3 digits) cc_digits = _cc_digits(opts.country) # Digitize MCC/MNC (5 or 6 digits) plmn_digits = _mcc_mnc_digits(mcc, mnc) if opts.name is not None: if len(opts.name) > 16: raise ValueError('Service Provider Name must max 16 characters!') if opts.msisdn is not None: msisdn = opts.msisdn if msisdn[0] == '+': msisdn = msisdn[1:] if not msisdn.isdigit(): raise ValueError('MSISDN must be digits only! ' 'Start with \'+\' for international numbers.') if len(msisdn) > 10 * 2: # TODO: Support MSISDN of length > 20 (10 Bytes) raise ValueError( 'MSISDNs longer than 20 digits are not (yet) supported.') # ICCID (19 digits, E.118), though some phase1 vendors use 20 :( if opts.iccid is not None: iccid = opts.iccid if not _isnum(iccid, 19) and not _isnum(iccid, 20): raise ValueError('ICCID must be 19 or 20 digits !') else: if opts.num is None: raise ValueError('Neither ICCID nor card number specified !') iccid = ( '89' + # Common prefix (telecom) cc_digits + # Country Code on 2/3 digits plmn_digits # MCC/MNC on 5/6 digits ) ml = 18 - len(iccid) if opts.secret is None: # The raw number iccid += ('%%0%dd' % ml) % opts.num else: # Randomized digits iccid += _digits(opts.secret, 'ccid', ml, opts.num) # Add checksum digit iccid += ('%1d' % calculate_luhn(iccid)) # IMSI (15 digits usually) if opts.imsi is not None: imsi = opts.imsi if not _isnum(imsi): raise ValueError('IMSI must be digits only !') else: if opts.num is None: raise ValueError('Neither IMSI nor card number specified !') ml = 15 - len(plmn_digits) if opts.secret is None: # The raw number msin = ('%%0%dd' % ml) % opts.num else: # Randomized digits msin = _digits(opts.secret, 'imsi', ml, opts.num) imsi = ( plmn_digits + # MCC/MNC on 5/6 digits msin # MSIN ) # SMSP if opts.smsp is not None: smsp = opts.smsp if not _ishex(smsp): raise ValueError('SMSP must be hex digits only !') if len(smsp) < 28 * 2: raise ValueError('SMSP must be at least 28 bytes') else: ton = "81" if opts.smsc is not None: smsc = opts.smsc if smsc[0] == '+': ton = "91" smsc = smsc[1:] if not _isnum(smsc): raise ValueError('SMSC must be digits only!\n \ Start with \'+\' for international numbers') else: smsc = '00%d' % opts.country + '5555' # Hack ... smsc = '%02d' % ( (len(smsc) + 3) // 2, ) + ton + swap_nibbles(rpad(smsc, 20)) smsp = ( 'e1' + # Parameters indicator 'ff' * 12 + # TP-Destination address smsc + # TP-Service Centre Address '00' + # TP-Protocol identifier '00' + # TP-Data coding scheme '00' # TP-Validity period ) # ACC if opts.acc is not None: acc = opts.acc if not _ishex(acc): raise ValueError('ACC must be hex digits only !') if len(acc) != 2 * 2: raise ValueError('ACC must be exactly 2 bytes') else: acc = None # Ki (random) if opts.ki is not None: ki = opts.ki if not re.match('^[0-9a-fA-F]{32}$', ki): raise ValueError('Ki needs to be 128 bits, in hex format') else: ki = ''.join(['%02x' % random.randrange(0, 256) for i in range(16)]) # OPC (random) if opts.opc is not None: opc = opts.opc if not re.match('^[0-9a-fA-F]{32}$', opc): raise ValueError('OPC needs to be 128 bits, in hex format') elif opts.op is not None: opc = derive_milenage_opc(ki, opts.op) else: opc = ''.join(['%02x' % random.randrange(0, 256) for i in range(16)]) pin_adm = sanitize_pin_adm(opts.pin_adm, opts.pin_adm_hex) # ePDG Selection Information if opts.epdgSelection: if len(opts.epdgSelection) < 5 or len(opts.epdgSelection) > 6: raise ValueError('ePDG Selection Information is not valid') epdg_mcc = opts.epdgSelection[:3] epdg_mnc = opts.epdgSelection[3:] if not epdg_mcc.isdigit() or not epdg_mnc.isdigit(): raise ValueError( 'PLMN for ePDG Selection must only contain decimal digits') # Return that return { 'name': opts.name, 'iccid': iccid, 'mcc': mcc, 'mnc': mnc, 'imsi': imsi, 'smsp': smsp, 'ki': ki, 'opc': opc, 'acc': acc, 'pin_adm': pin_adm, 'msisdn': opts.msisdn, 'epdgid': opts.epdgid, 'epdgSelection': opts.epdgSelection, 'pcscf': opts.pcscf, 'ims_hdomain': opts.ims_hdomain, 'impi': opts.impi, 'impu': opts.impu, 'opmode': opts.opmode, }
def gen_parameters(opts): """Generates Name, ICCID, MCC, MNC, IMSI, SMSP, Ki, PIN-ADM from the options given by the user""" # MCC/MNC mcc = opts.mcc mnc = opts.mnc if not ((0 < mcc < 999) and (0 < mnc < 999)): raise ValueError('mcc & mnc must be between 0 and 999') # Digitize country code (2 or 3 digits) cc_digits = _cc_digits(opts.country) # Digitize MCC/MNC (5 or 6 digits) plmn_digits = _mcc_mnc_digits(mcc, mnc) # ICCID (19 digits, E.118), though some phase1 vendors use 20 :( if opts.iccid is not None: iccid = opts.iccid if not _isnum(iccid, 19): raise ValueError('ICCID must be 19 digits !'); else: if opts.num is None: raise ValueError('Neither ICCID nor card number specified !') iccid = ( '89' + # Common prefix (telecom) cc_digits + # Country Code on 2/3 digits plmn_digits # MCC/MNC on 5/6 digits ) ml = 18 - len(iccid) if opts.secret is None: # The raw number iccid += ('%%0%dd' % ml) % opts.num else: # Randomized digits iccid += _digits(opts.secret, 'ccid', ml, opts.num) # Add checksum digit iccid += ('%1d' % calculate_luhn(iccid)) # IMSI (15 digits usually) if opts.imsi is not None: imsi = opts.imsi if not _isnum(imsi): raise ValueError('IMSI must be digits only !') else: if opts.num is None: raise ValueError('Neither IMSI nor card number specified !') ml = 15 - len(plmn_digits) if opts.secret is None: # The raw number msin = ('%%0%dd' % ml) % opts.num else: # Randomized digits msin = _digits(opts.secret, 'imsi', ml, opts.num) imsi = ( plmn_digits + # MCC/MNC on 5/6 digits msin # MSIN ) # SMSP if opts.smsp is not None: smsp = opts.smsp if not _ishex(smsp): raise ValueError('SMSP must be hex digits only !') if len(smsp) < 28*2: raise ValueError('SMSP must be at least 28 bytes') else: if opts.smsc is not None: smsc = opts.smsc if not _isnum(smsc): raise ValueError('SMSC must be digits only !') else: smsc = '00%d' % opts.country + '5555' # Hack ... smsc = '%02d' % ((len(smsc) + 3)//2,) + "81" + swap_nibbles(rpad(smsc, 20)) smsp = ( 'e1' + # Parameters indicator 'ff' * 12 + # TP-Destination address smsc + # TP-Service Centre Address '00' + # TP-Protocol identifier '00' + # TP-Data coding scheme '00' # TP-Validity period ) # ACC if opts.acc is not None: acc = opts.acc if not _ishex(acc): raise ValueError('ACC must be hex digits only !') if len(acc) != 2*2: raise ValueError('ACC must be exactly 2 bytes') else: acc = None # Ki (random) if opts.ki is not None: ki = opts.ki if not re.match('^[0-9a-fA-F]{32}$', ki): raise ValueError('Ki needs to be 128 bits, in hex format') else: ki = ''.join(['%02x' % random.randrange(0,256) for i in range(16)]) # Ki (random) if opts.opc is not None: opc = opts.opc if not re.match('^[0-9a-fA-F]{32}$', opc): raise ValueError('OPC needs to be 128 bits, in hex format') elif opts.op is not None: opc = derive_milenage_opc(ki, opts.op) else: opc = ''.join(['%02x' % random.randrange(0,256) for i in range(16)]) if opts.pin_adm is not None: if len(opts.pin_adm) > 8: raise ValueError("PIN-ADM needs to be <=8 digits") pin_adm = ''.join(['%02x'%(ord(x)) for x in opts.pin_adm]) pin_adm = rpad(pin_adm, 16) else: pin_adm = None # Return that return { 'name' : opts.name, 'iccid' : iccid, 'mcc' : mcc, 'mnc' : mnc, 'imsi' : imsi, 'smsp' : smsp, 'ki' : ki, 'opc' : opc, 'acc' : acc, 'pin_adm' : pin_adm, }
def gen_parameters(opts): """Generates Name, ICCID, MCC, MNC, IMSI, SMSP, Ki, PIN-ADM from the options given by the user""" # MCC/MNC mcc = opts.mcc mnc = opts.mnc if not ((0 < mcc < 999) and (0 < mnc < 999)): raise ValueError('mcc & mnc must be between 0 and 999') # Digitize country code (2 or 3 digits) cc_digits = _cc_digits(opts.country) # Digitize MCC/MNC (5 or 6 digits) plmn_digits = _mcc_mnc_digits(mcc, mnc) # ICCID (19 digits, E.118), though some phase1 vendors use 20 :( if opts.iccid is not None: iccid = opts.iccid if not _isnum(iccid, 19) and not _isnum(iccid, 20): raise ValueError('ICCID must be 19 or 20 digits !') else: if opts.num is None: raise ValueError('Neither ICCID nor card number specified !') iccid = ( '89' + # Common prefix (telecom) cc_digits + # Country Code on 2/3 digits plmn_digits # MCC/MNC on 5/6 digits ) ml = 18 - len(iccid) if opts.secret is None: # The raw number iccid += ('%%0%dd' % ml) % opts.num else: # Randomized digits iccid += _digits(opts.secret, 'ccid', ml, opts.num) # Add checksum digit iccid += ('%1d' % calculate_luhn(iccid)) # IMSI (15 digits usually) if opts.imsi is not None: imsi = opts.imsi if not _isnum(imsi): raise ValueError('IMSI must be digits only !') else: if opts.num is None: raise ValueError('Neither IMSI nor card number specified !') ml = 15 - len(plmn_digits) if opts.secret is None: # The raw number msin = ('%%0%dd' % ml) % opts.num else: # Randomized digits msin = _digits(opts.secret, 'imsi', ml, opts.num) imsi = ( plmn_digits + # MCC/MNC on 5/6 digits msin # MSIN ) # SMSP if opts.smsp is not None: smsp = opts.smsp if not _ishex(smsp): raise ValueError('SMSP must be hex digits only !') if len(smsp) < 28 * 2: raise ValueError('SMSP must be at least 28 bytes') else: if opts.smsc is not None: smsc = opts.smsc if not _isnum(smsc): raise ValueError('SMSC must be digits only !') else: smsc = '00%d' % opts.country + '5555' # Hack ... smsc = '%02d' % ( (len(smsc) + 3) // 2, ) + "81" + swap_nibbles(rpad(smsc, 20)) smsp = ( 'e1' + # Parameters indicator 'ff' * 12 + # TP-Destination address smsc + # TP-Service Centre Address '00' + # TP-Protocol identifier '00' + # TP-Data coding scheme '00' # TP-Validity period ) # ACC if opts.acc is not None: acc = opts.acc if not _ishex(acc): raise ValueError('ACC must be hex digits only !') if len(acc) != 2 * 2: raise ValueError('ACC must be exactly 2 bytes') else: acc = None # Ki (random) if opts.ki is not None: ki = opts.ki if not re.match('^[0-9a-fA-F]{32}$', ki): raise ValueError('Ki needs to be 128 bits, in hex format') else: ki = ''.join(['%02x' % random.randrange(0, 256) for i in range(16)]) # OPC (random) if opts.opc is not None: opc = opts.opc if not re.match('^[0-9a-fA-F]{32}$', opc): raise ValueError('OPC needs to be 128 bits, in hex format') elif opts.op is not None: opc = derive_milenage_opc(ki, opts.op) else: opc = ''.join(['%02x' % random.randrange(0, 256) for i in range(16)]) if opts.pin_adm is not None: if len(opts.pin_adm) <= 8: pin_adm = ''.join(['%02x' % (ord(x)) for x in opts.pin_adm]) pin_adm = rpad(pin_adm, 16) elif len(opts.pin_adm) == 16: pin_adm = opts.pin_adm else: raise ValueError( "PIN-ADM needs to be <=8 digits (ascii) or exactly 16 digits (raw hex)" ) else: pin_adm = None # Return that return { 'name': opts.name, 'iccid': iccid, 'mcc': mcc, 'mnc': mnc, 'imsi': imsi, 'smsp': smsp, 'ki': ki, 'opc': opc, 'acc': acc, 'pin_adm': pin_adm, }
if args.disable_pin: sl.send_apdu_checksw('0026000108' + args.disable_pin.encode("hex") + 'ff' * (8 - len(args.disable_pin))) if args.dump_phonebook: num_records = sc.record_count(['3f00','7f10','6f3a']) print ("Phonebook: %d records available" % num_records) for record_id in range(1, num_records + 1): print sc.read_record(['3f00','7f10','6f3a'], record_id) if args.set_phonebook_entry: num_records = sc.record_count(['3f00','7f10','6f3a']) record_size = sc.record_size(['3f00','7f10','6f3a']) record_num = int(args.set_phonebook_entry[0]) if (record_num < 1) or (record_num > num_records): raise RuntimeError("Invalid phonebook record number") encoded_name = rpad(b2h(args.set_phonebook_entry[1]), (record_size - 14) * 2) if len(encoded_name) > ((record_size - 14) * 2): raise RuntimeError("Name is too long") if len(args.set_phonebook_entry[2]) > 20: raise RuntimeError("Number is too long") encoded_number = swap_nibbles(rpad(args.set_phonebook_entry[2], 20)) record = encoded_name + ('%02x' % len(args.set_phonebook_entry[2])) + args.set_phonebook_entry[3] + encoded_number + 'ffff' sc.update_record(['3f00','7f10','6f3a'], record_num, record) if args.list_applets: (data, status) = ac.send_wrapped_apdu('80f21000024f0000c0000000') while status == '6310': (partData, status) = ac.send_wrapped_apdu('80f21001024f0000c0000000') data = data + partData while len(data) > 0: