mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-16 18:38:32 +03:00
WIP
Change-Id: Id3ae902ffb0a25fb69e2ebb469f925b7482f8d26
This commit is contained in:
34
ota_test.py
34
ota_test.py
@@ -46,6 +46,25 @@ OTA_KEYSET_SJA5_AES128 = OtaKeyset(algo_crypt='aes_cbc', kic_idx=2,
|
|||||||
kic=h2b('200102030405060708090a0b0c0d0e0f'),
|
kic=h2b('200102030405060708090a0b0c0d0e0f'),
|
||||||
kid=h2b('201102030405060708090a0b0c0d0e0f'))
|
kid=h2b('201102030405060708090a0b0c0d0e0f'))
|
||||||
|
|
||||||
|
# TS.48 profile on sysmoEUICC1-C2G
|
||||||
|
OTA_KEYSET_C2G_AES128 = OtaKeyset(algo_crypt='aes_cbc', kic_idx=2,
|
||||||
|
algo_auth='aes_cmac', kid_idx=2,
|
||||||
|
kic=h2b('66778899AABBCCDD1122334455EEFF10'),
|
||||||
|
kid=h2b('112233445566778899AABBCCDDEEFF10'))
|
||||||
|
|
||||||
|
|
||||||
|
# ISD-R on sysmoEUICC1-C2G
|
||||||
|
OTA_KEYSET_C2G_AES128_ISDR = OtaKeyset(algo_crypt='aes_cbc', kic_idx=1,
|
||||||
|
algo_auth='aes_cmac', kid_idx=1,
|
||||||
|
kic=h2b('B52F9C5938D1C19ED73E1AE772937FD7'),
|
||||||
|
kid=h2b('3BC696ACD1EEC95A6624F7330D22FC81'))
|
||||||
|
|
||||||
|
# ISD-A on sysmoEUICC1-C2G
|
||||||
|
OTA_KEYSET_C2G_AES128_ISDA = OtaKeyset(algo_crypt='aes_cbc', kic_idx=1,
|
||||||
|
algo_auth='aes_cmac', kid_idx=1,
|
||||||
|
kic=h2b('8DAAD1DAAA8D7C9000E3BBED8B7556E7'),
|
||||||
|
kid=h2b('5392D503AE050DDEAF81AFAEFF275A2B'))
|
||||||
|
|
||||||
# TODO: AES192
|
# TODO: AES192
|
||||||
# TODO: AES256
|
# TODO: AES256
|
||||||
|
|
||||||
@@ -87,11 +106,12 @@ testcases = [
|
|||||||
'encoded_resp': '027100000e0ab0001100000000000000016132',
|
'encoded_resp': '027100000e0ab0001100000000000000016132',
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
'name': 'AES128-SJA5-CIPHERED-CC',
|
'name': 'AES128-C2G-CIPHERED-CC',
|
||||||
'ota_keyset': OTA_KEYSET_SJA5_AES128,
|
'ota_keyset': OTA_KEYSET_C2G_AES128_ISDR,
|
||||||
'spi': SPI_CC_POR_CIPHERED_CC,
|
'spi': SPI_CC_POR_CIPHERED_CC,
|
||||||
'request': {
|
'request': {
|
||||||
'apdu': b'\x00\xa4\x00\x04\x02\x3f\x00',
|
#'apdu': b'\x00\xa4\x00\x04\x02\x3f\x00',
|
||||||
|
'apdu': h2b('80ec800300'),
|
||||||
'encoded_cmd': '00281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058',
|
'encoded_cmd': '00281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058',
|
||||||
'encoded_tpdu': '400881214365877ff6227052000000000302700000281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058',
|
'encoded_tpdu': '400881214365877ff6227052000000000302700000281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058',
|
||||||
},
|
},
|
||||||
@@ -109,12 +129,14 @@ for t in testcases:
|
|||||||
# RAM: B00000
|
# RAM: B00000
|
||||||
# SIM RFM: B00010
|
# SIM RFM: B00010
|
||||||
# USIM RFM: B00011
|
# USIM RFM: B00011
|
||||||
tar = h2b('B00011')
|
# ISD-R: 000001
|
||||||
|
# ECASD: 000002
|
||||||
|
tar = h2b('000001')
|
||||||
|
|
||||||
dialect = OtaDialectSms()
|
dialect = OtaDialectSms()
|
||||||
outp = dialect.encode_cmd(od, tar, t['spi'], apdu=t['request']['apdu'])
|
outp = dialect.encode_cmd(od, tar, t['spi'], apdu=t['request']['apdu'])
|
||||||
print("result: %s" % b2h(outp))
|
print("result: %s" % b2h(outp))
|
||||||
assert(b2h(outp) == t['request']['encoded_cmd'])
|
#assert(b2h(outp) == t['request']['encoded_cmd'])
|
||||||
|
|
||||||
with_udh = b'\x02\x70\x00' + outp
|
with_udh = b'\x02\x70\x00' + outp
|
||||||
print("with_udh: %s" % b2h(with_udh))
|
print("with_udh: %s" % b2h(with_udh))
|
||||||
@@ -126,7 +148,7 @@ for t in testcases:
|
|||||||
tpdu = SMS_DELIVER(tp_udhi=True, tp_oa=da, tp_pid=0x7F, tp_dcs=0xF6, tp_scts=h2b('22705200000000'), tp_udl=3, tp_ud=with_udh)
|
tpdu = SMS_DELIVER(tp_udhi=True, tp_oa=da, tp_pid=0x7F, tp_dcs=0xF6, tp_scts=h2b('22705200000000'), tp_udl=3, tp_ud=with_udh)
|
||||||
print("TPDU: %s" % tpdu)
|
print("TPDU: %s" % tpdu)
|
||||||
print("tpdu: %s" % b2h(tpdu.to_bytes()))
|
print("tpdu: %s" % b2h(tpdu.to_bytes()))
|
||||||
assert(b2h(tpdu.to_bytes()) == t['request']['encoded_tpdu'])
|
#assert(b2h(tpdu.to_bytes()) == t['request']['encoded_tpdu'])
|
||||||
|
|
||||||
r = dialect.decode_resp(od, t['spi'], t['response']['encoded_resp'])
|
r = dialect.decode_resp(od, t['spi'], t['response']['encoded_resp'])
|
||||||
print("RESP: ", r)
|
print("RESP: ", r)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from pySim.exceptions import SwMatchError
|
|||||||
# CardModel is created, which will add the ATR-based matching and
|
# CardModel is created, which will add the ATR-based matching and
|
||||||
# calling of SysmocomSJA2.add_files. See CardModel.apply_matching_models
|
# calling of SysmocomSJA2.add_files. See CardModel.apply_matching_models
|
||||||
import pySim.sysmocom_sja2
|
import pySim.sysmocom_sja2
|
||||||
|
import pySim.sysmocom_euicc1
|
||||||
|
|
||||||
# we need to import these modules so that the various sub-classes of
|
# we need to import these modules so that the various sub-classes of
|
||||||
# CardProfile are created, which will be used in init_card() to iterate
|
# CardProfile are created, which will be used in init_card() to iterate
|
||||||
|
|||||||
14
pySim/ota.py
14
pySim/ota.py
@@ -302,7 +302,7 @@ class OtaAlgoAuthDES3(OtaAlgoAuth):
|
|||||||
class OtaAlgoCryptAES(OtaAlgoCrypt):
|
class OtaAlgoCryptAES(OtaAlgoCrypt):
|
||||||
name = 'AES'
|
name = 'AES'
|
||||||
enum_name = 'aes_cbc'
|
enum_name = 'aes_cbc'
|
||||||
blocksize = 16 # TODO: is this needed?
|
blocksize = 16
|
||||||
def _encrypt(self, data:bytes) -> bytes:
|
def _encrypt(self, data:bytes) -> bytes:
|
||||||
cipher = AES.new(self.otak.kic, AES.MODE_CBC, self.iv)
|
cipher = AES.new(self.otak.kic, AES.MODE_CBC, self.iv)
|
||||||
return cipher.encrypt(data)
|
return cipher.encrypt(data)
|
||||||
@@ -356,20 +356,20 @@ class OtaDialectSms(OtaDialect):
|
|||||||
|
|
||||||
# CHL + SPI (+ KIC + KID)
|
# CHL + SPI (+ KIC + KID)
|
||||||
part_head = self.hdr_construct.build({'chl': chl, 'spi':spi, 'kic':kic, 'kid':kid, 'tar':tar})
|
part_head = self.hdr_construct.build({'chl': chl, 'spi':spi, 'kic':kic, 'kid':kid, 'tar':tar})
|
||||||
#print("part_head: %s" % b2h(part_head))
|
print("part_head: %s" % b2h(part_head))
|
||||||
|
|
||||||
# CNTR + PCNTR (CNTR not used)
|
# CNTR + PCNTR (CNTR not used)
|
||||||
part_cnt = otak.cntr.to_bytes(5, 'big') + pad_cnt.to_bytes(1, 'big')
|
part_cnt = otak.cntr.to_bytes(5, 'big') + pad_cnt.to_bytes(1, 'big')
|
||||||
#print("part_cnt: %s" % b2h(part_cnt))
|
print("part_cnt: %s" % b2h(part_cnt))
|
||||||
|
|
||||||
envelope_data = part_head + part_cnt + apdu
|
envelope_data = part_head + part_cnt + apdu
|
||||||
#print("envelope_data: %s" % b2h(envelope_data))
|
print("envelope_data: %s" % b2h(envelope_data))
|
||||||
|
|
||||||
# 2-byte CPL. CPL is part of RC/CC/CPI to end of secured data, including any padding for ciphering
|
# 2-byte CPL. CPL is part of RC/CC/CPI to end of secured data, including any padding for ciphering
|
||||||
# CPL from and including CPI to end of secured data, including any padding for ciphering
|
# CPL from and including CPI to end of secured data, including any padding for ciphering
|
||||||
cpl = len(envelope_data) + len_sig
|
cpl = len(envelope_data) + len_sig
|
||||||
envelope_data = cpl.to_bytes(2, 'big') + envelope_data
|
envelope_data = cpl.to_bytes(2, 'big') + envelope_data
|
||||||
#print("envelope_data with cpl: %s" % b2h(envelope_data))
|
print("envelope_data with cpl: %s" % b2h(envelope_data))
|
||||||
|
|
||||||
if spi['rc_cc_ds'] == 'cc':
|
if spi['rc_cc_ds'] == 'cc':
|
||||||
cc = otak.auth.sign(envelope_data)
|
cc = otak.auth.sign(envelope_data)
|
||||||
@@ -383,7 +383,7 @@ class OtaDialectSms(OtaDialect):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Invalid rc_cc_ds: %s" % spi['rc_cc_ds'])
|
raise ValueError("Invalid rc_cc_ds: %s" % spi['rc_cc_ds'])
|
||||||
|
|
||||||
#print("envelope_data with sig: %s" % b2h(envelope_data))
|
print("envelope_data with sig: %s" % b2h(envelope_data))
|
||||||
|
|
||||||
# encrypt as needed
|
# encrypt as needed
|
||||||
if spi['ciphering']: # ciphering is requested
|
if spi['ciphering']: # ciphering is requested
|
||||||
@@ -395,7 +395,7 @@ class OtaDialectSms(OtaDialect):
|
|||||||
else:
|
else:
|
||||||
envelope_data = part_head + envelope_data
|
envelope_data = part_head + envelope_data
|
||||||
|
|
||||||
#print("envelope_data: %s" % b2h(envelope_data))
|
print("envelope_data: %s" % b2h(envelope_data))
|
||||||
|
|
||||||
if len(envelope_data) > 140:
|
if len(envelope_data) > 140:
|
||||||
raise ValueError('Cannot encode command in a single SMS; Fragmentation not implemented')
|
raise ValueError('Cannot encode command in a single SMS; Fragmentation not implemented')
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class Foo:
|
|||||||
self.tar = h2b('000001') # ISD-R according to Annex H of SGP.02
|
self.tar = h2b('000001') # ISD-R according to Annex H of SGP.02
|
||||||
#self.tar = h2b('000002') # ECASD according to Annex H of SGP.02
|
#self.tar = h2b('000002') # ECASD according to Annex H of SGP.02
|
||||||
|
|
||||||
if True:
|
if False:
|
||||||
KIC1 = h2b('4BE2D58A1FA7233DD723B3C70996E6E6')
|
KIC1 = h2b('4BE2D58A1FA7233DD723B3C70996E6E6')
|
||||||
KID1 = h2b('4a664208eba091d32c4ecbc299da1f34')
|
KID1 = h2b('4a664208eba091d32c4ecbc299da1f34')
|
||||||
self.ota_keyset = OtaKeyset(algo_crypt='triple_des_cbc2', kic_idx=1, kic=KIC1,
|
self.ota_keyset = OtaKeyset(algo_crypt='triple_des_cbc2', kic_idx=1, kic=KIC1,
|
||||||
@@ -67,6 +67,14 @@ class Foo:
|
|||||||
#self.tar = h2b('B00011') # USIM RFM
|
#self.tar = h2b('B00011') # USIM RFM
|
||||||
self.tar = h2b('000000') # RAM
|
self.tar = h2b('000000') # RAM
|
||||||
|
|
||||||
|
if True: # sysmoEUICC1-C2G
|
||||||
|
KIC1 = h2b('B52F9C5938D1C19ED73E1AE772937FD7')
|
||||||
|
KID1 = h2b('3BC696ACD1EEC95A6624F7330D22FC81')
|
||||||
|
self.ota_keyset = OtaKeyset(algo_crypt='aes_cbc', kic_idx=1, kic=KIC1,
|
||||||
|
algo_auth='aes_cmac', kid_idx=1, kid=KID1)
|
||||||
|
self.tar = h2b('000001') # ISD-R according to Annex H of SGP.02
|
||||||
|
#self.tar = h2b('000002') # ECASD according to Annex H of SGP.02
|
||||||
|
|
||||||
self.ota_dialect = OtaDialectSms()
|
self.ota_dialect = OtaDialectSms()
|
||||||
self.spi = {'counter':'no_counter', 'ciphering':True, 'rc_cc_ds': 'cc', 'por_in_submit':False,
|
self.spi = {'counter':'no_counter', 'ciphering':True, 'rc_cc_ds': 'cc', 'por_in_submit':False,
|
||||||
'por_shall_be_ciphered':True, 'por_rc_cc_ds': 'cc', 'por': 'por_required'}
|
'por_shall_be_ciphered':True, 'por_rc_cc_ds': 'cc', 'por': 'por_required'}
|
||||||
|
|||||||
Reference in New Issue
Block a user