dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/38118?usp=email )
Change subject: utils: support alpha identifier in enc/dec_msisdn ......................................................................
utils: support alpha identifier in enc/dec_msisdn
The functions enc_msisdn and dec_msisdn do not support encoding and decoding of the alpha identifier. Let's extend the functions accordingly.
Related: OS#5714 Change-Id: I19ec8ba14551ec282fc0cc12ae2f6d528bdfc527 --- M pySim-read.py M pySim/utils.py M tests/unittests/test_utils.py 3 files changed, 33 insertions(+), 14 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/18/38118/1
diff --git a/pySim-read.py b/pySim-read.py index aae5ad4..7af40b2 100755 --- a/pySim-read.py +++ b/pySim-read.py @@ -209,7 +209,7 @@ if sw == '9000': # (npi, ton, msisdn) = res if res is not None: - print("MSISDN (NPI=%d ToN=%d): %s" % res) + print("MSISDN (Alpha-Identifier="%s" NPI=%d ToN=%d): %s" % res) else: print("MSISDN: Not available") else: diff --git a/pySim/utils.py b/pySim/utils.py index 05ad962..aa69a18 100644 --- a/pySim/utils.py +++ b/pySim/utils.py @@ -355,8 +355,9 @@ if len(ef_msisdn) < 14: raise ValueError("EF.MSISDN is too short")
- # Skip optional Alpha Identifier + # Decode and skip optional Alpha Identifier xlen = len(ef_msisdn) - 14 + alpha_id = h2s(b2h(ef_msisdn[0:xlen])) msisdn_lhv = ef_msisdn[xlen:]
# Parse the length (in bytes) of the BCD encoded number @@ -382,23 +383,28 @@ if ton == 0x01: msisdn = '+' + msisdn
- return (npi, ton, msisdn) + return (alpha_id, npi, ton, msisdn)
-def enc_msisdn(msisdn: str, npi: int = 0x01, ton: int = 0x03) -> Hexstr: +def enc_msisdn(msisdn: str, npi: int = 0x01, ton: int = 0x03, alpha_id: str = "", rec_len: int = 14) -> 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. (The result - will not contain the optional Alpha Identifier at the beginning.) + See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
Default NPI / ToN values: - NPI: ISDN / telephony numbering plan (E.164 / E.163), - ToN: network specific or international number (if starts with '+'). + - alpha_id: human readable string that serves a label for the MSISDN + - rec_len: overall record length of the encoded result (>= 14) """
- # If no MSISDN is supplied then encode the file contents as all "ff" + # The resulting record length must have a length of at least 14 bytes. + if rec_len < 14: + raise ValueError("record length must be at least 14 bytess") + + # If no MSISDN is supplied then encode the record contents as all "ff" if msisdn in ["", "+"]: - return "ff" * 14 + return "ff" * rec_len
# Leading '+' indicates International Number if msisdn[0] == '+': @@ -418,7 +424,14 @@ npi_ton = (npi & 0x0f) | ((ton & 0x07) << 4) | 0x80 bcd = rpad(swap_nibbles(msisdn), 10 * 2) # pad to 10 octets
- return ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd + ("ff" * 2) + # Encode Alpha identifier + alpha_id_enc = s2h(alpha_id) + alpha_id_padding_len = rec_len - 14 - len(alpha_id) + if alpha_id_padding_len < 0: + raise ValueError("alpha_id too long, increase rec_len") + alpha_id_padding = "ff" * alpha_id_padding_len + + return alpha_id_enc + alpha_id_padding + ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd + ("ff" * 2)
def sanitize_pin_adm(pin_adm, pin_adm_hex=None) -> Hexstr: diff --git a/tests/unittests/test_utils.py b/tests/unittests/test_utils.py index 0e61a61..ed22a73 100755 --- a/tests/unittests/test_utils.py +++ b/tests/unittests/test_utils.py @@ -157,20 +157,26 @@ self.assertEqual(msisdn_encoded, "ffffffffffffffffffffffffffff") msisdn_encoded = utils.enc_msisdn("+", npi=0x01, ton=0x03) self.assertEqual(msisdn_encoded, "ffffffffffffffffffffffffffff") + msisdn_encoded = utils.enc_msisdn("+4917279119183", npi=0x01, ton=0x01, alpha_id="Eigene Rufnummer", rec_len=34) + self.assertEqual(msisdn_encoded, "456967656e65205275666e756d6d6572ffffffff0891947172199181f3ffffffffff")
def testDec_msisdn(self): msisdn_decoded = utils.dec_msisdn("0891946110325476f8ffffffffff") - self.assertEqual(msisdn_decoded, (1, 1, "+4916012345678")) + self.assertEqual(msisdn_decoded, ("", 1, 1, "+4916012345678")) msisdn_decoded = utils.dec_msisdn("04b1214365ffffffffffffffffff") - self.assertEqual(msisdn_decoded, (1, 3, "123456")) + self.assertEqual(msisdn_decoded, ("", 1, 3, "123456")) msisdn_decoded = utils.dec_msisdn("0bb121436587092143658709ffff") - self.assertEqual(msisdn_decoded, (1, 3, "12345678901234567890")) + self.assertEqual(msisdn_decoded, ("", 1, 3, "12345678901234567890")) msisdn_decoded = utils.dec_msisdn("ffffffffffffffffffffffffffff") self.assertEqual(msisdn_decoded, None) msisdn_decoded = utils.dec_msisdn("00112233445566778899AABBCCDDEEFF001122330bb121436587092143658709ffff") - self.assertEqual(msisdn_decoded, (1, 3, "12345678901234567890")) + self.assertEqual(msisdn_decoded, ('\x00\x11"3DUfw\x88\x99ª»ÌÝî\x00\x11"3', 1, 3, "12345678901234567890")) msisdn_decoded = utils.dec_msisdn("ffffffffffffffffffffffffffffffffffffffff0bb121436587092143658709ffff") - self.assertEqual(msisdn_decoded, (1, 3, "12345678901234567890")) + self.assertEqual(msisdn_decoded, ("", 1, 3, "12345678901234567890")) + msisdn_decoded = utils.dec_msisdn("456967656e65205275666e756d6d6572ffffffff0891947172199181f3ffffffffff") + self.assertEqual(msisdn_decoded, ( "Eigene Rufnummer", 1, 1, "+4917279119183" )) + msisdn_decoded = utils.dec_msisdn("456967656e65205275666e756d6d65720891947172199181f3ffffffffff") + self.assertEqual(msisdn_decoded, ( "Eigene Rufnummer", 1, 1, "+4917279119183" ))
class TestLuhn(unittest.TestCase): def test_verify(self):