From 2c0ff3a1677a232f2617b5aba1a1002f16e7c7d3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 7 Dec 2011 12:34:13 +0100 Subject: correctly compute the ICCID (19 digits, including luhn checksum) --- pySim-prog.py | 15 +++++++++++---- pySim/cards.py | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pySim-prog.py b/pySim-prog.py index d057a51..493d434 100755 --- a/pySim-prog.py +++ b/pySim-prog.py @@ -188,6 +188,10 @@ def _dbi_binary_quote(s): return ''.join(out) +def calculate_luhn(cc): + num = map(int, str(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 gen_parameters(opts): """Generates Name, ICCID, MCC, MNC, IMSI, SMSP, Ki from the @@ -206,11 +210,11 @@ def gen_parameters(opts): # Digitize MCC/MNC (5 or 6 digits) plmn_digits = _mcc_mnc_digits(mcc, mnc) - # ICCID (20 digits) + # ICCID (19 digits, E.118), though some phase1 vendors use 20 :( if opts.iccid is not None: iccid = opts.iccid - if not _isnum(iccid, 20): - raise ValueError('ICCID must be 20 digits !'); + if not _isnum(iccid, 19): + raise ValueError('ICCID must be 19 digits !'); else: if opts.num is None: @@ -222,7 +226,7 @@ def gen_parameters(opts): plmn_digits # MCC/MNC on 5/6 digits ) - ml = 20 - len(iccid) + ml = 18 - len(iccid) if opts.secret is None: # The raw number @@ -231,6 +235,9 @@ def gen_parameters(opts): # 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 diff --git a/pySim/cards.py b/pySim/cards.py index 3ceaa63..8f7fda7 100644 --- a/pySim/cards.py +++ b/pySim/cards.py @@ -31,7 +31,7 @@ class Card(object): self._scc = scc def _e_iccid(self, iccid): - return swap_nibbles(iccid) + return swap_nibbles(rpad(iccid, 20)) def _e_imsi(self, imsi): """Converts a string imsi into the value of the EF""" -- cgit v1.2.3