1.1.4 高级主题
通过 CardKeyProvider 检索卡特定密钥
当处理一批卡片或多个卡片时,手动检索卡片特定的 PIN(如 ADM1)或密钥材料(如 SCP02/SCP03 密钥)将是一项繁重的工作。
为了提高这方面的工作效率,pySim 引入了一个名为 CardKeyProvider 的概念。这是一个通用机制,允许 pySim[-shell] 代码的不同部分通过数据源(提供者)程序化地请求卡特定的密钥材料。
例如,当您使用 verify_adm 命令验证 ADM1 PIN 而不提供 ADM1 值时,pySim-shell 将通过 CardKeyProvider 请求与卡片 ICCID 相关的 ADM1 值。
理论上可以有多个不同的 CardKeyProvider。例如,您可以开发自己的 CardKeyProvider,用于查询数据库中的密钥材料,或者使用密钥派生函数从全局主密钥派生出卡特定的密钥材料。
pySim 中包含的唯一实际 CardKeyProvider 实现是 CardKeyProviderCsv,它从一个[可能加密的] CSV 文件中检索密钥材料。
CardKeyProviderCsv
CardKeyProviderCsv 允许您从可由 pySim 访问的 CSV(逗号分隔值)文件中检索卡特定的密钥材料。
CSV 文件必须具有预期的列名,例如,如果您想使用该 CSV 文件在使用 verify_adm 命令时获取特定于卡片的 ADM1 PIN,则需要 ICCID 和 ADM1 列。
您可以通过 pySim-shell 的 -csv
命令行选项指定要使用的 CSV 文件。如果您没有指定 CSV 文件,pySim 将尝试从默认位置 ~/.osmocom/pysim/card_data.csv
打开一个 CSV 文件(如果存在)。
列级 CSV 加密
pySim 支持列级 CSV 加密。此功能确保您的密钥材料不会以明文形式存储在 CSV 文件中。
加密机制使用 AES 的 CBC 模式。您可以使用 AES 允许的任何密钥长度(128/192/256 位)。
根据 GSMA FS.28,加密是在列级别上工作的。这意味着不同的列可以使用不同的密钥材料进行解密。这意味着泄露某一列的加密密钥不会危及可能存储在其他列中的各种其他密钥。
您可以使用 -csv-column-key
命令行参数指定列级解密密钥。语法是 FIELD:AES_KEY_HEX,例如:
取消自动换行
复制
pySim-shell.py –csv-column-key SCP03_ENC_ISDR:000102030405060708090a0b0c0d0e0f
为了避免在密钥集内一组密钥的每个列中重复列密钥,存在预定义的列组别名,这将确保指定的密钥将被所有列使用:
- UICC_SCP02 是 UICC_SCP02_KIC1、UICC_SCP02_KID1、UICC_SCP02_KIK1 的组别名。
- UICC_SCP03 是 UICC_SCP03_KIC1、UICC_SCP03_KID1、UICC_SCP03_KIK1 的组别名。
- SCP03_ECASD 是 SCP03_ENC_ECASD、SCP03_MAC_ECASD、SCP03_DEK_ECASD 的组别名。
- SCP03_ISDA 是 SCP03_ENC_ISDA、SCP03_MAC_ISDA、SCP03_DEK_ISDA 的组别名。
- SCP03_ISDR 是 SCP03_ENC_ISDR、SCP03_MAC_ISDR、SCP03_DEK_ISDR 的组别名。
字段命名:
- 对于查找 UICC/SIM/USIM/ISIM 或 eSIM 配置文件特定的密钥材料,pySim 使用 ICCID 字段作为查找键。
- 对于查找 eUICC 特定的密钥材料(如 ISD-R 的 SCP03 密钥、ECASD),pySim 使用 EID 字段作为查找键。
一旦 CardKeyProviderCsv 在您的 CSV 中找到与 ICCID 或 EID 匹配的行(行),它就会查找包含所需数据的列。
ADM PIN
verify_adm 命令将尝试通过 SIM/UICC 的 ICCID 查找 ADM1 列。
SCP02 / SCP03
SCP02 和 SCP03 每个都使用由 ENC、MAC 和 DEK 密钥组成的密钥三元组。更多细节,请参阅适用的 GlobalPlatform 规范。
如果您不想手动为每个特定卡片输入密钥材料作为 establish_scp02 或 establish_scp03 命令的参数,您可以使用 -key-provider-suffix
选项。pySim 使用此后缀来组成 CardKeyProvider 的列名,如下所示:
- SCP02_ENC_ + 后缀用于 SCP02 加密密钥
- SCP02_MAC_ + 后缀用于 SCP02 MAC 密钥
- SCP02_DEK_ + 后缀用于 SCP02 DEK 密钥
- SCP03_ENC_ + 后缀用于 SCP03 加密密钥
- SCP03_MAC_ + 后缀用于 SCP03 MAC 密钥
- SCP03_DEK_ + 后缀用于 SCP03 DEK 密钥
例如,如果您使用的是 establish_scp03 –key-provider-suffix ISDR 命令,则密钥材料查找的列名分别是 SCP03_ENC_ISDR、SCP03_MAC_ISDR 和 SCP03_DEK_ISDR。
用于查找的标识符由安全域的定义决定。例如,eUICC ISD-R 和 ECASD 将使用 eUICC 的 EID。另一方面,eSIM 的 ISD-P 或 UICC 的 ISD 将使用 ICCID。
1.1.5 cmd2 基础
由于 pySim-shell 是基于 cmd2 构建的,因此它提供了一些通用的 cmd2 命令/功能。您可能想查看 cmd2 内置命令以了解这些内容。
1.1.6 pySim 命令
此类别中的命令是 pySim 特有的;它们并不与 ISO 7816 或 3GPP 命令一一对应。大多数命令将仅操作本地(内存中的)状态,或者执行一系列复杂的卡命令。
desc
显示当前选定文件的人类可读文件描述。
dir
显示当前选定 DF(专用文件)或 MF(主文件)中可用的文件列表。
命名参数:
--fids
显示文件标识符
默认值:False--names
显示文件名
默认值:False--apps
显示应用程序
默认值:False--all
显示所有可选择的标识符和名称
默认值:False
命名参数
--filename
仅导出特定文件--json
以 JSON 格式导出(可靠性较低)
默认值:False
请注意,export
命令是相对于当前工作目录工作的,所以如果你在 MF 中,那么导出将包含卡上所有已知的文件。然而,如果你在 ADF.ISIM 中,只有该 ADF 下的文件才会被包含在导出中。
此外,强烈建议首先输入 ADM1 PIN(使用 verify_adm
命令)以最大化读取所有/大多数文件的权限。
示例:
取消自动换行
复制
pySIM-shell (00:MF)> export --json > /tmp/export.json
EXCEPTION of type 'RuntimeError' occurred with message: 'unable to export 50 elementary
→file(s) and 2 dedicated file(s), also had to stop early due to exception:6e00: ARA-M -→Invalid class'
要启用完整的回溯,请运行以下命令:'set debug true'
pySIM-shell (00:MF)>
上述异常基本上是可以预料的。它仅仅意味着定义的 50 个文件(很可能是在某个后续的 3GPP 版本中作为可选文件)在卡上未找到,或者在尝试选择它们时被无效化/禁用了。
fsdump
导出当前 DF 下所有文件的文件系统元数据和文件内容,以机器可读的 JSON 格式。这与“export”类似,但对下游处理工具来说更容易解析。通常,您可能希望从 MF 调用此命令,并验证 ADM1 PIN(如果可用),以最大化可读文件的数量。
用法:fsdump [-h] [--filename FILENAME] [--json]
命名参数:
--filename
仅导出特定(命名)文件--json
以 JSON 格式导出文件内容(可靠性较低)
默认值:False
请注意,fsdump
是相对于当前工作目录工作的,所以如果你在 MF 中,那么导出将包含卡上所有已知的文件。然而,如果你在 ADF.ISIM 中,只有该 ADF 下的文件才会被包含在导出中。
此外,强烈建议首先输入 ADM1 PIN(使用 verify_adm
命令)以最大化读取所有/大多数文件的权限。
使用案例:要系统地分析两张卡内容之间的差异,你可以创建这两张卡的 fsdumps
,然后使用一些通用的 JSON 差异工具,比如 jycm –show
(参见 GitHub - eggachecat/jycm: A flexible json diff framework for minimalist.)。
示例:
取消自动换行
复制
pySIM-shell (00:MF)> fsdump > /tmp/fsdump.json
pySIM-shell (00:MF)>
显示卡文件系统树
显示卡文件系统的树状结构非常重要,需要注意的是,这显示的是基于卡配置可能存在的文件树。要确定给定文件是否真的存在于特定卡上,您必须尝试选择该文件。
verify_adm
验证指定的管理员 PIN(ADM PIN),通常需要此操作以获得对 SIM 卡上大多数文件的写入/更新权限。
用法:verify_adm [-h] [--pin-is-hex] [--adm-type {ADM1,ADM2,ADM3,ADM4,ADM5,ADM6,ADM7,ADM8,ADM9,ADM10}] [ADM]
位置参数
ADM
:管理员 PIN 值。如果未提供,则会查询 CSV 文件。
命名参数
--pin-is-hex
:将 ADM PIN 值指定为十六进制字符串(非十进制)。
默认值:False--adm-type
:可能的选择:ADM1, ADM2, ADM3, ADM4, ADM5, ADM6, ADM7, ADM8, ADM9, ADM10。
覆盖 ADM 编号。默认是卡型号特定的,通常是 1。
成功示例:
取消自动换行
复制
pySIM-shell (00:MF)> verify_adm 11111111
pySIM-shell (00:MF)>
在上述情况下,管理员 PIN 成功验证。请始终确保使用您插入的特定卡的正确 ADM1!如果您连续几次错误地提供 ADM1 值,您的卡 ADM1 很可能会被永久锁定,意味着您将永远无法达到 ADM1 特权级别。对于 sysmoUSIM/ISIM 产品,连续三次错误的 ADM1 值将锁定 ADM1。
在使用 verify_adm
命令时,如果输入的管理员 PIN(ADM PIN)不正确,将会引发异常。例如,当尝试验证 PIN 为 1
时,可能会遇到以下错误:
取消自动换行
复制
pySIM-shell (00:MF)> verify_adm 1
EXCEPTION of type 'RuntimeError' occurred with message: 'Failed to verify chv_no 0x0A with code 0x31FFFFFFFFFFFFFF, 2 tries left.'
To enable full traceback, run the following command: 'set debug true'
这个异常表明无法验证 CHV(Card Holder Verification)编号为 0x0A 的 PIN,且剩余尝试次数为 2 次。
为了方便经常需要修改同一组 SIM 卡的 ADM1,您可以将这些卡的 ICCID 和 ADM1 值放入一个 CSV 文件中,该文件位于 ~/.osmocom/pysim/card_data.csv
。在这种情况下,您可以使用 verify_adm
命令而不指定 ADM1 值。
成功的例子:
取消自动换行
复制
pySIM-shell (00:MF)> verify_adm
found ADM-PIN '11111111' for ICCID '898821190000000512'
pySIM-shell (00:MF)>
在这种情况下,CSV 文件中包含了卡片 ICCID 的记录(11111111),并且使用该值成功验证了 ADM1。
错误的例子:
取消自动换行
复制
pySIM-shell (00:MF)> verify_adm
EXCEPTION of type 'ValueError' occurred with message: 'cannot find ADM-PIN for ICCID '898821190000000512''
To enable full traceback, run the following command: 'set debug true'
在这种情况下,CSV 文件中没有该卡片 ICCID 的记录,因此无法找到对应的 ADM-PIN。
equip
为 pySim-shell 配备一张卡;特别有用,如果程序在卡存在之前就已经启动,或者在用户更换卡后,而 pySim-shell 仍在运行时。
bulk_script
在多张卡上运行脚本(批量配置)
用法:bulk_script [-h] [--halt_on_error] [--tries TRIES] [--on_stop_action ON_STOP_ACTION] [--pre_card_action PRE_CARD_ACTION] SCRIPT_PATH
位置参数
SCRIPT_PATH
脚本文件的路径
命名参数
--halt_on_error
如果发生异常则停止处理卡
默认值:False--tries
在尝试下一张卡之前尝试的次数
默认值:2--on_stop_action
当卡处理停止时执行的命令行--pre_card_action
在实际与卡通信之前执行的命令行
echo
在控制台打印(回显)一个字符串
用法:echo [-h] STRING [STRING ...]
位置参数
STRING
要在 shell 上打印的字符串
apdu
向卡发送原始 APDU,并打印 SW + 响应。注意:此命令绕过了 pySim-shell 的逻辑通道处理,且不跟踪卡状态变化。根据发送的原始 APDU,pySim-shell 可能无法继续按预期工作,例如,如果您选择了一个不同的文件。
用法:apdu [-h] [--expect-sw EXPECT_SW] [--raw] APDU
位置参数
APDU
作为十六进制字符串的 APDU
命名参数
--expect-sw
期望指定的状态字--raw
绕过逻辑通道(和安全通道)
默认值:False
示例:
取消自动换行
复制
pySIM-shell (00:MF)> apdu 00a40400023f00
SW: 6700
在上述情况下,原始 APDU 十六进制字符串 00a40400023f00
被发送到卡,卡响应了状态字 6700
。请记住,pySim-shell 不知道您发送给卡的原始命令类型,因此无法同步其内部状态(如当前选定的文件)与卡。因此,应限制使用此命令,仅限于 pySim-shell 目前还没有高级支持的命令。
1.1.7 ISO7816 命令
这一类命令与 ISO 7861-4 规范中起源的命令有关,其中大多数命令在规范中有 1:1 的对应关系。
select
select
命令用于选择文件,可以通过其文件标识符(FID)、应用程序标识符(AID)或其符号名称来选择。
尝试使用带有 tab 补全的 select
命令以获取所有当前可选择项的列表:
取消自动换行
复制
pySIM-shell (00:MF)> select
.. 2fe2 a0000000871004 EF.ARR MF
2f00 3f00 ADF.ISIM EF.DIR
2f05 7f10 ADF.USIM EF.ICCID
2f06 7f20 DF.GSM EF.PL
2f08 a0000000871002 DF.TELECOM EF.UMPC
使用特定的 FID 或名称来选择新文件。这将:
- 输出可能已解码的 select 响应
- 更改提示符到新选定的文件
- 启用任何针对新选定文件的特定命令
示例:
取消自动换行
复制
pySIM-shell (00:MF)> select ADF.USIM
{
"file_descriptor": {
"file_descriptor_byte": {
"shareable": true,
"file_type": "df",
"structure": "no_info_given"
}
},
"df_name": "A0000000871002FFFFFFFF8907090000",
"proprietary_info": {
"uicc_characteristics": "71",
"available_memory": 101640
},
"life_cycle_status_int": "operational_activated",
"security_attrib_compact": "00",
"pin_status_template_do": {
"ps_do": "70",
"key_reference": 11
}
}
pySIM-shell (00:MF/ADF.USIM)>
status
status
命令重新获取当前选定文件的文件控制模板,并打印其解码输出。
示例:
取消自动换行
复制
pySIM-shell (00:MF/ADF.ISIM)> status
{
"file_descriptor": {
"file_descriptor_byte": {
"shareable": true,
"file_type": "df",
"structure": "no_info_given"
},
"record_len": null,
"num_of_rec": null
},
"file_identifier": "ff01",
"df_name": "a0000000871004ffffffff8907090000",
"proprietary_information": {
"uicc_characteristics": "71",
"available_memory": 101640
},
"life_cycle_status_integer": "operational_activated",
"security_attrib_compact": "00",
"pin_status_template_do": {
"ps_do": "70",
"key_reference": 11
}
}
change_chv
更改 PIN 码为新的 PIN 码。
用法:change_chv [-h] [--pin-nr PIN_NR] [NEWPIN] [PIN]
位置参数:
NEWPIN
PIN 码值。如果未提供,则查询 CSV 文件。PIN
PIN 码值。如果未提供,则查询 CSV 文件。
命名参数:
--pin-nr
PUK 编号,1=PIN1,2=PIN2 或自定义值(十进制)
默认值:1
deactivate_file
使当前选定的文件失效。一旦文件被停用,就无法再进行任何进一步的操作(例如选择文件,随后进行读取或写入)。
任何对已停用文件的访问都将触发错误 SW 6283 ‘选定的文件已失效/被禁用’。
要重新访问已停用的文件,您需要再次激活它,请参阅下面的 activate_file 命令。请注意,停用时必须选择要停用的 EF,但激活时,必须选择要激活的 EF 上方的 DF!
此命令向卡发送一个 DEACTIVATE FILE APDU(在 TS 11.11 中的经典 SIM 中曾被称为 INVALIDATE)。
activate_file
通过发送 ACTIVATE FILE apdu 命令来激活指定的 EF(在 TS 11.11 中的经典 SIM 中曾被称为 REHABILITATE)。
用法:activate_file [-h] NAME
位置参数:
NAME
要激活的文件名或文件标识符(FID)。