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) 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, }