mirror of https://gerrit.osmocom.org/pysim
utils.py: Add more type annotations
Change-Id: I50a0a07132890af0817f4ff0ce9fec53b7512522
This commit is contained in:
parent
6e0458dda6
commit
522555710b
|
@ -3,7 +3,8 @@
|
|||
""" pySim: various utilities
|
||||
"""
|
||||
|
||||
#
|
||||
from typing import Optional, List, Dict, Any, Tuple
|
||||
|
||||
# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
@ -20,40 +21,42 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# just to differentiate strings of hex nibbles from everything else
|
||||
Hexstr = str
|
||||
|
||||
def h2b(s: str) -> bytearray:
|
||||
def h2b(s:Hexstr) -> bytearray:
|
||||
"""convert from a string of hex nibbles to a sequence of bytes"""
|
||||
return bytearray.fromhex(s)
|
||||
|
||||
def b2h(b: bytearray) -> str:
|
||||
def b2h(b:bytearray) -> Hexstr:
|
||||
"""convert from a sequence of bytes to a string of hex nibbles"""
|
||||
return ''.join(['%02x'%(x) for x in b])
|
||||
|
||||
def h2i(s:str):
|
||||
def h2i(s:Hexstr) -> List[int]:
|
||||
"""convert from a string of hex nibbles to a list of integers"""
|
||||
return [(int(x,16)<<4)+int(y,16) for x,y in zip(s[0::2], s[1::2])]
|
||||
|
||||
def i2h(s) -> str:
|
||||
def i2h(s:List[int]) -> Hexstr:
|
||||
"""convert from a list of integers to a string of hex nibbles"""
|
||||
return ''.join(['%02x'%(x) for x in s])
|
||||
|
||||
def h2s(s:str) -> str:
|
||||
def h2s(s:Hexstr) -> str:
|
||||
"""convert from a string of hex nibbles to an ASCII string"""
|
||||
return ''.join([chr((int(x,16)<<4)+int(y,16)) for x,y in zip(s[0::2], s[1::2])
|
||||
if int(x + y, 16) != 0xff])
|
||||
|
||||
def s2h(s:str) -> str:
|
||||
def s2h(s:str) -> Hexstr:
|
||||
"""convert from an ASCII string to a string of hex nibbles"""
|
||||
b = bytearray()
|
||||
b.extend(map(ord, s))
|
||||
return b2h(b)
|
||||
|
||||
# List of bytes to string
|
||||
def i2s(s) -> str:
|
||||
def i2s(s:List[int]) -> str:
|
||||
"""convert from a list of integers to an ASCII string"""
|
||||
return ''.join([chr(x) for x in s])
|
||||
|
||||
def swap_nibbles(s:str) -> str:
|
||||
def swap_nibbles(s:Hexstr) -> Hexstr:
|
||||
"""swap the nibbles in a hex string"""
|
||||
return ''.join([x+y for x,y in zip(s[1::2], s[0::2])])
|
||||
|
||||
|
@ -104,7 +107,7 @@ def enc_imsi(imsi:str):
|
|||
ei = '%02x' % l + swap_nibbles('%01x%s' % ((oe<<3)|1, rpad(imsi, 15)))
|
||||
return ei
|
||||
|
||||
def dec_imsi(ef):
|
||||
def dec_imsi(ef:Hexstr) -> Optional[str]:
|
||||
"""Converts an EF value to the imsi string representation"""
|
||||
if len(ef) < 4:
|
||||
return None
|
||||
|
@ -122,10 +125,10 @@ def dec_imsi(ef):
|
|||
imsi = swapped[1:]
|
||||
return imsi
|
||||
|
||||
def dec_iccid(ef):
|
||||
def dec_iccid(ef:Hexstr) -> str:
|
||||
return swap_nibbles(ef).strip('f')
|
||||
|
||||
def enc_iccid(iccid):
|
||||
def enc_iccid(iccid:str) -> Hexstr:
|
||||
return swap_nibbles(rpad(iccid, 20))
|
||||
|
||||
def enc_plmn(mcc, mnc):
|
||||
|
@ -151,7 +154,7 @@ def hexstr_to_Nbytearr(s, nbytes):
|
|||
return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2)) ]
|
||||
|
||||
# Accepts hex string representing three bytes
|
||||
def dec_mcc_from_plmn(plmn):
|
||||
def dec_mcc_from_plmn(plmn:Hexstr) -> int:
|
||||
ia = h2i(plmn)
|
||||
digit1 = ia[0] & 0x0F # 1st byte, LSB
|
||||
digit2 = (ia[0] & 0xF0) >> 4 # 1st byte, MSB
|
||||
|
@ -160,7 +163,7 @@ def dec_mcc_from_plmn(plmn):
|
|||
return 0xFFF # 4095
|
||||
return derive_mcc(digit1, digit2, digit3)
|
||||
|
||||
def dec_mnc_from_plmn(plmn):
|
||||
def dec_mnc_from_plmn(plmn:Hexstr) -> int:
|
||||
ia = h2i(plmn)
|
||||
digit1 = ia[2] & 0x0F # 3rd byte, LSB
|
||||
digit2 = (ia[2] & 0xF0) >> 4 # 3rd byte, MSB
|
||||
|
@ -169,7 +172,7 @@ def dec_mnc_from_plmn(plmn):
|
|||
return 0xFFF # 4095
|
||||
return derive_mnc(digit1, digit2, digit3)
|
||||
|
||||
def dec_act(twohexbytes):
|
||||
def dec_act(twohexbytes:Hexstr) -> List[str]:
|
||||
act_list = [
|
||||
{'bit': 15, 'name': "UTRAN"},
|
||||
{'bit': 14, 'name': "E-UTRAN"},
|
||||
|
@ -186,7 +189,7 @@ def dec_act(twohexbytes):
|
|||
sel.append(a['name'])
|
||||
return sel
|
||||
|
||||
def dec_xplmn_w_act(fivehexbytes):
|
||||
def dec_xplmn_w_act(fivehexbytes:Hexstr) -> Dict[str,Any]:
|
||||
res = {'mcc': 0, 'mnc': 0, 'act': []}
|
||||
plmn_chars = 6
|
||||
act_chars = 4
|
||||
|
@ -238,7 +241,7 @@ def dec_epsloci(hexstr):
|
|||
res['status'] = h2i(hexstr[34:36])
|
||||
return res
|
||||
|
||||
def dec_xplmn(threehexbytes):
|
||||
def dec_xplmn(threehexbytes:Hexstr) -> dict:
|
||||
res = {'mcc': 0, 'mnc': 0, 'act': []}
|
||||
plmn_chars = 6
|
||||
plmn_str = threehexbytes[:plmn_chars] # first three bytes (six ascii hex chars)
|
||||
|
@ -246,7 +249,7 @@ def dec_xplmn(threehexbytes):
|
|||
res['mnc'] = dec_mnc_from_plmn(plmn_str)
|
||||
return res
|
||||
|
||||
def format_xplmn(hexstr):
|
||||
def format_xplmn(hexstr:Hexstr) -> str:
|
||||
s = ""
|
||||
for rec_data in hexstr_to_Nbytearr(hexstr, 3):
|
||||
rec_info = dec_xplmn(rec_data)
|
||||
|
@ -257,7 +260,7 @@ def format_xplmn(hexstr):
|
|||
s += "\t%s # %s\n" % (rec_data, rec_str)
|
||||
return s
|
||||
|
||||
def derive_milenage_opc(ki_hex, op_hex):
|
||||
def derive_milenage_opc(ki_hex:Hexstr, op_hex:Hexstr) -> Hexstr:
|
||||
"""
|
||||
Run the milenage algorithm to calculate OPC from Ki and OP
|
||||
"""
|
||||
|
@ -272,7 +275,7 @@ def derive_milenage_opc(ki_hex, op_hex):
|
|||
opc_bytes = aes.encrypt(op_bytes)
|
||||
return b2h(strxor(opc_bytes, op_bytes))
|
||||
|
||||
def calculate_luhn(cc):
|
||||
def calculate_luhn(cc) -> int:
|
||||
"""
|
||||
Calculate Luhn checksum used in e.g. ICCID and IMEI
|
||||
"""
|
||||
|
@ -280,7 +283,7 @@ def calculate_luhn(cc):
|
|||
check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
|
||||
return 0 if check_digit == 10 else check_digit
|
||||
|
||||
def mcc_from_imsi(imsi):
|
||||
def mcc_from_imsi(imsi:str) -> Optional[str]:
|
||||
"""
|
||||
Derive the MCC (Mobile Country Code) from the first three digits of an IMSI
|
||||
"""
|
||||
|
@ -292,7 +295,7 @@ def mcc_from_imsi(imsi):
|
|||
else:
|
||||
return None
|
||||
|
||||
def mnc_from_imsi(imsi, long=False):
|
||||
def mnc_from_imsi(imsi:str, long:bool=False) -> Optional[str]:
|
||||
"""
|
||||
Derive the MNC (Mobile Country Code) from the 4th to 6th digit of an IMSI
|
||||
"""
|
||||
|
@ -307,7 +310,7 @@ def mnc_from_imsi(imsi, long=False):
|
|||
else:
|
||||
return None
|
||||
|
||||
def derive_mcc(digit1, digit2, digit3):
|
||||
def derive_mcc(digit1:int, digit2:int, digit3:int) -> int:
|
||||
"""
|
||||
Derive decimal representation of the MCC (Mobile Country Code)
|
||||
from three given digits.
|
||||
|
@ -324,7 +327,7 @@ def derive_mcc(digit1, digit2, digit3):
|
|||
|
||||
return mcc
|
||||
|
||||
def derive_mnc(digit1, digit2, digit3=0x0f):
|
||||
def derive_mnc(digit1:int, digit2:int, digit3:int=0x0f) -> int:
|
||||
"""
|
||||
Derive decimal representation of the MNC (Mobile Network Code)
|
||||
from two or (optionally) three given digits.
|
||||
|
@ -344,7 +347,7 @@ def derive_mnc(digit1, digit2, digit3=0x0f):
|
|||
|
||||
return mnc
|
||||
|
||||
def dec_msisdn(ef_msisdn):
|
||||
def dec_msisdn(ef_msisdn:Hexstr) -> Optional[Tuple[int,int,Optional[str]]]:
|
||||
"""
|
||||
Decode MSISDN from EF.MSISDN or EF.ADN (same structure).
|
||||
See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
|
||||
|
@ -385,7 +388,7 @@ def dec_msisdn(ef_msisdn):
|
|||
|
||||
return (npi, ton, msisdn)
|
||||
|
||||
def enc_msisdn(msisdn, npi=0x01, ton=0x03):
|
||||
def enc_msisdn(msisdn:str, npi:int=0x01, ton:int=0x03) -> Hexstr:
|
||||
"""
|
||||
Encode MSISDN as LHV so it can be stored to EF.MSISDN.
|
||||
See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
|
||||
|
@ -411,7 +414,7 @@ def enc_msisdn(msisdn, npi=0x01, ton=0x03):
|
|||
|
||||
return ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd
|
||||
|
||||
def dec_st(st, table="sim"):
|
||||
def dec_st(st, table="sim") -> str:
|
||||
"""
|
||||
Parses the EF S/U/IST and prints the list of available services in EF S/U/IST
|
||||
"""
|
||||
|
@ -599,7 +602,7 @@ def enc_addr_tlv(addr, addr_type='00'):
|
|||
|
||||
return s
|
||||
|
||||
def is_hex(string, minlen=2, maxlen=None) -> bool:
|
||||
def is_hex(string:str, minlen:int=2, maxlen:Optional[int]=None) -> bool:
|
||||
"""
|
||||
Check if a string is a valid hexstring
|
||||
"""
|
||||
|
@ -621,7 +624,7 @@ def is_hex(string, minlen=2, maxlen=None) -> bool:
|
|||
except:
|
||||
return False
|
||||
|
||||
def sanitize_pin_adm(pin_adm, pin_adm_hex = None):
|
||||
def sanitize_pin_adm(pin_adm, pin_adm_hex = None) -> Hexstr:
|
||||
"""
|
||||
The ADM pin can be supplied either in its hexadecimal form or as
|
||||
ascii string. This function checks the supplied opts parameter and
|
||||
|
@ -792,7 +795,7 @@ def sw_match(sw:str, pattern:str) -> bool:
|
|||
return sw_masked == pattern
|
||||
|
||||
def tabulate_str_list(str_list, width:int = 79, hspace:int = 2, lspace:int = 1,
|
||||
align_left:bool = True):
|
||||
align_left:bool = True) -> str:
|
||||
"""Pretty print a list of strings into a tabulated form.
|
||||
|
||||
Args:
|
||||
|
|
Loading…
Reference in New Issue