This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Falkenber9 gerrit-no-reply at lists.osmocom.orgFalkenber9 has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/24180 ) Change subject: Add codecs for EF_SPN and GSM strings via construct ...................................................................... Add codecs for EF_SPN and GSM strings via construct This will replace the hand-crafted codec for EF_SPN by a struct definition using the construct library. Old encoders are updated and kept for API compatibility but are not used internally anymore. New data structures: * Rpad(Adapter): Right-padded bytestring (0xff, adjustable) * GsmStringAdapter(Adapter): Codec for "SMS default 7-bit coded alphabet as defined int TS 23.038" using the gsm0338 library. * GsmString(n): Convenient wrapper of both above Adjustments: * utils: update+deprecate old dec_spn(), enc_spn() * remove refs to deprecated functions Change-Id: Ia1d3a3835933bac0002b7c52511481dd8094b994 --- M pySim-read.py M pySim/cards.py M pySim/construct.py M pySim/ts_51_011.py M pySim/utils.py M requirements.txt M setup.py 7 files changed, 96 insertions(+), 27 deletions(-) git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/80/24180/1 diff --git a/pySim-read.py b/pySim-read.py index ebe0e29..9feef9d 100755 --- a/pySim-read.py +++ b/pySim-read.py @@ -36,7 +36,7 @@ from pySim.transport import init_reader, argparse_add_reader_args from pySim.cards import card_detect, Card, UsimCard, IsimCard from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, dec_msisdn -from pySim.utils import format_xplmn_w_act, dec_spn, dec_st, dec_addr_tlv +from pySim.utils import format_xplmn_w_act, dec_st, dec_addr_tlv from pySim.utils import h2s, format_ePDGSelection option_parser = argparse.ArgumentParser(prog='pySim-read', diff --git a/pySim/cards.py b/pySim/cards.py index 30857b3..dcba26c 100644 --- a/pySim/cards.py +++ b/pySim/cards.py @@ -25,7 +25,7 @@ from typing import Optional, Dict, Tuple import abc -from pySim.ts_51_011 import EF, DF, EF_AD +from pySim.ts_51_011 import EF, DF, EF_AD, EF_SPN from pySim.ts_31_102 import EF_USIM_ADF_map from pySim.ts_31_103 import EF_ISIM_ADF_map from pySim.utils import * @@ -203,15 +203,24 @@ return sw def read_spn(self): - (spn, sw) = self._scc.read_binary(EF['SPN']) + (content, sw) = self._scc.read_binary(EF['SPN']) if sw == '9000': - return (dec_spn(spn), sw) + abstract_data = EF_SPN().decode_hex(content) + show_in_hplmn = abstract_data['show_in_hplmn'] + hide_in_oplmn = abstract_data['hide_in_oplmn'] + name = abstract_data['spn'] + return ((name, show_in_hplmn, hide_in_oplmn), sw) else: return (None, sw) - def update_spn(self, name, hplmn_disp=False, oplmn_disp=False): - content = enc_spn(name, hplmn_disp, oplmn_disp) - data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32)) + def update_spn(self, name="", show_in_hplmn=False, hide_in_oplmn=False): + abstract_data = { + 'hide_in_oplmn' : hide_in_oplmn, + 'show_in_hplmn' : show_in_hplmn, + 'spn' : name, + } + content = EF_SPN().encode_hex(abstract_data) + data, sw = self._scc.update_binary(EF['SPN'], content) return sw def read_binary(self, ef, length=None, offset=0): @@ -915,8 +924,7 @@ # set Service Provider Name if p.get('name') is not None: - content = enc_spn(p['name'], True, True) - data, sw = self._scc.update_binary('6F46', rpad(content, 32)) + self.update_spn(p['name'], True, True) if p.get('acc') is not None: self.update_acc(p['acc']) @@ -1310,8 +1318,7 @@ # set Service Provider Name if p.get('name') is not None: - content = enc_spn(p['name'], True, True) - data, sw = self._scc.update_binary('6F46', rpad(content, 32)) + self.update_spn(p['name'], True, True) # write EF.IMSI if p.get('imsi'): diff --git a/pySim/construct.py b/pySim/construct.py index b0f03b7..a903305 100644 --- a/pySim/construct.py +++ b/pySim/construct.py @@ -1,5 +1,6 @@ from construct import * from pySim.utils import b2h, h2b, swap_nibbles +import gsm0338 """Utility code related to the integration of the 'construct' declarative parser.""" @@ -33,6 +34,42 @@ def _encode(self, obj, context, path): return h2b(swap_nibbles(obj)) +class Rpad(Adapter): + """ + Encoder appends padding bytes (b'\\xff') up to target size. + Decoder removes trailing padding bytes. + + Parameters: + subcon: Subconstruct as defined by construct library + pattern: set padding pattern (default: b'\\xff') + """ + + def __init__(self, subcon, pattern=b'\xff'): + super().__init__(subcon) + self.pattern = pattern + + def _decode(self, obj, context, path): + return obj.rstrip(self.pattern) + + def _encode(self, obj, context, path): + if len(obj) > self.sizeof(): + raise SizeofError("Input ({}) exceeds target size ({})".format(len(obj), self.sizeof())) + return obj + self.pattern * (self.sizeof() - len(obj)) + +class GsmStringAdapter(Adapter): + """Convert GSM 03.38 encoded bytes to a string.""" + + def __init__(self, subcon, codec='gsm03.38', err='strict'): + super().__init__(subcon) + self.codec = codec + self.err = err + + def _decode(self, obj, context, path): + return obj.decode(self.codec) + + def _encode(self, obj, context, path): + return obj.encode(self.codec, self.err) + def filter_dict(d, exclude_prefix='_'): """filter the input dict to ensure no keys starting with 'exclude_prefix' remain.""" res = {} @@ -88,3 +125,17 @@ n (Integer): Number of bytes (default: 1) ''' return Default(Bytes(n), __RFU_VALUE) + +def GsmString(n): + ''' + GSM 03.38 encoded byte string of fixed length n. + Encoder appends padding bytes (b'\\xff') to maintain + length. Decoder removes those trailing bytes. + + Exceptions are raised for invalid characters + and length excess. + + Parameters: + n (Integer): Fixed length of the encoded byte string + ''' + return GsmStringAdapter(Rpad(Bytes(n), pattern=b'\xff'), codec='gsm03.38') diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py index dba0369..6ab07f0 100644 --- a/pySim/ts_51_011.py +++ b/pySim/ts_51_011.py @@ -323,7 +323,7 @@ from struct import pack, unpack from construct import * from construct import Optional as COptional -from pySim.construct import HexAdapter, BcdAdapter, FlagRFU, ByteRFU, GreedyBytesRFU, BitsRFU, BytesRFU +from pySim.construct import * import enum from pySim.filesystem import * @@ -519,11 +519,14 @@ class EF_SPN(TransparentEF): def __init__(self, fid='6f46', sfid=None, name='EF.SPN', desc='Service Provider Name', size={17,17}): super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size) - def _decode_hex(self, raw_hex): - return {'spn': dec_spn(raw_hex)} - def _encode_hex(self, abstract): - spn = abstract['spn'] - return enc_spn(spn[0], spn[1], spn[2]) + self._construct = BitStruct( + # Byte 1 + 'rfu'/BitsRFU(6), + 'hide_in_oplmn'/Flag, + 'show_in_hplmn'/Flag, + # Bytes 2..17 + 'spn'/Bytewise(GsmString(16)) + ) # TS 51.011 Section 10.3.13 class EF_CBMI(TransRecEF): diff --git a/pySim/utils.py b/pySim/utils.py index a3cd1b5..3a8ddac 100644 --- a/pySim/utils.py +++ b/pySim/utils.py @@ -248,17 +248,23 @@ return res def dec_spn(ef): - byte1 = int(ef[0:2]) - hplmn_disp = (byte1&0x01 == 0x01) - oplmn_disp = (byte1&0x02 == 0x02) - name = h2s(ef[2:]) - return (name, hplmn_disp, oplmn_disp) + """Obsolete, kept for API compatibility""" + from ts_51_011 import EF_SPN + abstract_data = EF_SPN().decode_hex(ef) + show_in_hplmn = abstract_data['show_in_hplmn'] + hide_in_oplmn = abstract_data['hide_in_oplmn'] + name = abstract_data['spn'] + return (name, show_in_hplmn, hide_in_oplmn) -def enc_spn(name:str, hplmn_disp=False, oplmn_disp=False): - byte1 = 0x00 - if hplmn_disp: byte1 = byte1|0x01 - if oplmn_disp: byte1 = byte1|0x02 - return i2h([byte1])+s2h(name) +def enc_spn(name:str, show_in_hplmn=False, hide_in_oplmn=False): + """Obsolete, kept for API compatibility""" + from ts_51_011 import EF_SPN + abstract_data = { + 'hide_in_oplmn' : hide_in_oplmn, + 'show_in_hplmn' : show_in_hplmn, + 'spn' : name, + } + return EF_SPN().encode_hex(abstract_data) def hexstr_to_Nbytearr(s, nbytes): return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2)) ] diff --git a/requirements.txt b/requirements.txt index 6e8336c..10e9667 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ jsonpath-ng construct bidict +gsm0338 diff --git a/setup.py b/setup.py index 08608dc..2ef498f 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ "jsonpath-ng", "construct >= 2.9", "bidict", + "gsm0338", ], scripts=[ 'pySim-prog.py', -- To view, visit https://gerrit.osmocom.org/c/pysim/+/24180 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ia1d3a3835933bac0002b7c52511481dd8094b994 Gerrit-Change-Number: 24180 Gerrit-PatchSet: 1 Gerrit-Owner: Falkenber9 <robert.falkenberg at tu-dortmund.de> Gerrit-MessageType: newchange -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210509/6d66a103/attachment.htm>