#!/usr/bin/env python # # CCC Event HLR management common stuff # # # Copyright (C) 2010 Sylvain Munaut # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import hashlib import os import random from collections import namedtuple try: import json except Importerror: # Python < 2.5 import simplejson as json # # Various helpers # def isnum(s, l=-1): return s.isdigit() and ((l== -1) or (len(s) == l)) # # Storage tuples # CardParameters = namedtuple("CardParameters", "num iccid imsi ki") NetworkParameters = namedtuple("NetworkParameters", "name cc mcc mnc smsp") # # State management # class StateManager(object): def __init__(self, filename=None, options=None): # Filename for state storage self._filename = filename # Params from options self._net_name = options.name if options else None self._net_cc = options.country if options else None self._net_mcc = options.mcc if options else None self._net_mnc = options.mnc if options else None self._net_smsp = options.smsp if options else None self._secret = options.secret if options else None # Default self._num_gen = 0 self._num_write = 0 def load(self): # Skip if no state file if self._filename is None: return # Skip if doesn't exist yet if not os.path.isfile(self._filename): return # Read fh = open(self._filename, 'r') data = fh.read() fh.close() # Decode json and merge dd = json.loads(data) self._net_name = dd['name'] self._net_cc = dd['cc'] self._net_mcc = dd['mcc'] self._net_mnc = dd['mnc'] self._net_smsp = dd['smsp'] self._secret = dd['secret'] self._num_gen = dd['num_gen'] self._num_write = dd['num_write'] def save(self): # Skip if no state file if self._filename is None: return # Serialize data = json.dumps({ 'name': self._net_name, 'cc': self._net_cc, 'mcc': self._net_mcc, 'mnc': self._net_mnc, 'smsp': self._net_smsp, 'secret': self._secret, 'num_gen': self._num_gen, 'num_write': self._num_write, }) # Save in json fh = open(self._filename, 'w') fh.write(data) fh.close() @property def network(self): return NetworkParameters( self._net_name, self._net_cc, self._net_mcc, self._net_mnc, self._net_smsp, ) def get_secret(self): return self._secret def next_gen_num(self): n = self._num_gen self._num_gen += 1 return n def next_write_num(self): n = self._num_write self._num_write += 1 return n # # Card parameters generation # class CardParametersGenerator(object): def __init__(self, cc, mcc, mnc, secret): # Digitize country code (2 or 3 digits) self._cc_digits = ('%03d' if cc > 100 else '%02d') % cc # Digitize MCC/MNC (5 or 6 digits) self._plmn_digits = ('%03d%03d' if mnc > 100 else '%03d%02d') % (mcc, mnc) # Store secret self._secret = secret def _digits(self, usage, len_, num): s = hashlib.sha1(self._secret + usage + '%d' % num) d = ''.join(['%02d'%ord(x) for x in s.digest()]) return d[0:len_] def _gen_iccid(self, num): iccid = ( '89' + # Common prefix (telecom) self._cc_digits + # Country Code on 2/3 digits self._plmn_digits # MCC/MNC on 5/6 digits ) ml = 20 - len(iccid) iccid += self._digits('ccid', ml, num) return iccid def _gen_imsi(self, num): ml = 15 - len(self._plmn_digits) msin = self._digits('imsi', ml, num) return ( self._plmn_digits + # MCC/MNC on 5/6 digits msin # MSIN ) def _gen_ki(self): return ''.join(['%02x' % random.randrange(0,256) for i in range(16)]) def generate(self, num): return CardParameters( num, self._gen_iccid(num), self._gen_imsi(num), self._gen_ki(), )