blob: dc14d58e5e3e5c52e0b9cdd9db05ead3f604a792 [file] [log] [blame]
Sylvain Munaut76504e02010-12-07 00:24:32 +01001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4""" pySim: various utilities
5"""
6
7#
8# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23
24
25def h2b(s):
26 return ''.join([chr((int(x,16)<<4)+int(y,16)) for x,y in zip(s[0::2], s[1::2])])
27
28def b2h(s):
29 return ''.join(['%02x'%ord(x) for x in s])
30
31def h2i(s):
32 return [(int(x,16)<<4)+int(y,16) for x,y in zip(s[0::2], s[1::2])]
33
34def i2h(s):
35 return ''.join(['%02x'%(x) for x in s])
36
Alexander Chemerisa5f0ea62017-07-18 16:48:47 +030037def h2s(s):
Vadim Yanitskiyeb06b452020-05-10 02:32:46 +070038 return ''.join([chr((int(x,16)<<4)+int(y,16)) for x,y in zip(s[0::2], s[1::2])
39 if int(x + y, 16) != 0xff])
Alexander Chemerisa5f0ea62017-07-18 16:48:47 +030040
41def s2h(s):
42 return b2h(s)
43
Supreeth Herle7d77d2d2020-05-11 09:07:08 +020044# List of bytes to string
45def i2s(s):
46 return ''.join([chr(x) for x in s])
47
Sylvain Munaut76504e02010-12-07 00:24:32 +010048def swap_nibbles(s):
49 return ''.join([x+y for x,y in zip(s[1::2], s[0::2])])
50
51def rpad(s, l, c='f'):
52 return s + c * (l - len(s))
53
54def lpad(s, l, c='f'):
55 return c * (l - len(s)) + s
Alexander Chemeris5e96c3d2013-07-04 17:33:33 +040056
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020057def half_round_up(n):
58 return (n + 1)//2
59
60# IMSI encoded format:
61# For IMSI 0123456789ABCDE:
62#
63# | byte 1 | 2 upper | 2 lower | 3 upper | 3 lower | ... | 9 upper | 9 lower |
64# | length in bytes | 0 | odd/even | 2 | 1 | ... | E | D |
65#
66# If the IMSI is less than 15 characters, it should be padded with 'f' from the end.
67#
68# The length is the total number of bytes used to encoded the IMSI. This includes the odd/even
69# parity bit. E.g. an IMSI of length 14 is 8 bytes long, not 7, as it uses bytes 2 to 9 to
70# encode itself.
71#
72# Because of this, an odd length IMSI fits exactly into len(imsi) + 1 // 2 bytes, whereas an
73# even length IMSI only uses half of the last byte.
74
Alexander Chemeris7be92ff2013-07-10 11:18:06 +040075def enc_imsi(imsi):
76 """Converts a string imsi into the value of the EF"""
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020077 l = half_round_up(len(imsi) + 1) # Required bytes - include space for odd/even indicator
Alexander Chemeris7be92ff2013-07-10 11:18:06 +040078 oe = len(imsi) & 1 # Odd (1) / Even (0)
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020079 ei = '%02x' % l + swap_nibbles('%01x%s' % ((oe<<3)|1, rpad(imsi, 15)))
Alexander Chemeris7be92ff2013-07-10 11:18:06 +040080 return ei
81
Alexander Chemeris5e96c3d2013-07-04 17:33:33 +040082def dec_imsi(ef):
83 """Converts an EF value to the imsi string representation"""
84 if len(ef) < 4:
85 return None
Pau Espin Pedrol665bd222017-12-29 20:30:35 +010086 l = int(ef[0:2], 16) * 2 # Length of the IMSI string
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020087 l = l - 1 # Encoded length byte includes oe nibble
88 swapped = swap_nibbles(ef[2:]).rstrip('f')
Philipp Maiercd3d6262020-05-11 21:41:56 +020089 if len(swapped) < 1:
90 return None
Alexander Chemeris5e96c3d2013-07-04 17:33:33 +040091 oe = (int(swapped[0])>>3) & 1 # Odd (1) / Even (0)
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020092 if not oe:
93 # if even, only half of last byte was used
Alexander Chemeris5e96c3d2013-07-04 17:33:33 +040094 l = l-1
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020095 if l != len(swapped) - 1:
Alexander Chemeris5e96c3d2013-07-04 17:33:33 +040096 return None
Ben Fox-Moore0ec14752018-09-24 15:47:02 +020097 imsi = swapped[1:]
Alexander Chemeris5e96c3d2013-07-04 17:33:33 +040098 return imsi
99
100def dec_iccid(ef):
101 return swap_nibbles(ef).strip('f')
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400102
103def enc_iccid(iccid):
104 return swap_nibbles(rpad(iccid, 20))
105
106def enc_plmn(mcc, mnc):
Alexander Chemerisdddbf522017-07-18 16:49:59 +0300107 """Converts integer MCC/MNC into 3 bytes for EF"""
Harald Welte7f1d3c42020-05-12 21:12:44 +0200108 if len(mnc) == 2:
109 mnc = "F%s" % mnc
110 return swap_nibbles("%s%s" % (mcc, mnc))
Alexander Chemerisa5f0ea62017-07-18 16:48:47 +0300111
112def dec_spn(ef):
113 byte1 = int(ef[0:2])
114 hplmn_disp = (byte1&0x01 == 0x01)
115 oplmn_disp = (byte1&0x02 == 0x02)
116 name = h2s(ef[2:])
117 return (name, hplmn_disp, oplmn_disp)
118
119def enc_spn(name, hplmn_disp=False, oplmn_disp=False):
120 byte1 = 0x00
121 if hplmn_disp: byte1 = byte1|0x01
122 if oplmn_disp: byte1 = byte1|0x02
123 return i2h([byte1])+s2h(name)
Alexander Chemeris19fffa12018-01-11 13:06:43 +0900124
Daniel Laszlo Sitzer851e9c02018-12-04 19:40:08 +0100125def hexstr_to_fivebytearr(s):
126 return [s[i:i+10] for i in range(0, len(s), 10) ]
127
Harald Welteca673942020-06-03 15:19:40 +0200128def hexstr_to_threebytearr(s):
129 return [s[i:i+6] for i in range(0, len(s), 6) ]
130
Daniel Laszlo Sitzer851e9c02018-12-04 19:40:08 +0100131# Accepts hex string representing three bytes
132def dec_mcc_from_plmn(plmn):
133 ia = h2i(plmn)
134 digit1 = ia[0] & 0x0F # 1st byte, LSB
135 digit2 = (ia[0] & 0xF0) >> 4 # 1st byte, MSB
136 digit3 = ia[1] & 0x0F # 2nd byte, LSB
137 if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
138 return 0xFFF # 4095
Supreeth Herled24f1632019-11-30 10:37:09 +0100139 return derive_mcc(digit1, digit2, digit3)
Daniel Laszlo Sitzer851e9c02018-12-04 19:40:08 +0100140
141def dec_mnc_from_plmn(plmn):
142 ia = h2i(plmn)
143 digit1 = ia[2] & 0x0F # 3rd byte, LSB
144 digit2 = (ia[2] & 0xF0) >> 4 # 3rd byte, MSB
145 digit3 = (ia[1] & 0xF0) >> 4 # 2nd byte, MSB
146 if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
147 return 0xFFF # 4095
Supreeth Herled24f1632019-11-30 10:37:09 +0100148 return derive_mnc(digit1, digit2, digit3)
Daniel Laszlo Sitzer851e9c02018-12-04 19:40:08 +0100149
150def dec_act(twohexbytes):
151 act_list = [
152 {'bit': 15, 'name': "UTRAN"},
153 {'bit': 14, 'name': "E-UTRAN"},
154 {'bit': 7, 'name': "GSM"},
155 {'bit': 6, 'name': "GSM COMPACT"},
156 {'bit': 5, 'name': "cdma2000 HRPD"},
157 {'bit': 4, 'name': "cdma2000 1xRTT"},
158 ]
159 ia = h2i(twohexbytes)
160 u16t = (ia[0] << 8)|ia[1]
161 sel = []
162 for a in act_list:
163 if u16t & (1 << a['bit']):
164 sel.append(a['name'])
165 return sel
166
167def dec_xplmn_w_act(fivehexbytes):
168 res = {'mcc': 0, 'mnc': 0, 'act': []}
169 plmn_chars = 6
170 act_chars = 4
171 plmn_str = fivehexbytes[:plmn_chars] # first three bytes (six ascii hex chars)
172 act_str = fivehexbytes[plmn_chars:plmn_chars + act_chars] # two bytes after first three bytes
173 res['mcc'] = dec_mcc_from_plmn(plmn_str)
174 res['mnc'] = dec_mnc_from_plmn(plmn_str)
175 res['act'] = dec_act(act_str)
176 return res
177
178def format_xplmn_w_act(hexstr):
179 s = ""
180 for rec_data in hexstr_to_fivebytearr(hexstr):
181 rec_info = dec_xplmn_w_act(rec_data)
182 if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
183 rec_str = "unused"
184 else:
Supreeth Herled24f1632019-11-30 10:37:09 +0100185 rec_str = "MCC: %03d MNC: %03d AcT: %s" % (rec_info['mcc'], rec_info['mnc'], ", ".join(rec_info['act']))
Daniel Laszlo Sitzer851e9c02018-12-04 19:40:08 +0100186 s += "\t%s # %s\n" % (rec_data, rec_str)
187 return s
188
Sebastian Vivianie61170c2020-06-03 08:57:00 +0100189def dec_loci(hexstr):
190 res = {'tmsi': '', 'mcc': 0, 'mnc': 0, 'lac': '', 'status': 0}
191 res['tmsi'] = hexstr[:8]
192 res['mcc'] = dec_mcc_from_plmn(hexstr[8:14])
193 res['mnc'] = dec_mnc_from_plmn(hexstr[8:14])
194 res['lac'] = hexstr[14:18]
195 res['status'] = h2i(hexstr[20:22])
196 return res
197
198def dec_psloci(hexstr):
199 res = {'p-tmsi': '', 'p-tmsi-sig': '', 'mcc': 0, 'mnc': 0, 'lac': '', 'rac': '', 'status': 0}
200 res['p-tmsi'] = hexstr[:8]
201 res['p-tmsi-sig'] = hexstr[8:14]
202 res['mcc'] = dec_mcc_from_plmn(hexstr[14:20])
203 res['mnc'] = dec_mnc_from_plmn(hexstr[14:20])
204 res['lac'] = hexstr[20:24]
205 res['rac'] = hexstr[24:26]
206 res['status'] = h2i(hexstr[26:28])
207 return res
208
209def dec_epsloci(hexstr):
210 res = {'guti': '', 'mcc': 0, 'mnc': 0, 'tac': '', 'status': 0}
211 res['guti'] = hexstr[:24]
212 res['tai'] = hexstr[24:34]
213 res['mcc'] = dec_mcc_from_plmn(hexstr[24:30])
214 res['mnc'] = dec_mnc_from_plmn(hexstr[24:30])
215 res['tac'] = hexstr[30:34]
216 res['status'] = h2i(hexstr[34:36])
217 return res
218
Harald Welteca673942020-06-03 15:19:40 +0200219def dec_xplmn(threehexbytes):
220 res = {'mcc': 0, 'mnc': 0, 'act': []}
221 plmn_chars = 6
222 plmn_str = threehexbytes[:plmn_chars] # first three bytes (six ascii hex chars)
223 res['mcc'] = dec_mcc_from_plmn(plmn_str)
224 res['mnc'] = dec_mnc_from_plmn(plmn_str)
225 return res
226
227def format_xplmn(hexstr):
228 s = ""
229 for rec_data in hexstr_to_threebytearr(hexstr):
230 rec_info = dec_xplmn(rec_data)
231 if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
232 rec_str = "unused"
233 else:
234 rec_str = "MCC: %03d MNC: %03d" % (rec_info['mcc'], rec_info['mnc'])
235 s += "\t%s # %s\n" % (rec_data, rec_str)
236 return s
237
Alexander Chemeris19fffa12018-01-11 13:06:43 +0900238def derive_milenage_opc(ki_hex, op_hex):
239 """
240 Run the milenage algorithm to calculate OPC from Ki and OP
241 """
242 from Crypto.Cipher import AES
243 from Crypto.Util.strxor import strxor
244 from pySim.utils import b2h
245
246 # We pass in hex string and now need to work on bytes
247 aes = AES.new(h2b(ki_hex))
248 opc_bytes = aes.encrypt(h2b(op_hex))
249 return b2h(strxor(opc_bytes, h2b(op_hex)))
250
251def calculate_luhn(cc):
252 """
253 Calculate Luhn checksum used in e.g. ICCID and IMEI
254 """
255 num = map(int, str(cc))
256 check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
257 return 0 if check_digit == 10 else check_digit
Philipp Maier7592eee2019-09-12 13:03:23 +0200258
259def mcc_from_imsi(imsi):
260 """
261 Derive the MCC (Mobile Country Code) from the first three digits of an IMSI
262 """
263 if imsi == None:
264 return None
265
266 if len(imsi) > 3:
267 return imsi[:3]
268 else:
269 return None
270
271def mnc_from_imsi(imsi, long=False):
272 """
273 Derive the MNC (Mobile Country Code) from the 4th to 6th digit of an IMSI
274 """
275 if imsi == None:
276 return None
277
278 if len(imsi) > 3:
279 if long:
280 return imsi[3:6]
281 else:
282 return imsi[3:5]
283 else:
284 return None
Supreeth Herled24f1632019-11-30 10:37:09 +0100285
286def derive_mcc(digit1, digit2, digit3):
287 """
288 Derive decimal representation of the MCC (Mobile Country Code)
289 from three given digits.
290 """
291
292 mcc = 0
293
294 if digit1 != 0x0f:
295 mcc += digit1 * 100
296 if digit2 != 0x0f:
297 mcc += digit2 * 10
298 if digit3 != 0x0f:
299 mcc += digit3
300
301 return mcc
302
303def derive_mnc(digit1, digit2, digit3=0x0f):
304 """
305 Derive decimal representation of the MNC (Mobile Network Code)
306 from two or (optionally) three given digits.
307 """
308
309 mnc = 0
310
311 # 3-rd digit is optional for the MNC. If present
312 # the algorythm is the same as for the MCC.
313 if digit3 != 0x0f:
314 return derive_mcc(digit1, digit2, digit3)
315
316 if digit1 != 0x0f:
317 mnc += digit1 * 10
318 if digit2 != 0x0f:
319 mnc += digit2
320
321 return mnc
Supreeth Herle4b1c7632019-12-22 09:00:59 +0100322
323def dec_msisdn(ef_msisdn):
324 """
325 Decode MSISDN from EF.MSISDN or EF.ADN (same structure).
326 See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
327 """
328
329 # Convert from str to (kind of) 'bytes'
330 ef_msisdn = h2b(ef_msisdn)
331
332 # Make sure mandatory fields are present
333 if len(ef_msisdn) < 14:
334 raise ValueError("EF.MSISDN is too short")
335
336 # Skip optional Alpha Identifier
337 xlen = len(ef_msisdn) - 14
338 msisdn_lhv = ef_msisdn[xlen:]
339
340 # Parse the length (in bytes) of the BCD encoded number
341 bcd_len = ord(msisdn_lhv[0])
342 # BCD length = length of dial num (max. 10 bytes) + 1 byte ToN and NPI
343 if bcd_len == 0xff:
344 return None
345 elif bcd_len > 11 or bcd_len < 1:
346 raise ValueError("Length of MSISDN (%d bytes) is out of range" % bcd_len)
347
348 # Parse ToN / NPI
349 ton = (ord(msisdn_lhv[1]) >> 4) & 0x07
350 npi = ord(msisdn_lhv[1]) & 0x0f
351 bcd_len -= 1
352
353 # No MSISDN?
354 if not bcd_len:
355 return (npi, ton, None)
356
357 msisdn = swap_nibbles(b2h(msisdn_lhv[2:][:bcd_len])).rstrip('f')
358 # International number 10.5.118/3GPP TS 24.008
Vadim Yanitskiy7ba24282020-02-27 00:04:13 +0700359 if ton == 0x01:
Supreeth Herle4b1c7632019-12-22 09:00:59 +0100360 msisdn = '+' + msisdn
361
362 return (npi, ton, msisdn)
Supreeth Herle5a541012019-12-22 08:59:16 +0100363
364def enc_msisdn(msisdn, npi=0x01, ton=0x03):
365 """
366 Encode MSISDN as LHV so it can be stored to EF.MSISDN.
367 See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
368
369 Default NPI / ToN values:
370 - NPI: ISDN / telephony numbering plan (E.164 / E.163),
371 - ToN: network specific or international number (if starts with '+').
372 """
373
374 # Leading '+' indicates International Number
375 if msisdn[0] == '+':
376 msisdn = msisdn[1:]
377 ton = 0x01
378
379 # Append 'f' padding if number of digits is odd
380 if len(msisdn) % 2 > 0:
381 msisdn += 'f'
382
383 # BCD length also includes NPI/ToN header
384 bcd_len = len(msisdn) // 2 + 1
385 npi_ton = (npi & 0x0f) | ((ton & 0x07) << 4) | 0x80
386 bcd = rpad(swap_nibbles(msisdn), 10 * 2) # pad to 10 octets
387
388 return ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd
Supreeth Herle441c4a72020-03-24 10:19:15 +0100389
Supreeth Herle0c4d82d2020-04-20 13:28:31 +0200390def dec_st(st, table="sim"):
391 """
392 Parses the EF S/U/IST and prints the list of available services in EF S/U/IST
393 """
394
Supreeth Herledf330372020-04-20 14:48:55 +0200395 if table == "isim":
396 from pySim.ts_31_103 import EF_IST_map
397 lookup_map = EF_IST_map
398 elif table == "usim":
Supreeth Herle0c4d82d2020-04-20 13:28:31 +0200399 from pySim.ts_31_102 import EF_UST_map
400 lookup_map = EF_UST_map
401 else:
402 from pySim.ts_51_011 import EF_SST_map
403 lookup_map = EF_SST_map
404
405 st_bytes = [st[i:i+2] for i in range(0, len(st), 2) ]
406
407 avail_st = ""
408 # Get each byte and check for available services
409 for i in range(0, len(st_bytes)):
410 # Byte i contains info about Services num (8i+1) to num (8i+8)
411 byte = int(st_bytes[i], 16)
412 # Services in each byte are in order MSB to LSB
413 # MSB - Service (8i+8)
414 # LSB - Service (8i+1)
415 for j in range(1, 9):
416 if byte&0x01 == 0x01 and ((8*i) + j in lookup_map):
417 # Byte X contains info about Services num (8X-7) to num (8X)
418 # bit = 1: service available
419 # bit = 0: service not available
420 avail_st += '\tService %d - %s\n' % ((8*i) + j, lookup_map[(8*i) + j])
421 byte = byte >> 1
422 return avail_st
Supreeth Herle98370552020-05-11 09:04:41 +0200423
424def first_TLV_parser(bytelist):
425 '''
426 first_TLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00]) -> (170, 2, [171, 205])
427
428 parses first TLV format record in a list of bytelist
429 returns a 3-Tuple: Tag, Length, Value
430 Value is a list of bytes
431 parsing of length is ETSI'style 101.220
432 '''
433 Tag = bytelist[0]
434 if bytelist[1] == 0xFF:
435 Len = bytelist[2]*256 + bytelist[3]
436 Val = bytelist[4:4+Len]
437 else:
438 Len = bytelist[1]
439 Val = bytelist[2:2+Len]
440 return (Tag, Len, Val)
441
442def TLV_parser(bytelist):
443 '''
444 TLV_parser([0xAA, ..., 0xFF]) -> [(T, L, [V]), (T, L, [V]), ...]
445
446 loops on the input list of bytes with the "first_TLV_parser()" function
447 returns a list of 3-Tuples
448 '''
449 ret = []
450 while len(bytelist) > 0:
451 T, L, V = first_TLV_parser(bytelist)
452 if T == 0xFF:
453 # padding bytes
454 break
455 ret.append( (T, L, V) )
456 # need to manage length of L
457 if L > 0xFE:
458 bytelist = bytelist[ L+4 : ]
459 else:
460 bytelist = bytelist[ L+2 : ]
461 return ret
Supreeth Herled572ede2020-03-22 09:55:04 +0100462
463def dec_epdgid(hexstr):
464 """
465 Decode ePDG Id to get EF.ePDGId or EF.ePDGIdEm.
466 See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.102 and 4.2.104.
467 """
468
469 # Convert from hex str to int bytes list
470 epdgid_bytes = h2i(hexstr)
471
472 s = ""
473
474 # Get list of tuples containing parsed TLVs
475 tlvs = TLV_parser(epdgid_bytes)
476
477 for tlv in tlvs:
478 # tlv = (T, L, [V])
479 # T = Tag
480 # L = Length
481 # [V] = List of value
482
483 # Invalid Tag value scenario
484 if tlv[0] != 0x80:
485 continue
486
Supreeth Herled6a5ec52020-06-01 12:27:51 +0200487 # Empty field - Zero length
488 if tlv[1] == 0:
489 continue
490
Supreeth Herled572ede2020-03-22 09:55:04 +0100491 # First byte in the value has the address type
492 addr_type = tlv[2][0]
493 # TODO: Support parsing of IPv4 and IPv6
494 if addr_type == 0x00: #FQDN
495 # Skip address tye byte i.e. first byte in value list
496 content = tlv[2][1:]
497 s += "\t%s # %s\n" % (i2h(content), i2s(content))
498
499 return s
Philipp Maierff84c232020-05-12 17:24:18 +0200500
Supreeth Herle3c0bd7a2020-03-23 11:59:33 +0100501def enc_epdgid(epdg_addr, addr_type='00'):
502 """
503 Encode ePDG Id so it can be stored to EF.ePDGId or EF.ePDGIdEm.
504 See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.102 and 4.2.104.
505
506 Default values:
507 - addr_type: 00 - FQDN format of ePDG Address
508 """
509
510 s = ""
511
512 # TODO: Encoding of IPv4 and IPv6 address
513 if addr_type == '00':
514 hex_str = s2h(epdg_addr)
515 s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str
516
517 return s
518
Philipp Maiere8536c02020-05-11 21:35:01 +0200519def sanitize_pin_adm(opts):
520 """
521 The ADM pin can be supplied either in its hexadecimal form or as
522 ascii string. This function checks the supplied opts parameter and
523 returns the pin_adm as hex encoded string, regardles in which form
524 it was originally supplied by the user
525 """
526
527 pin_adm = None
528
529 if opts.pin_adm is not None:
530 if len(opts.pin_adm) <= 8:
531 pin_adm = ''.join(['%02x'%(ord(x)) for x in opts.pin_adm])
532 pin_adm = rpad(pin_adm, 16)
533
534 else:
535 raise ValueError("PIN-ADM needs to be <=8 digits (ascii)")
536
537 if opts.pin_adm_hex is not None:
538 if len(opts.pin_adm_hex) == 16:
539 pin_adm = opts.pin_adm_hex
540 # Ensure that it's hex-encoded
541 try:
542 try_encode = h2b(pin_adm)
543 except ValueError:
544 raise ValueError("PIN-ADM needs to be hex encoded using this option")
545 else:
546 raise ValueError("PIN-ADM needs to be exactly 16 digits (hex encoded)")
547
548 return pin_adm
549
Philipp Maierff84c232020-05-12 17:24:18 +0200550def init_reader(opts):
551 """
552 Init card reader driver
553 """
554 if opts.pcsc_dev is not None:
555 print("Using PC/SC reader interface")
556 from pySim.transport.pcsc import PcscSimLink
557 sl = PcscSimLink(opts.pcsc_dev)
558 elif opts.osmocon_sock is not None:
559 print("Using Calypso-based (OsmocomBB) reader interface")
560 from pySim.transport.calypso import CalypsoSimLink
561 sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
Vadim Yanitskiy29ca8042020-05-09 21:23:37 +0700562 elif opts.modem_dev is not None:
563 print("Using modem for Generic SIM Access (3GPP TS 27.007)")
564 from pySim.transport.modem_atcmd import ModemATCommandLink
565 sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud)
Philipp Maierff84c232020-05-12 17:24:18 +0200566 else: # Serial reader is default
567 print("Using serial reader interface")
568 from pySim.transport.serial import SerialSimLink
569 sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
570
571 return sl