作者归档:softsim

SubscriptionManager

boolean setSubscriptionEnabled(int subscriptionId, boolean enable)
首先检查 canDisablePhysicalSubscription

public static int getSubscriptionId(int slotIndex)

boolean isSubscriptionEnabled(int subscriptionId)

public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex (int slotIndex)

getSubscriptionId()

Jetpack Compose

@Composable
fun TextDemo() {
    Column(modifier = Modifier.fillMaxSize()) {
        var text by remember { mutableStateOf("Hello, World!") }
        Button(onClick = {


            text = "Good"
        }) {
            Text(text = "Go")
        }

        Text(text)
    }
}

点击button, 修改text

Android SIM卡pass through模式

将SIM卡先Power Down, 然后在Power up pass through, 就可以将 SIM设置为直通(pass through)模式.

当初sim卡处于直通模式时,modem不发送其他任何指令(包括选择MF文件,TERMINAL CAPABILITY)。sim卡完全被Telephony控制, 直接发送 APDU. SIM卡的状态,将被设置为RIL_CARDSTATE_PRESENT, card apps的数目将是0. 不会生成任何错误代码。紧急呼叫将被支持,就如同SIM不存在时,也可以支持紧急呼叫那样。

直通模式,只对 激活它的 特定会话 有效。当卡下次初始化时, 就回到普通模式,除非你 再次请求直通模式。也就是说,手机重启后, SIM卡将回到 正常模式。

调用者应该监视 TelephonyIntents#ACTION_SIM_STATE_CHANGED 广播,来决定 成功或者失败,以及是否超时. 但新设备上,不保证会触发 广播。 请用新接口 setSimPowerState(int, Executor, Consumer_integer)

回调可能的值:
SET_SIM_POWER_STATE_SUCCESS
SET_SIM_POWER_STATE_ALREADY_IN_STATE
SET_SIM_POWER_STATE_MODEM_ERROR
SET_SIM_POWER_STATE_SIM_ERROR
SET_SIM_POWER_STATE_NOT_SUPPORTED
如果请求的 sim卡状态不对,将抛出 IllegalArgumentException 异常。

platform/hardware/interfaces/+/master/radio/1.6/IRadio.hal

oneway setSimCardPower_1_6(int32_t serial, CardPowerState powerUp);
设置SIM卡电源状态。
请求关掉 或者打开 sim卡的电源。
它不应该生成一个 CardState.CARDSTATE_ABSEND指示。
因为SIM卡还是物理插入在卡槽的。

当SIM卡处于直通模式时, modem不发送任何指定给sim卡,(比如
SELECT MF或者TERMINAL CAPABILITY指令)。SIM卡完全被
Telephony控制发送APDU.
SIM卡的状态必须是 RIL_CAFDSTATE_PERSENT
卡上的apps数量将为0
不会生成新的错误代码。
在切换为POWER_UP/POWE_UP_PASS_THROUGH状态前,SIM卡必须处于power down.

在手机power up时, SIM卡接口也会自动power up
关sim,开sim,这些请求,必须等前一个请求完成后,才能处理。

关卡状态,在CardStatus.applicaont中, modem发送一个空的AppStatus向量。

在关卡状态是,如果物理移除并插入新的sim卡,新卡必须默认处于开卡状态。

oneway setSimCardPower_1_1(int32_t serial, CardPowerState powerUp);

hardware/interfaces/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
void setSimCardPower(in int serial, in CardPowerState powerUp);

SGP.22 eUICC信息

EUICCInfo1是EUICCInfo2的子集。
EUICCInfo1 是在 卡片被 authenticated前,发送给RSP服务器的信息。
EUICCInfo2 是卡片完整的信息, 只有euicc和rsp双方相互认证完成后,才会发给RSP.

LPA可以在任何时候向 euicc取得这些信息。

Profile Package Versions 包版本
Specification Version Numbers 规范版本
Firmware version 固件版本
Available amount of non-volatile memory 可用的存储空间大小
UICC capabilities  能力
ETSI TS 102 241 version    102.241规范版本
GlobalPlatform version   GP版本
RSP capabilities     RSP能力
Lists of supported eSIM CA RootCA Public Key Identifiers    支持的根证书公钥标识符 列表
eUICC Category   类别
Forbidden PPRs  
Protection Profile version
SAS Accreditation Number
Certification Data Object
TRE properties
TRE product reference
LPA Mode
EUM specific information


euicc download profile

1. 拥有要下载的profile的运营商,通过调用 ES2.DownloadProfile 功能(输入数据为 SM-SR的标识符和地址,这些应该由运营商提供)。
默认情况下, profile处于disabled状态。当然,运营商可以要求SM-DP在最后启用新下载的profile

2. 受到请求的 SM-DP ,应该调用ES3.GetEIS

