Change-Id: Id3ae902ffb0a25fb69e2ebb469f925b7482f8d26
This commit is contained in:
Harald Welte
2024-05-12 14:05:01 +02:00
parent ad9c01f1c1
commit d45123f6ac
4 changed files with 45 additions and 14 deletions

View File

@@ -46,6 +46,25 @@ OTA_KEYSET_SJA5_AES128 = OtaKeyset(algo_crypt='aes_cbc', kic_idx=2,
kic=h2b('200102030405060708090a0b0c0d0e0f'),
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: AES256
@@ -87,11 +106,12 @@ testcases = [
'encoded_resp': '027100000e0ab0001100000000000000016132',
}
}, {
'name': 'AES128-SJA5-CIPHERED-CC',
'ota_keyset': OTA_KEYSET_SJA5_AES128,
'name': 'AES128-C2G-CIPHERED-CC',
'ota_keyset': OTA_KEYSET_C2G_AES128_ISDR,
'spi': SPI_CC_POR_CIPHERED_CC,
'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_tpdu': '400881214365877ff6227052000000000302700000281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058',
},
@@ -109,12 +129,14 @@ for t in testcases:
# RAM: B00000
# SIM RFM: B00010
# USIM RFM: B00011
tar = h2b('B00011')
# ISD-R: 000001
# ECASD: 000002
tar = h2b('000001')
dialect = OtaDialectSms()
outp = dialect.encode_cmd(od, tar, t['spi'], apdu=t['request']['apdu'])
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
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)
print("TPDU: %s" % tpdu)
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'])
print("RESP: ", r)

View File

@@ -31,6 +31,7 @@ from pySim.exceptions import SwMatchError
# CardModel is created, which will add the ATR-based matching and
# calling of SysmocomSJA2.add_files. See CardModel.apply_matching_models
import pySim.sysmocom_sja2
import pySim.sysmocom_euicc1
# 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

View File

@@ -302,7 +302,7 @@ class OtaAlgoAuthDES3(OtaAlgoAuth):
class OtaAlgoCryptAES(OtaAlgoCrypt):
name = 'AES'
enum_name = 'aes_cbc'
blocksize = 16 # TODO: is this needed?
blocksize = 16
def _encrypt(self, data:bytes) -> bytes:
cipher = AES.new(self.otak.kic, AES.MODE_CBC, self.iv)
return cipher.encrypt(data)
@@ -356,20 +356,20 @@ class OtaDialectSms(OtaDialect):
# CHL + SPI (+ KIC + KID)
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)
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
#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
# CPL from and including CPI to end of secured data, including any padding for ciphering
cpl = len(envelope_data) + len_sig
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':
cc = otak.auth.sign(envelope_data)
@@ -383,7 +383,7 @@ class OtaDialectSms(OtaDialect):
else:
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
if spi['ciphering']: # ciphering is requested
@@ -395,7 +395,7 @@ class OtaDialectSms(OtaDialect):
else:
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:
raise ValueError('Cannot encode command in a single SMS; Fragmentation not implemented')

View File

@@ -55,7 +55,7 @@ class Foo:
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
if True:
if False:
KIC1 = h2b('4BE2D58A1FA7233DD723B3C70996E6E6')
KID1 = h2b('4a664208eba091d32c4ecbc299da1f34')
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('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.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'}