def do_unblock_chv(self, opts): """Unblock PIN code using specified PUK code""" new_pin = self.get_code(opts.new_pin_code) puk = self.get_code(opts.puk_code) (data, sw) = self._cmd.card._scc.unblock_chv(opts.pin_nr, h2b(puk), h2b(new_pin)) self._cmd.poutput("CHV unblock successful")
def do_change_chv(self, opts): """Change PIN code to a new PIN code""" new_pin = self.get_code(opts.new_pin_code) pin = self.get_code(opts.pin_code) (data, sw) = self._cmd.card._scc.change_chv(opts.pin_nr, h2b(pin), h2b(new_pin)) self._cmd.poutput("CHV change successful")
def program(self, p): # select MF r = self._scc.select_file(['3f00']) # authenticate as SUPER ADM using default key self._scc.verify_chv(0x0b, h2b("3838383838383838")) # set ADM pin using proprietary command # INS: D4 # P1: 3A for PIN, 3B for PUK # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10) if p['pin_adm']: pin = p['pin_adm'] else: pin = h2b("4444444444444444") pdu = 'A0D43A0508' + b2h(pin) data, sw = self._scc._tp.send_apdu(pdu) # authenticate as ADM (enough to write file, and can set PINs) self._scc.verify_chv(0x05, pin) # write EF.ICCID data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid'])) # select DF_GSM r = self._scc.select_file(['7f20']) # write EF.IMSI data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi'])) # write EF.ACC if p.get('acc') is not None: data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4)) # get size and write EF.HPLMN r = self._scc.select_file(['6f30']) size = int(r[-1][4:8], 16) hplmn = enc_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (size-3)) # set COMP128 version 0 in proprietary file data, sw = self._scc.update_binary('0001', '001000') # set Ki in proprietary file data, sw = self._scc.update_binary('0001', p['ki'], 3) # select DF_TELECOM r = self._scc.select_file(['3f00', '7f10']) # write EF.SMSP data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
def program(self, p): # select MF r = self._scc.select_file(['3f00']) # authenticate as SUPER ADM using default key self._scc.verify_chv(0x0b, h2b("3838383838383838")) # set ADM pin using proprietary command # INS: D4 # P1: 3A for PIN, 3B for PUK # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10) if p['pin_adm']: pin = p['pin_adm'] else: pin = h2b("4444444444444444") pdu = 'A0D43A0508' + b2h(pin) data, sw = self._scc._tp.send_apdu(pdu) # authenticate as ADM (enough to write file, and can set PINs) self._scc.verify_chv(0x05, pin) # write EF.ICCID data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid'])) # select DF_GSM r = self._scc.select_file(['7f20']) # write EF.IMSI data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi'])) # write EF.ACC if p.get('acc') is not None: data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4)) # get size and write EF.HPLMN r = self._scc.select_file(['6f30']) size = int(r[-1][4:8], 16) hplmn = enc_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (size - 3)) # set COMP128 version 0 in proprietary file data, sw = self._scc.update_binary('0001', '001000') # set Ki in proprietary file data, sw = self._scc.update_binary('0001', p['ki'], 3) # select DF_TELECOM r = self._scc.select_file(['3f00', '7f10']) # write EF.SMSP data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
def derive_milenage_opc(ki_hex, op_hex): """ Run the milenage algorithm. """ from Crypto.Cipher import AES from Crypto.Util.strxor import strxor from pySim.utils import b2h # We pass in hex string and now need to work on bytes aes = AES.new(h2b(ki_hex)) opc_bytes = aes.encrypt(h2b(op_hex)) return b2h(strxor(opc_bytes, h2b(op_hex)))
def set_data(self, ef, tag: int, value: str, verify: bool = False, conserve: bool = False): """Execute SET DATA. Args ef : string or list of strings indicating name or path of transparent EF tag : BER-TLV Tag of value to be stored value : BER-TLV value to be stored """ r = self.select_path(ef) if len(r[-1]) == 0: return (None, None) # in case of deleting the data, we only have 'tag' but no 'value' if not value: return self._set_data('%02x' % tag, first=True) # FIXME: proper BER-TLV encode tl = '%02x%s' % (tag, b2h(bertlv_encode_len(len(value) // 2))) tlv = tl + value tlv_bin = h2b(tlv) first = True total_len = len(tlv_bin) remaining = tlv_bin while len(remaining) > 0: fragment = remaining[:255] rdata, sw = self._set_data(fragment, first=first) first = False remaining = remaining[255:] return rdata, sw
def program(self, p): # authenticate as ADM using default key (written on the card..) if not p['pin_adm']: raise ValueError("Please provide a PIN-ADM as there is no default one") self._scc.verify_chv(0x0A, h2b(p['pin_adm'])) # select MF r = self._scc.select_file(['3f00']) # write EF.ICCID data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid'])) # select DF_GSM r = self._scc.select_file(['7f20']) # set Ki in proprietary file data, sw = self._scc.update_binary('00FF', p['ki']) # set Ki in proprietary file content = "01" + p['opc'] data, sw = self._scc.update_binary('00F7', content) # write EF.IMSI data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
def write_parameters(opts, params): # CSV if opts.write_csv: import csv row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc'] f = open(opts.write_csv, 'a') cw = csv.writer(f) cw.writerow([params[x] for x in row]) f.close() # SQLite3 OpenBSC HLR if opts.write_hlr: import sqlite3 conn = sqlite3.connect(opts.write_hlr) c = conn.execute( 'INSERT INTO Subscriber ' + '(imsi, name, extension, authorized, created, updated) ' + 'VALUES ' + '(?,?,?,1,datetime(\'now\'),datetime(\'now\'));', [params['imsi'], params['name'], '9' + params['iccid'][-5:]], ) sub_id = c.lastrowid c.close() c = conn.execute( 'INSERT INTO AuthKeys ' + '(subscriber_id, algorithm_id, a3a8_ki)' + 'VALUES ' + '(?,?,?)', [sub_id, 2, sqlite3.Binary(_dbi_binary_quote(h2b(params['ki'])))], ) conn.commit() conn.close()
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 write_params_hlr(opts, params): # SQLite3 OpenBSC HLR if opts.write_hlr: import sqlite3 conn = sqlite3.connect(opts.write_hlr) c = conn.execute( 'INSERT INTO Subscriber ' + '(imsi, name, extension, authorized, created, updated) ' + 'VALUES ' + '(?,?,?,1,datetime(\'now\'),datetime(\'now\'));', [ params['imsi'], params['name'], '9' + params['iccid'][-5:-1] ], ) sub_id = c.lastrowid c.close() c = conn.execute( 'INSERT INTO AuthKeys ' + '(subscriber_id, algorithm_id, a3a8_ki)' + 'VALUES ' + '(?,?,?)', [ sub_id, 2, sqlite3.Binary(_dbi_binary_quote(h2b(params['ki']))) ], ) conn.commit() conn.close()
def send_apdu_raw(self, pdu): """see LinkBase.send_apdu_raw""" # Request FULL reset req_msg = L1CTLMessageSIM(h2b(pdu)) self.sock.send(req_msg.gen_msg()) # Read message length first rsp = self.wait_for_rsp(struct.calcsize("!H")) msg_len = struct.unpack_from("!H", rsp)[0] if msg_len < struct.calcsize("BBxx"): raise ReaderError("Missing L1CTL header for L1CTL_SIM_CONF") # Read the whole message then rsp = self.sock.recv(msg_len) # Verify L1CTL header hdr = struct.unpack_from("BBxx", rsp) if hdr[0] != L1CTLMessageSIM.L1CTL_SIM_CONF: raise ReaderError("Unexpected L1CTL message received") # Verify the payload length offset = struct.calcsize("BBxx") if len(rsp) <= offset: raise ProtocolError("Empty response from SIM?!?") # Omit L1CTL header rsp = rsp[offset:] # Unpack data and SW data = rsp[:-2] sw = rsp[-2:] return b2h(data), b2h(sw)
def program(self, p): # select MF r = self._scc.select_file(['3f00']) # select DF_GSM r = self._scc.select_file(['7f20']) # authenticate as ADM using default key (written on the card..) if not p['pin_adm']: raise ValueError("Please provide a PIN-ADM as there is no default one") self._scc.verify_chv(0x0A, h2b(p['pin_adm'])) # set Ki in proprietary file data, sw = self._scc.update_binary('00FF', p['ki']) # set Ki in proprietary file content = "01" + p['opc'] data, sw = self._scc.update_binary('00F7', content) # write EF.IMSI data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
def send_apdu_constr(self, cla, ins, p1, p2, cmd_constr, cmd_data, resp_constr): """Build and sends an APDU using a 'construct' definition; parses response. Args: cla : string (in hex) ISO 7816 class byte ins : string (in hex) ISO 7816 instruction byte p1 : string (in hex) ISO 7116 Parameter 1 byte p2 : string (in hex) ISO 7116 Parameter 2 byte cmd_cosntr : defining how to generate binary APDU command data cmd_data : command data passed to cmd_constr resp_cosntr : defining how to decode binary APDU response data Returns: Tuple of (decoded_data, sw) """ cmd = cmd_constr.build(cmd_data) if cmd_data else '' p3 = i2h([len(cmd)]) pdu = ''.join([cla, ins, p1, p2, p3, b2h(cmd)]) (data, sw) = self.send_apdu(pdu) if data: # filter the resulting dict to avoid '_io' members inside rsp = filter_dict(resp_constr.parse(h2b(data))) else: rsp = None return (rsp, sw)
def encode_record_bin(self, abstract_data): """Encode abstract representation into raw (binary) data. Overloaded by specific classes.""" method = getattr(self, '_encode_record_bin', None) if callable(method): return method(abstract_data) method = getattr(self, '_encode_record_hex', None) if callable(method): return h2b(method(abstract_data)) raise NotImplementedError
def decode_record_hex(self, raw_hex_data): """Decode raw (hex string) data into abstract representation. Overloaded by specific classes.""" method = getattr(self, '_decode_record_hex', None) if callable(method): return method(raw_hex_data) method = getattr(self, '_decode_record_bin', None) if callable(method): raw_bin_data = h2b(raw_hex_data) return method(raw_bin_data) return {'raw': raw_hex_data}
def send_apdu_raw(self, pdu): """see LinkBase.send_apdu_raw""" pdu = h2b(pdu) data_len = ord(pdu[4]) # P3 # Send first CLASS,INS,P1,P2,P3 self._tx_string(pdu[0:5]) # Wait ack which can be # - INS: Command acked -> go ahead # - 0x60: NULL, just wait some more # - SW1: The card can apparently proceed ... while True: b = self._rx_byte() if b == pdu[1]: break elif b != '\x60': # Ok, it 'could' be SW1 sw1 = b sw2 = self._rx_byte() nil = self._rx_byte() if (sw2 and not nil): return '', b2h(sw1 + sw2) raise ProtocolError() # Send data (if any) if len(pdu) > 5: self._tx_string(pdu[5:]) # Receive data (including SW !) # length = [P3 - tx_data (=len(pdu)-len(hdr)) + 2 (SW1/2) ] to_recv = data_len - len(pdu) + 5 + 2 data = '' while (len(data) < to_recv): b = self._rx_byte() if (to_recv == 2) and ( b == '\x60'): # Ignore NIL if we have no RX data (hack ?) continue if not b: break data += b # Split datafield from SW if len(data) < 2: return None, None sw = data[-2:] data = data[0:-2] # Return value return b2h(data), b2h(sw)
def send_apdu_raw(self, pdu): """see LinkBase.send_apdu_raw""" pdu = h2b(pdu) data_len = ord(pdu[4]) # P3 # Send first CLASS,INS,P1,P2,P3 self._tx_string(pdu[0:5]) # Wait ack which can be # - INS: Command acked -> go ahead # - 0x60: NULL, just wait some more # - SW1: The card can apparently proceed ... while True: b = self._rx_byte() if b == pdu[1]: break elif b != '\x60': # Ok, it 'could' be SW1 sw1 = b sw2 = self._rx_byte() nil = self._rx_byte() if (sw2 and not nil): return '', b2h(sw1+sw2) raise ProtocolError() # Send data (if any) if len(pdu) > 5: self._tx_string(pdu[5:]) # Receive data (including SW !) # length = [P3 - tx_data (=len(pdu)-len(hdr)) + 2 (SW1/2) ] to_recv = data_len - len(pdu) + 5 + 2 data = '' while (len(data) < to_recv): b = self._rx_byte() if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?) continue if not b: break; data += b # Split datafield from SW if len(data) < 2: return None, None sw = data[-2:] data = data[0:-2] # Return value return b2h(data), b2h(sw)
def program(self, p): # We don't really know yet what ADM PIN 4 is about #self._scc.verify_chv(4, h2b("4444444444444444")) # Authenticate using ADM PIN 5 if p['pin_adm']: pin = p['pin_adm'] else: pin = h2b("4444444444444444") self._scc.verify_chv(5, pin) # EF.ICCID r = self._scc.select_file(['3f00', '2fe2']) data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid'])) # EF.IMSI r = self._scc.select_file(['3f00', '7f20', '6f07']) data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi'])) # EF.ACC if p.get('acc') is not None: data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4)) # EF.SMSP r = self._scc.select_file(['3f00', '7f10', '6f42']) data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80)) # Set the Ki using proprietary command pdu = '80d4020010' + p['ki'] data, sw = self._scc._tp.send_apdu(pdu) # EF.HPLMN r = self._scc.select_file(['3f00', '7f20', '6f30']) size = int(r[-1][4:8], 16) hplmn = enc_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (size-3)) # EF.SPN (Service Provider Name) r = self._scc.select_file(['3f00', '7f20', '6f30']) size = int(r[-1][4:8], 16)
def program(self, p): # We don't really know yet what ADM PIN 4 is about #self._scc.verify_chv(4, h2b("4444444444444444")) # Authenticate using ADM PIN 5 if p['pin_adm']: pin = p['pin_adm'] else: pin = h2b("4444444444444444") self._scc.verify_chv(5, pin) # EF.ICCID r = self._scc.select_file(['3f00', '2fe2']) data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid'])) # EF.IMSI r = self._scc.select_file(['3f00', '7f20', '6f07']) data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi'])) # EF.ACC if p.get('acc') is not None: data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4)) # EF.SMSP r = self._scc.select_file(['3f00', '7f10', '6f42']) data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80)) # Set the Ki using proprietary command pdu = '80d4020010' + p['ki'] data, sw = self._scc._tp.send_apdu(pdu) # EF.HPLMN r = self._scc.select_file(['3f00', '7f20', '6f30']) size = int(r[-1][4:8], 16) hplmn = enc_plmn(p['mcc'], p['mnc']) self._scc.update_binary('6f30', hplmn + 'ff' * (size - 3)) # EF.SPN (Service Provider Name) r = self._scc.select_file(['3f00', '7f20', '6f30']) size = int(r[-1][4:8], 16)
def do_verify_adm(self, arg): """VERIFY the ADM1 PIN""" if arg: # use specified ADM-PIN pin_adm = sanitize_pin_adm(arg) else: # try to find an ADM-PIN if none is specified result = card_key_provider_get_field('ADM1', key='ICCID', value=self._cmd.iccid) pin_adm = sanitize_pin_adm(result) if pin_adm: self._cmd.poutput("found ADM-PIN '%s' for ICCID '%s'" % (result, self._cmd.iccid)) else: raise ValueError("cannot find ADM-PIN for ICCID '%s'" % (self._cmd.iccid)) if pin_adm: self._cmd.card.verify_adm(h2b(pin_adm)) else: raise ValueError("error: cannot authenticate, no adm-pin!")
def write_parameters(opts, params): # CSV if opts.write_csv: import csv row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc'] f = open(opts.write_csv, 'a') cw = csv.writer(f) cw.writerow([params[x] for x in row]) f.close() # SQLite3 OpenBSC HLR if opts.write_hlr: import sqlite3 conn = sqlite3.connect(opts.write_hlr) c = conn.execute( 'INSERT INTO Subscriber ' + '(imsi, name, extension, authorized, created, updated) ' + 'VALUES ' + '(?,?,?,1,datetime(\'now\'),datetime(\'now\'));', [ params['imsi'], params['name'], '9' + params['iccid'][-5:] ], ) sub_id = c.lastrowid c.close() c = conn.execute( 'INSERT INTO AuthKeys ' + '(subscriber_id, algorithm_id, a3a8_ki)' + 'VALUES ' + '(?,?,?)', [ sub_id, 2, sqlite3.Binary(_dbi_binary_quote(h2b(params['ki']))) ], ) conn.commit() conn.close()
card_handler = card_handler(sl) card = card_detect("auto", scc) if card is None: print("No card detected!") sys.exit(2) profile = CardProfileUICC() profile.add_application(ADF_USIM()) profile.add_application(ADF_ISIM()) rs = RuntimeState(card, profile) # FIXME: do this dynamically rs.mf.add_file(DF_TELECOM()) rs.mf.add_file(DF_GSM()) app = PysimApp(card, rs, opts.script) rs.select('MF', app) # If the user supplies an ADM PIN at via commandline args authenticate # immediatley so that the user does not have to use the shell commands pin_adm = sanitize_pin_adm(opts.pin_adm, opts.pin_adm_hex) if pin_adm: try: card.verify_adm(h2b(pin_adm)) except Exception as e: print(e) app.cmdloop()
def do_verify_adm(self, arg): """VERIFY the ADM1 PIN""" pin_adm = sanitize_pin_adm(arg) self.card.verify_adm(h2b(pin_adm))
def _encode(self, obj, context, path): return h2b(swap_nibbles(obj))
def _encode(self, obj, context, path): return h2b(obj)
# print "Testing RFM" # ac.test_rfm(False)#SIM # ac.test_rfm(True)#USIM # exit(0) if args.pin: print "Verify PIN1" data, sw = sc.verify_chv(1, args.pin) if sw == '9000': print "Passed - %s" % sw else: print "Failed - %s" % sw if args.adm: print "Verify ADM1" adm = args.adm if len(args.adm) <= 8 else h2b(args.adm) data, sw = sc.verify_chv(0x0A,adm) if sw == '9000': print "Passed - %s" % sw else: print "Failed - %s" % sw if args.delete_app: print "Delete applet" ac.delete_aid(args.delete_app) if args.load_app: print "Load applet" ac.load_app(args.load_app) if args.install:
def do_enable_chv(self, opts): """Enable PIN code using specified PIN code""" pin = self.get_code(opts.pin_code) (data, sw) = self._cmd.card._scc.enable_chv(opts.pin_nr, h2b(pin)) self._cmd.poutput("CHV enable successful")
def export(self, filename, context): """ Select and export a single file """ context['COUNT'] += 1 df = self._cmd.rs.selected_file if not isinstance(df, CardDF): raise RuntimeError( "currently selected file %s is not a DF or ADF" % str(df)) df_path_list = df.fully_qualified_path(True) df_path_list_fid = df.fully_qualified_path(False) file_str = '/'.join(df_path_list) + "/" + str(filename) self._cmd.poutput(boxed_heading_str(file_str)) self._cmd.poutput("# directory: %s (%s)" % ('/'.join(df_path_list), '/'.join(df_path_list_fid))) try: fcp_dec = self._cmd.rs.select(filename, self._cmd) self._cmd.poutput("# file: %s (%s)" % (self._cmd.rs.selected_file.name, self._cmd.rs.selected_file.fid)) fd = fcp_dec['file_descriptor'] structure = fd['structure'] self._cmd.poutput("# structure: %s" % str(structure)) for f in df_path_list: self._cmd.poutput("select " + str(f)) self._cmd.poutput("select " + self._cmd.rs.selected_file.name) if structure == 'transparent': result = self._cmd.rs.read_binary() self._cmd.poutput("update_binary " + str(result[0])) elif structure == 'cyclic' or structure == 'linear_fixed': num_of_rec = fd['num_of_rec'] for r in range(1, num_of_rec + 1): result = self._cmd.rs.read_record(r) self._cmd.poutput("update_record %d %s" % (r, str(result[0]))) elif structure == 'ber_tlv': tags = self._cmd.rs.retrieve_tags() for t in tags: result = self._cmd.rs.retrieve_data(t) (tag, l, val, remainer) = bertlv_parse_one(h2b(result[0])) self._cmd.poutput("set_data 0x%02x %s" % (t, b2h(val))) else: raise RuntimeError('Unsupported structure "%s" of file "%s"' % (structure, filename)) except Exception as e: bad_file_str = '/'.join(df_path_list) + "/" + str( filename) + ", " + str(e) self._cmd.poutput("# bad file: %s" % bad_file_str) context['ERR'] += 1 context['BAD'].append(bad_file_str) # When reading the file is done, make sure the parent file is # selected again. This will be the usual case, however we need # to check before since we must not select the same DF twice if df != self._cmd.rs.selected_file: self._cmd.rs.select(df.fid or df.aid, self._cmd) self._cmd.poutput("#")
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: 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 = None 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) else: raise ValueError("PIN-ADM needs to be <=8 digits (ascii)") if opts.pin_adm_hex is not None: if len(opts.pin_adm_hex) == 16: pin_adm = opts.pin_adm_hex # Ensure that it's hex-encoded try: try_encode = h2b(pin_adm) except ValueError: raise ValueError( "PIN-ADM needs to be hex encoded using this option") else: raise ValueError( "PIN-ADM needs to be exactly 16 digits (hex encoded)") # 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 do_verify_chv(self, opts): """Verify (authenticate) using specified PIN code""" pin = self.get_code(opts.pin_code) (data, sw) = self._cmd.card._scc.verify_chv(opts.pin_nr, h2b(pin)) self._cmd.poutput("CHV verification successful")