25 Commits
27c3 ... ccc

Author SHA1 Message Date
Sylvain Munaut
1f81cbf1f0 ccc: Fix SMSP generation in CCC tool as well
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-12-23 17:25:26 +01:00
Sylvain Munaut
487d01833d 27c3: Add a ccc-fix script to correct bad SMSP file ...
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-12-23 17:25:26 +01:00
Sylvain Munaut
33339a6daa Import of the programming tool
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-12-23 17:25:26 +01:00
Sylvain Munaut
93ec5f3566 Initial add of 27C3 HLR management tools
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-12-23 17:25:26 +01:00
Sylvain Munaut
2fc205ceb9 cards: sysmocom SysmoSIM-GR2 support added to cards
Written-by: Kevin Redon
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-12-23 17:22:56 +01:00
Sylvain Munaut
9f13897408 pySim-read: MISDN is not mandatory
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-07-18 10:36:51 +02:00
Alexander Chemeris
7be92ff5d2 Move encoder functions for ICCID, IMSI and PLMN to pySim.utils for consistency. 2013-07-13 08:53:21 +02:00
Alexander Chemeris
6e58914746 Add an utility to read data from a SIM card. 2013-07-13 08:50:55 +02:00
Alexander Chemeris
5e96c3d910 utils: Add functions to decode IMSI and ICCID from EF raw data. 2013-07-13 08:49:03 +02:00
Alexander Chemeris
21885249cf Implement setting of EF.ACC file in GrcardSim and _MagicSimBase
From: Alexander Chemeris <Alexander.Chemeris@gmail.com>
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-07-02 15:19:09 +02:00
Sylvain Munaut
5da8d4e0d4 cards: Fix spacing according to PEP
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-07-02 15:13:24 +02:00
Sylvain Munaut
053c89578c cards: Fix comment position
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2013-07-02 15:12:32 +02:00
Holger Hans Peter Freyther
cca41795a7 usim/opc: Derive OPC from KI and OP 2012-03-22 15:25:31 +01:00
Harald Welte
93b38cd0f5 usim/opc: Add support to write completely random OPC
Allow to set the OPC, write it out to the state, generate it randomly.
2012-03-22 15:25:19 +01:00
Holger Hans Peter Freyther
4d91bf449f sysmoUSIM-GR1: Add basic (hacky) support for the sysmoUSIM-GR1
Right now we are only to program the KI, OPC, ICCID and IMSI. This
is done in a direct way and through the card abstraction.
2012-03-22 14:28:38 +01:00
Sylvain Munaut
8ca49e9ca8 cards: SMSP is left padded not right padded
I confused left & right, silly me ...

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2011-12-10 09:57:50 +01:00
Sylvain Munaut
9977c86e96 pySim-prog: Fix SMSC 'number type' field to 0x81
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2011-12-10 09:57:16 +01:00
Sylvain Munaut
607ce2a029 Fix computation of SMSP from a SMSC number
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2011-12-08 20:16:43 +01:00
Sylvain Munaut
1a914439b8 Whitespace fixes 2011-12-08 20:08:26 +01:00
Harald Welte
e10394bfb6 Add sysmoSIM-GR1 as alias to grcardsim 2011-12-08 19:39:49 +01:00
Harald Welte
2c0ff3a167 correctly compute the ICCID (19 digits, including luhn checksum) 2011-12-08 19:39:49 +01:00
Holger Hans Peter Freyther
5dffefbf0c pySim-prog.py: pyflakes doesn't find Importerror..
Importerror -> ImportError, spotted by pyflakes.
2011-11-22 21:18:06 +01:00
Holger Hans Peter Freyther
50e7c03816 README: Mention the necessary wait_for_card 2011-07-27 08:55:44 +02:00
Harald Welte
3156d9073f cards: Add support for grcard.cn (Green Card) SIM cards
This does not have auto-detection (yet), so you have to explicitly
specify "-t grcardsim" on the command line
2011-03-22 21:48:19 +01:00
Harald Welte
982a3075f9 commands: Check SW for UPDATE BIN / UPDATE REC / VERIFY CHV 2011-03-22 21:47:20 +01:00
7 changed files with 479 additions and 48 deletions

2
README
View File

