mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-16 18:38:32 +03:00
Compare commits
18 Commits
27c3
...
zecke/hack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44e4636755 | ||
|
|
93315bd466 | ||
|
|
69c2ce2525 | ||
|
|
8b59a55488 | ||
|
|
1d5968cfcf | ||
|
|
cca41795a7 | ||
|
|
93b38cd0f5 | ||
|
|
4d91bf449f | ||
|
|
8ca49e9ca8 | ||
|
|
9977c86e96 | ||
|
|
607ce2a029 | ||
|
|
1a914439b8 | ||
|
|
e10394bfb6 | ||
|
|
2c0ff3a167 | ||
|
|
5dffefbf0c | ||
|
|
50e7c03816 | ||
|
|
3156d9073f | ||
|
|
982a3075f9 |
2
README
2
README
@@ -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'])
|
||||
|
||||
|
||||
227
pySim-prog.py
227
pySim-prog.py
@@ -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():
|
||||
@@ -67,6 +67,12 @@ def parse_options():
|
||||
default=False,
|
||||
)
|
||||
|
||||
parser.add_option("-S", "--source", dest="source",
|
||||
help="Data Source[default: %default]",
|
||||
default="cmdline",
|
||||
)
|
||||
|
||||
# if mode is "cmdline"
|
||||
parser.add_option("-n", "--name", dest="name",
|
||||
help="Operator name [default: %default]",
|
||||
default="Magic",
|
||||
@@ -83,9 +89,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 +105,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("--read-imsi", dest="read_imsi", action="store_true",
|
||||
help="Read the IMSI from the CARD", default=False
|
||||
)
|
||||
|
||||
|
||||
parser.add_option("-z", "--secret", dest="secret", metavar="STR",
|
||||
help="Secret used for ICCID/IMSI autogen",
|
||||
@@ -111,12 +130,20 @@ def parse_options():
|
||||
help="Optional batch state file",
|
||||
)
|
||||
|
||||
# if mode is "csv"
|
||||
parser.add_option("--read-csv", dest="read_csv", metavar="FILE",
|
||||
help="Read parameters from CSV file rather than command line")
|
||||
|
||||
|
||||
parser.add_option("--write-csv", dest="write_csv", metavar="FILE",
|
||||
help="Append generated parameters in CSV file",
|
||||
)
|
||||
parser.add_option("--write-hlr", dest="write_hlr", metavar="FILE",
|
||||
help="Append generated parameters to OpenBSC HLR sqlite3",
|
||||
)
|
||||
parser.add_option("--dry-run", dest="dry_run",
|
||||
help="Perform a 'dry run', don't actually program the card",
|
||||
default=False, action="store_true")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
@@ -125,6 +152,20 @@ def parse_options():
|
||||
print kls.name
|
||||
sys.exit(0)
|
||||
|
||||
if options.source == 'csv':
|
||||
if (options.imsi is None) and (options.batch_mode is False) and (options.read_imsi is False):
|
||||
parser.error("CSV mode needs either an IMSI, --read-imsi or batch mode")
|
||||
if options.read_csv is None:
|
||||
parser.error("CSV mode requires a CSV input file")
|
||||
elif options.source == 'cmdline':
|
||||
if ((options.imsi is None) or (options.iccid is None)) and (options.num is None):
|
||||
parser.error("If either IMSI or ICCID isn't specified, num is required")
|
||||
else:
|
||||
parser.error("Only `cmdline' and `csv' sources supported")
|
||||
|
||||
if (options.read_csv is not None) and (options.source != 'csv'):
|
||||
parser.error("You cannot specify a CSV input file in source != csv")
|
||||
|
||||
if (options.batch_mode) and (options.num is None):
|
||||
options.num = 0
|
||||
|
||||
@@ -132,9 +173,6 @@ def parse_options():
|
||||
if (options.imsi is not None) or (options.iccid is not None):
|
||||
parser.error("Can't give ICCID/IMSI for batch mode, need to use automatic parameters ! see --num and --secret for more informations")
|
||||
|
||||
if ((options.imsi is None) or (options.iccid is None)) and (options.num is None):
|
||||
parser.error("If either IMSI or ICCID isn't specified, num is required")
|
||||
|
||||
if args:
|
||||
parser.error("Extraneous arguments")
|
||||
|
||||
@@ -155,6 +193,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 +216,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 +230,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 +265,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 +281,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 +290,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 +320,50 @@ 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
|
||||
)
|
||||
|
||||
# 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 +373,7 @@ def gen_parameters(opts):
|
||||
'imsi' : imsi,
|
||||
'smsp' : smsp,
|
||||
'ki' : ki,
|
||||
'opc' : opc,
|
||||
}
|
||||
|
||||
|
||||
@@ -294,19 +386,48 @@ def print_parameters(params):
|
||||
> MCC/MNC : %(mcc)d/%(mnc)d
|
||||
> IMSI : %(imsi)s
|
||||
> Ki : %(ki)s
|
||||
> OPC : %(opc)s
|
||||
""" % params
|
||||
|
||||
|
||||
def write_parameters(opts, params):
|
||||
# CSV
|
||||
def write_params_csv(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])
|
||||
f.close()
|
||||
|
||||
def _read_params_csv(opts, imsi):
|
||||
import csv
|
||||
row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc']
|
||||
f = open(opts.read_csv, 'r')
|
||||
cr = csv.DictReader(f, row)
|
||||
i = 0
|
||||
for row in cr:
|
||||
if opts.num is not None and opts.read_imsi is False:
|
||||
if opts.num == i:
|
||||
f.close()
|
||||
return row;
|
||||
i += 1
|
||||
if row['imsi'] == imsi:
|
||||
f.close()
|
||||
return row;
|
||||
|
||||
f.close()
|
||||
return None
|
||||
|
||||
def read_params_csv(opts, imsi):
|
||||
row = _read_params_csv(opts, imsi)
|
||||
if row is not None:
|
||||
row['mcc'] = int(row['mcc'])
|
||||
row['mnc'] = int(row['mnc'])
|
||||
return row
|
||||
|
||||
|
||||
def write_params_hlr(opts, params):
|
||||
# SQLite3 OpenBSC HLR
|
||||
if opts.write_hlr:
|
||||
import sqlite3
|
||||
@@ -320,7 +441,7 @@ def write_parameters(opts, params):
|
||||
[
|
||||
params['imsi'],
|
||||
params['name'],
|
||||
'9' + params['iccid'][-5:]
|
||||
'9' + params['iccid'][-5:-1]
|
||||
],
|
||||
)
|
||||
sub_id = c.lastrowid
|
||||
@@ -337,6 +458,10 @@ def write_parameters(opts, params):
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def write_parameters(opts, params):
|
||||
write_params_csv(opts, params)
|
||||
write_params_hlr(opts, params)
|
||||
|
||||
|
||||
BATCH_STATE = [ 'name', 'country', 'mcc', 'mnc', 'smsp', 'secret', 'num' ]
|
||||
BATCH_INCOMPATIBLE = ['iccid', 'imsi', 'ki']
|
||||
@@ -432,37 +557,59 @@ if __name__ == '__main__':
|
||||
done = False
|
||||
first = True
|
||||
card = None
|
||||
|
||||
|
||||
while not done:
|
||||
# Connect transport
|
||||
print "Insert card now (or CTRL-C to cancel)"
|
||||
sl.wait_for_card(newcardonly=not first)
|
||||
|
||||
if opts.dry_run is False:
|
||||
# Connect transport
|
||||
print "Insert card now (or CTRL-C to cancel)"
|
||||
sl.wait_for_card(newcardonly=not first)
|
||||
|
||||
# Not the first anymore !
|
||||
first = False
|
||||
|
||||
# Get card
|
||||
card = card_detect(opts, scc)
|
||||
if card is None:
|
||||
if opts.batch_mode:
|
||||
first = False
|
||||
continue
|
||||
else:
|
||||
sys.exit(-1)
|
||||
if opts.dry_run is False:
|
||||
# Get card
|
||||
card = card_detect(opts, scc)
|
||||
if card is None:
|
||||
if opts.batch_mode:
|
||||
first = False
|
||||
continue
|
||||
else:
|
||||
sys.exit(-1)
|
||||
|
||||
# Erase if requested
|
||||
if opts.erase:
|
||||
print "Formatting ..."
|
||||
card.erase()
|
||||
card.reset()
|
||||
# Erase if requested
|
||||
if opts.erase:
|
||||
print "Formatting ..."
|
||||
card.erase()
|
||||
card.reset()
|
||||
|
||||
# Generate parameters
|
||||
cp = gen_parameters(opts)
|
||||
if opts.source == 'cmdline':
|
||||
cp = gen_parameters(opts)
|
||||
elif opts.source == 'csv':
|
||||
if opts.read_imsi:
|
||||
if opts.dry_run:
|
||||
# Connect transport
|
||||
print "Insert card now (or CTRL-C to cancel)"
|
||||
sl.wait_for_card(newcardonly=not first)
|
||||
(res,_) = scc.read_binary(['3f00', '7f20', '6f07'])
|
||||
imsi = swap_nibbles(res)[3:]
|
||||
else:
|
||||
imsi = opts.imsi
|
||||
cp = read_params_csv(opts, imsi)
|
||||
if cp is None:
|
||||
print "Error reading parameters\n"
|
||||
sys.exit(2)
|
||||
print_parameters(cp)
|
||||
|
||||
# Program the card
|
||||
print "Programming ..."
|
||||
card.program(cp)
|
||||
if opts.dry_run is False:
|
||||
# Program the card
|
||||
print "Programming ..."
|
||||
if opts.dry_run is not True:
|
||||
card.program(cp)
|
||||
else:
|
||||
print "Dry Run: NOT PROGRAMMING!"
|
||||
|
||||
# Write parameters permanently
|
||||
write_parameters(opts, cp)
|
||||
|
||||
104
pySim/cards.py
104
pySim/cards.py
@@ -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
|
||||
|
||||
|
||||
class Card(object):
|
||||
@@ -30,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"""
|
||||
@@ -239,9 +240,7 @@ class FakeMagicSim(Card):
|
||||
self._e_iccid(p['iccid']) + # 10b ICCID
|
||||
self._e_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)
|
||||
|
||||
@@ -254,6 +253,99 @@ class FakeMagicSim(Card):
|
||||
for i in range(0, rec_cnt):
|
||||
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', self._e_iccid(p['iccid']))
|
||||
|
||||
# EF.IMSI
|
||||
r = self._scc.select_file(['3f00', '7f20', '6f07'])
|
||||
data, sw = self._scc.update_binary('6f07', self._e_imsi(p['imsi']))
|
||||
|
||||
# EF.ACC
|
||||
#r = self._scc.select_file(['3f00', '7f20', '6f78'])
|
||||
#self._scc.update_binary('6f78', self._e_imsi(p['imsi'])
|
||||
|
||||
# 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 = self._e_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'
|
||||
|
||||
# In order for autodetection ...
|
||||
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim ]
|
||||
|
||||
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
|
||||
self._e_iccid(p['iccid']) + # 10b ICCID
|
||||
self._e_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
|
||||
)
|
||||
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
|
||||
|
||||
def erase(self):
|
||||
return
|
||||
|
||||
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
|
||||
SysmoSIMgr1, SysmoUSIMgr1 ]
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user