3. SM-SR 应基于EID来取得 euicc的 EIS信息。 如果在它的系统里,没有这张euicc的信息,应该返回一个错误。
错误信息最终返回给运营商,运营商终止 profile下载过程

4. EIS信息中, 卡上的ISD-P 用 smdp-id 将此卡与 特定的SM-DP关联起来, 如果SM-SP尝试删除此euicc旧有的profile

5. SM-DP检查 euicc是否满足download profile的一些要求。
1) uicc的特性是否同profile兼容
2) uicc的ram/storage是否够用
3) uicc是否认证过(certified)

SM-DP应该验证 EIS信息中 关于该uicc的ECASD的证书, 使用CI签发的EUM的证书,来验证 ECASD证书的 PK.ECASD.ECKA密钥

6. SM-DP调用ES3.CreateISDP

7.

esim激活二维码

扫描esim服务提供商的二维码 来下载esim数据,比自己手动收入 激活码来下载,要容易得多。

购买esim服务后,一般会收到一封电子邮件,里面含有完整的激活字符串 和/或 它的二维码,比如

LPA:1$esim.wo.com.cn$A1B2C3D4

其中 SM-DP+ 的地址就是 esim.wo.com.cn

激活码是 A1B2C3D4
确认码是 空, 也就是没有

这些内容在 SGP.22 规范中定义

中国移动

LPA:1$esim.yhdzd.chinamobile.com:8001$

既没有 激活码,也没有确认码

中国联通

LPA:1$esim.wo.com.cn$1.3.6.1.4.1.47814.101.8

没有激活码,
有确认码,为 1.3.6.1.4.1.47814.101.8

java.util.Base64与 android.util.Base64

java.util.Base64 是在 Java 8 中添加的, Android早期是基于 Java 7的,所以自己搞了个android.util.Base64
android的base64编码后,默认会添加换行符号 “\n”

Base64.encodeToString(byte_array, Base64.NO_WRAP)

指定 NO_WRAP 参数,就不会换行
就同

Base64.getEncoder().encodeToString(byte_array)

的编码结果一样了

TMPI生成

ETSI TS 133 220 V17.4.0 (2023-01) 第44页

FC = 0x01
P0 = gba-me 也就是 十六进制 67 62 61 2d 6d 65 , Ks_NAF 和 Ks_ext_NAF都用这个参数
L0 = P0的长度, 6字节, 也就是 00 06
P1 = RAND
L1 = RAND的长度,16字节, 也就是00 10
P2 = IMPI ,以 UTF-8 编码
L2 = IMPI的长度, 不大于 65535
P3 = BSF_Id , 以 UTF-8 编码
L3 = BSF_Id的长度,小于 65535


BSF_Id 就是生成 B-TID的 BSF 服务器,在DNS系统的完整名称(比如 bsf.mnc002.mcc460.pub.3gppnetwork.org), 同Ua安全协议标识符
01 00 00 01 00 的拼接

Ks就是 CK IK的拼接。
TMPI 就是 TEMP@tmpi.org
其中 TEMP是 KDF输出的最前面的24个字节的 base64编码

python代码如下

s = fc + p0 +l0 + p1 + l1 + p2 + l2 + p3 + l3
k = ck +ik
h = hmac.new(k, digetmod=hashlib.sha256)
h.update(s)
temp = h.diget()[:24]
tmpi = base64.b64encode(temp).decode() + '@tmpi.bsf.3gppnetwork.org'

Ua安全协议标识符

Ua安全协议标识符 是一个5个字节的 字符串(string).
第1个字节,表示, 制定该Ua安全协议的 组织。
后面的4个字节,则指 该组织 定义的某种安全协议。

组织者字节
01 = 3GPP
02 = 3GPP2
03 = Open Mobile Alliance
04 = GSMA


01 00 00 00 00 = 按照TS 33.221定义的安全协议
01 00 00 00 01 = TS 33.246
01 00 00 00 02 = TS 24.109 定义的 Ua security protocol HTTP digest authentication
01 00 00 00 03 = TS 26.237 定义的 Ua security protocols used with HTTP-based security procedures for
MBMS user services
01 00 00 00 04 = TS 26.237定义的 Ua security protocols used with SIP-based security procedures for
MBMS user services

01 00 00 01 00 = Generation of TMPI
0x01,0x00,0x01,yy,zz = TS 33.222定义的 Ua security protocol for “Shared key-based UE authentication with
certificate-based NAF authentication” 或者 “Shared key-based mutual authentication between UE and NAF” for TLS 1.2 (see above for Ua security protocol identifier for TLS 1.3 with shared keys)
这里, “yy,zz” 是保护机制 CipherSuite code, 定义在 IANA 加密套件的TLS CipherSuites的定义的值。 RFC 8446
比如, The TLS 1.2 CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 的值是 { 0xC0,0x2B }

( 0x01,0x00,0x02,yy,zz )