@@ -29,6 +29,8 @@ from pySim.commands import SimCardCommands
sl = SerialSimLink(device='/dev/ttyUSB0', baudrate=9600)
sc = SimCardCommands(sl)
sl.wait_for_card()
# Print IMSI
print sc.read_binary(['3f00', '7f20', '6f07'])

View File

@@ -23,7 +23,7 @@
from optparse import OptionParser
from ccc import StateManager, CardParametersGenerator, isnum
from pySim.utils import h2b
from pySim.utils import h2b, swap_nibbles, rpad
#
@@ -134,9 +134,12 @@ def parse_options():
help="Mobile Network Code [default: %default]",
default=42,
)
parser.add_option("-m", "--smsp", dest="smsp",
parser.add_option("-m", "--smsc", dest="smsc",
help="SMSP [default: '00 + country code + 5555']",
)
parser.add_option("-M", "--smsp", dest="smsp",
help="Raw SMSP content in hex [default: auto from SMSC]",
)
# Autogen
parser.add_option("-z", "--secret", dest="secret", metavar="STR",
@@ -175,11 +178,32 @@ def parse_options():
if 0 < options.mnc > 999:
parser.error("Invalid Mobile Network Code (MNC)")
# SMSP
if options.smsp is not None:
if not isnum(options.smsp):
parser.error("Invalid SMSP Number")
smsp = options.smsp
if not _ishex(smsp):
raise ValueError('SMSP must be hex digits only !')
if len(smsp) < 28*2:
raise ValueError('SMSP must be at least 28 bytes')
else:
options.smsp = '00%d' % options.country + '5555'
if options.smsc is not None:
smsc = options.smsc
if not _isnum(smsc):
raise ValueError('SMSC must be digits only !')
else:
smsc = '00%d' % options.country + '5555' # Hack ...
smsc = '%02d' % ((len(smsc) + 3)//2,) + "81" + swap_nibbles(rpad(smsc, 20))
options.smsp = (
'e1' + # Parameters indicator
'ff' * 12 + # TP-Destination address
smsc + # TP-Service Centre Address
'00' + # TP-Protocol identifier
'00' + # TP-Data coding scheme
'00' # TP-Validity period
)
return options

View File

@@ -33,13 +33,13 @@ import sys
try:
import json
except Importerror:
except ImportError:
# Python < 2.5
import simplejson as json
from pySim.commands import SimCardCommands
from pySim.cards import _cards_classes
from pySim.utils import h2b
from pySim.utils import h2b, swap_nibbles, rpad
def parse_options():
@@ -83,9 +83,12 @@ def parse_options():
help="Mobile Network Code [default: %default]",
default=55,
)
parser.add_option("-m", "--smsp", dest="smsp",
parser.add_option("-m", "--smsc", dest="smsc",
help="SMSP [default: '00 + country code + 5555']",
)
parser.add_option("-M", "--smsp", dest="smsp",
help="Raw SMSP content in hex [default: auto from SMSC]",
)
parser.add_option("-s", "--iccid", dest="iccid", metavar="ID",
help="Integrated Circuit Card ID",
@@ -96,6 +99,16 @@ def parse_options():
parser.add_option("-k", "--ki", dest="ki",
help="Ki (default is to randomize)",
)
parser.add_option("-o", "--opc", dest="opc",
help="OPC (default is to randomize)",
)
parser.add_option("--op", dest="op",
help="Set OP to derive OPC from OP and KI",
)
parser.add_option("--acc", dest="acc",
help="Set ACC bits (Access Control Code). not all card types are supported",
)
parser.add_option("-z", "--secret", dest="secret", metavar="STR",
help="Secret used for ICCID/IMSI autogen",
@@ -155,6 +168,10 @@ def _cc_digits(cc):
def _isnum(s, l=-1):
return s.isdigit() and ((l== -1) or (len(s) == l))
def _ishex(s, l=-1):
hc = '0123456789abcdef'
return all([x in hc for x in s.lower()]) and ((l== -1) or (len(s) == l))
def _dbi_binary_quote(s):
# Count usage of each char
@@ -174,7 +191,7 @@ def _dbi_binary_quote(s):
e = i
if m == 0: # No overhead ? use this !
break;
# Generate output
out = []
out.append( chr(e) ) # Offset
@@ -188,6 +205,23 @@ 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 derive_milenage_opc(ki_hex, op_hex):
"""
Run the milenage algorithm.
"""
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from pySim.utils import b2h
# We pass in hex string and now need to work on bytes
aes = AES.new(h2b(ki_hex))
opc_bytes = aes.encrypt(h2b(op_hex))
return b2h(strxor(opc_bytes, h2b(op_hex)))
def gen_parameters(opts):
"""Generates Name, ICCID, MCC, MNC, IMSI, SMSP, Ki from the
@@ -206,11 +240,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 +256,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 +265,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
@@ -258,21 +295,61 @@ def gen_parameters(opts):
# SMSP
if opts.smsp is not None:
smsp = opts.smsp
if not _isnum(smsp):
raise ValueError('SMSP must be digits only !')
if not _ishex(smsp):
raise ValueError('SMSP must be hex digits only !')
if len(smsp) < 28*2:
raise ValueError('SMSP must be at least 28 bytes')
else:
smsp = '00%d' % opts.country + '5555' # Hack ...
if opts.smsc is not None:
smsc = opts.smsc
if not _isnum(smsc):
raise ValueError('SMSC must be digits only !')
else:
smsc = '00%d' % opts.country + '5555' # Hack ...
smsc = '%02d' % ((len(smsc) + 3)//2,) + "81" + swap_nibbles(rpad(smsc, 20))
smsp = (
'e1' + # Parameters indicator
'ff' * 12 + # TP-Destination address
smsc + # TP-Service Centre Address
'00' + # TP-Protocol identifier
'00' + # TP-Data coding scheme
'00' # TP-Validity period
)
# ACC
if opts.acc is not None:
acc = opts.acc
if not _ishex(acc):
raise ValueError('ACC must be hex digits only !')
if len(acc) != 2*2:
raise ValueError('ACC must be exactly 2 bytes')
else:
acc = None
# Ki (random)
if opts.ki is not None:
ki = opts.ki
if not re.match('^[0-9a-fA-F]{32}$', ki):
raise ValueError('Ki needs to be 128 bits, in hex format')
else:
ki = ''.join(['%02x' % random.randrange(0,256) for i in range(16)])
# Ki (random)
if opts.opc is not None:
opc = opts.opc
if not re.match('^[0-9a-fA-F]{32}$', opc):
raise ValueError('OPC needs to be 128 bits, in hex format')
elif opts.op is not None:
opc = derive_milenage_opc(ki, opts.op)
else:
opc = ''.join(['%02x' % random.randrange(0,256) for i in range(16)])
# Return that
return {
'name' : opts.name,
@@ -282,6 +359,8 @@ def gen_parameters(opts):
'imsi' : imsi,
'smsp' : smsp,
'ki' : ki,
'opc' : opc,
'acc' : acc,
}
@@ -294,6 +373,8 @@ def print_parameters(params):
> MCC/MNC : %(mcc)d/%(mnc)d
> IMSI : %(imsi)s
> Ki : %(ki)s
> OPC : %(opc)s
> ACC : %(acc)s
""" % params
@@ -301,7 +382,7 @@ def write_parameters(opts, params):
# CSV
if opts.write_csv:
import csv
row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki']
row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc']
f = open(opts.write_csv, 'a')
cw = csv.writer(f)
cw.writerow([params[x] for x in row])
@@ -432,7 +513,7 @@ if __name__ == '__main__':
done = False
first = True
card = None
while not done:
# Connect transport
print "Insert card now (or CTRL-C to cancel)"

141
pySim-read.py Executable file
View File

@@ -0,0 +1,141 @@
#!/usr/bin/env python
#
# Utility to display some informations about a SIM card
#
#
# Copyright (C) 2009 Sylvain Munaut <tnt@246tNt.com>
# Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>
# Copyright (C) 2013 Alexander Chemeris <alexander.chemeris@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
import hashlib
from optparse import OptionParser
import os
import random
import re
import sys
try:
import json
except ImportError:
# Python < 2.5
import simplejson as json
from pySim.commands import SimCardCommands
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid
def parse_options():
parser = OptionParser(usage="usage: %prog [options]")
parser.add_option("-d", "--device", dest="device", metavar="DEV",
help="Serial Device for SIM access [default: %default]",
default="/dev/ttyUSB0",
)
parser.add_option("-b", "--baud", dest="baudrate", type="int", metavar="BAUD",
help="Baudrate used for SIM access [default: %default]",
default=9600,
)
parser.add_option("-p", "--pcsc-device", dest="pcsc_dev", type='int', metavar="PCSC",
help="Which PC/SC reader number for SIM access",
default=None,
)
(options, args) = parser.parse_args()
if args:
parser.error("Extraneous arguments")
return options
if __name__ == '__main__':
# Parse options
opts = parse_options()
# Connect to the card
if opts.pcsc_dev is None:
from pySim.transport.serial import SerialSimLink
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
else:
from pySim.transport.pcsc import PcscSimLink
sl = PcscSimLink(opts.pcsc_dev)
# Create command layer
scc = SimCardCommands(transport=sl)
# Wait for SIM card
sl.wait_for_card()
# Program the card
print("Reading ...")
# EF.ICCID
(res, sw) = scc.read_binary(['3f00', '2fe2'])
if sw == '9000':
print("ICCID: %s" % (dec_iccid(res),))
else:
print("ICCID: Can't read, response code = %s" % (sw,))
# EF.IMSI
(res, sw) = scc.read_binary(['3f00', '7f20', '6f07'])
if sw == '9000':
print("IMSI: %s" % (dec_imsi(res),))
else:
print("IMSI: Can't read, response code = %s" % (sw,))
# EF.SMSP
(res, sw) = scc.read_record(['3f00', '7f10', '6f42'], 1)
if sw == '9000':
print("SMSP: %s" % (res,))
else:
print("SMSP: Can't read, response code = %s" % (sw,))
# EF.HPLMN
# (res, sw) = scc.read_binary(['3f00', '7f20', '6f30'])
# if sw == '9000':
# print("HPLMN: %s" % (res))
# print("HPLMN: %s" % (dec_hplmn(res),))
# else:
# print("HPLMN: Can't read, response code = %s" % (sw,))
# FIXME
# EF.ACC
(res, sw) = scc.read_binary(['3f00', '7f20', '6f78'])
if sw == '9000':
print("ACC: %s" % (res,))
else:
print("ACC: Can't read, response code = %s" % (sw,))
# EF.MSISDN
try:
# print(scc.record_size(['3f00', '7f10', '6f40']))
(res, sw) = scc.read_record(['3f00', '7f10', '6f40'], 1)
if sw == '9000':
if res[1] != 'f':
print("MSISDN: %s" % (res,))
else:
print("MSISDN: Not available")
else:
print("MSISDN: Can't read, response code = %s" % (sw,))
except:
print "MSISDN: Can't read. Probably not existing file"
# Done for this card and maybe for everything ?
print "Done !\n"

View File

@@ -6,6 +6,7 @@
#
# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
# Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
#
# 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
@@ -21,7 +22,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from pySim.utils import b2h, swap_nibbles, rpad, lpad
from pySim.utils import b2h, h2b, swap_nibbles, rpad, lpad, enc_imsi, enc_iccid, enc_plmn
class Card(object):
@@ -29,20 +30,6 @@ class Card(object):
def __init__(self, scc):
self._scc = scc
def _e_iccid(self, iccid):
return swap_nibbles(iccid)
def _e_imsi(self, imsi):
"""Converts a string imsi into the value of the EF"""
l = (len(imsi) + 1) // 2 # Required bytes
oe = len(imsi) & 1 # Odd (1) / Even (0)
ei = '%02x' % l + swap_nibbles(lpad('%01x%s' % ((oe<<3)|1, imsi), 16))
return ei
def _e_plmn(self, mcc, mnc):
"""Converts integer MCC/MNC into 6 bytes for EF"""
return swap_nibbles(lpad('%d' % mcc, 3) + lpad('%d' % mnc, 3))
def reset(self):
self._scc.reset_card()
@@ -102,7 +89,7 @@ class _MagicSimBase(Card):
self._scc.select_file(['3f00', '7f4d'])
# Home PLMN in PLMN_Sel format
hplmn = self._e_plmn(p['mcc'], p['mnc'])
hplmn = enc_plmn(p['mcc'], p['mnc'])
# Operator name ( 3f00/7f4d/8f0c )
self._scc.update_record(self._files['name'][0], 2,
@@ -117,10 +104,10 @@ class _MagicSimBase(Card):
v += p['ki']
# ICCID
v += '3f00' + '2fe2' + '0a' + self._e_iccid(p['iccid'])
v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
# IMSI
v += '7f20' + '6f07' + '09' + self._e_imsi(p['imsi'])
v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
# Ki
if self._ki_file:
@@ -129,6 +116,12 @@ class _MagicSimBase(Card):
# PLMN_Sel
v+= '6f30' + '18' + rpad(hplmn, 36)
# ACC
# This doesn't work with "fake" SuperSIM cards,
# but will hopefully work with real SuperSIMs.
if p.get('acc') is not None:
v+= '6f78' + '02' + lpad(p['acc'], 4)
self._scc.update_record(self._files['b_ef'][0], 1,
rpad(v, self._files['b_ef'][1]*2)
)
@@ -140,7 +133,7 @@ class _MagicSimBase(Card):
r = self._scc.select_file(['3f00', '7f20', '6f30'])
tl = int(r[-1][4:8], 16)
hplmn = self._e_plmn(p['mcc'], p['mnc'])
hplmn = enc_plmn(p['mcc'], p['mnc'])
self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
def erase(self):
@@ -226,7 +219,7 @@ class FakeMagicSim(Card):
r = self._scc.select_file(['3f00', '7f20', '6f30'])
tl = int(r[-1][4:8], 16)
hplmn = self._e_plmn(p['mcc'], p['mnc'])
hplmn = enc_plmn(p['mcc'], p['mnc'])
self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
# Get total number of entries and entry size
@@ -236,12 +229,10 @@ class FakeMagicSim(Card):
entry = (
'81' + # 1b Status: Valid & Active
rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name
self._e_iccid(p['iccid']) + # 10b ICCID
self._e_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
enc_iccid(p['iccid']) + # 10b ICCID
enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
p['ki'] + # 16b Ki
24*'f' + 'fd' + 24*'f' + # 25b (unknown ...)
rpad(p['smsp'], 20) + # 10b SMSP (padded with ff if needed)
10*'f' # 5b (unknown ...)
lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
)
self._scc.update_record('000c', 1, entry)
@@ -255,5 +246,166 @@ class FakeMagicSim(Card):
self._scc.update_record('000c', 1+i, entry)
class GrcardSim(Card):
"""
Greencard (grcard.cn) HZCOS GSM SIM
These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
"""
name = 'grcardsim'
@classmethod
def autodetect(kls, scc):
return None
def program(self, p):
# We don't really know yet what ADM PIN 4 is about
#self._scc.verify_chv(4, h2b("4444444444444444"))
# Authenticate using ADM PIN 5
self._scc.verify_chv(5, h2b("4444444444444444"))
# EF.ICCID
r = self._scc.select_file(['3f00', '2fe2'])
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
# EF.IMSI
r = self._scc.select_file(['3f00', '7f20', '6f07'])
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
# EF.ACC
if p.get('acc') is not None:
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
# EF.SMSP
r = self._scc.select_file(['3f00', '7f10', '6f42'])
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
# Set the Ki using proprietary command
pdu = '80d4020010' + p['ki']
data, sw = self._scc._tp.send_apdu(pdu)
# EF.HPLMN
r = self._scc.select_file(['3f00', '7f20', '6f30'])
size = int(r[-1][4:8], 16)
hplmn = enc_plmn(p['mcc'], p['mnc'])
self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
# EF.SPN (Service Provider Name)
r = self._scc.select_file(['3f00', '7f20', '6f30'])
size = int(r[-1][4:8], 16)
# FIXME
# FIXME: EF.MSISDN
def erase(self):
return
class SysmoSIMgr1(GrcardSim):
"""
sysmocom sysmoSIM-GR1
These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
"""
name = 'sysmosim-gr1'
class SysmoUSIMgr1(Card):
"""
sysmocom sysmoUSIM-GR1
"""
name = 'sysmoUSIM-GR1'
@classmethod
def autodetect(kls, scc):
# TODO: Access the ATR
return None
def program(self, p):
# TODO: check if verify_chv could be used or what it needs
# self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
# Unlock the card..
data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
# TODO: move into SimCardCommands
par = ( p['ki'] + # 16b K
p['opc'] + # 32b OPC
enc_iccid(p['iccid']) + # 10b ICCID
enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
)
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
def erase(self):
return
class SysmoSIMgr2(Card):
"""
sysmocom sysmoSIM-GR2
"""
name = 'sysmoSIM-GR2'
@classmethod
def autodetect(kls, scc):
# TODO: look for ATR 3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68
return None
def program(self, p):
# select MF
r = self._scc.select_file(['3f00'])
# authenticate as SUPER ADM using default key
self._scc.verify_chv(0x0b, h2b("3838383838383838"))
# set ADM pin using proprietary command
# INS: D4
# P1: 3A for PIN, 3B for PUK
# P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
# P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
pdu = 'A0D43A0508' + "4444444444444444"
data, sw = self._scc._tp.send_apdu(pdu)
# authenticate as ADM (enough to write file, and can set PINs)
self._scc.verify_chv(0x05, h2b("4444444444444444"))
# write EF.ICCID
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
# select DF_GSM
r = self._scc.select_file(['7f20'])
# write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
# write EF.ACC
if p.get('acc') is not None:
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
# get size and write EF.HPLMN
r = self._scc.select_file(['6f30'])
size = int(r[-1][4:8], 16)
hplmn = enc_plmn(p['mcc'], p['mnc'])
self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
# set COMP128 version 0 in proprietary file
data, sw = self._scc.update_binary('0001', '001000')
# set Ki in proprietary file
data, sw = self._scc.update_binary('0001', p['ki'], 3)
# select DF_TELECOM
r = self._scc.select_file(['3f00', '7f10'])
# write EF.SMSP
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
def erase(self):
return
# In order for autodetection ...
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim ]
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1 ]

View File

@@ -50,7 +50,7 @@ class SimCardCommands(object):
ef = [ef]
self.select_file(ef)
pdu = 'a0d6%04x%02x' % (offset, len(data)/2) + data
return self._tp.send_apdu(pdu)
return self._tp.send_apdu_checksw(pdu)
def read_record(self, ef, rec_no):
if not hasattr(type(ef), '__iter__'):
@@ -71,7 +71,7 @@ class SimCardCommands(object):
else:
rec_length = len(data)/2
pdu = ('a0dc%02x04%02x' % (rec_no, rec_length)) + data
return self._tp.send_apdu(pdu)
return self._tp.send_apdu_checksw(pdu)
def record_size(self, ef):
r = self.select_file(ef)
@@ -92,4 +92,4 @@ class SimCardCommands(object):
def verify_chv(self, chv_no, code):
fc = rpad(b2h(code), 16)
return self._tp.send_apdu('a02000' + ('%02x' % chv_no) + '08' + fc)
return self._tp.send_apdu_checksw('a02000' + ('%02x' % chv_no) + '08' + fc)

View File

@@ -42,3 +42,34 @@ def rpad(s, l, c='f'):
def lpad(s, l, c='f'):
return c * (l - len(s)) + s
def enc_imsi(imsi):
"""Converts a string imsi into the value of the EF"""
l = (len(imsi) + 1) // 2 # Required bytes
oe = len(imsi) & 1 # Odd (1) / Even (0)
ei = '%02x' % l + swap_nibbles(lpad('%01x%s' % ((oe<<3)|1, imsi), 16))
return ei
def dec_imsi(ef):
"""Converts an EF value to the imsi string representation"""
if len(ef) < 4:
return None
l = int(ef[0:2]) * 2 # Length of the IMSI string
swapped = swap_nibbles(ef[2:])
oe = (int(swapped[0])>>3) & 1 # Odd (1) / Even (0)
if oe:
l = l-1
if l+1 > len(swapped):
return None
imsi = swapped[1:l+2]
return imsi
def dec_iccid(ef):
return swap_nibbles(ef).strip('f')
def enc_iccid(iccid):
return swap_nibbles(rpad(iccid, 20))
def enc_plmn(mcc, mnc):
"""Converts integer MCC/MNC into 6 bytes for EF"""
return swap_nibbles(lpad('%d' % mcc, 3) + lpad('%d' % mnc, 3))