分类目录归档:sim

手机上用AT命令访问sim卡

0.手机获得root权限

1.找到AT端口
高通

/dev/at_mdm0 (SDM636,SDM8150等芯片都是这个 tty设备)
/dev/smd11  (MSM8909W)

联发科
/dev/radio/atci1
/dev/radio/atci2
展讯
/dev/stty_lte1

/dev/stty_lte31

展讯的stty_lte1, stty_lte2, stty_lte6, stty_lte7, 8, 9, 10, 11, 12….17
stty20, 21, 22, 23, … 30 能正常访问 sim卡
有些端口,只能执行其他AT命令,比如 AT+CGSN AT+CGREG? AT+CCLK?

但 /dev/stty_lte20 好像都是可以的
比如 Spreadtrum SL8521E

2.发送命令

echo "AT+COPS?\r"  > /dev/stty_lte1

3.常用AT命令

AT+CGSN            请求产品序列号号,一般就是IMEI
AT+CGLA            UICC逻辑通道访问
AT+CGMI            设备制造商标识
AT+CGMM            型号标识
AT+CGMR            版本
AT+CIMI            请求读取IMSI
AT+CSCA?           获取SMSP
AT+CPIN            输入PIN
AT+CPWD            改变密码
AT+CRSM            保密的SIM卡访问
AT+CSIM            一般SIM卡访问
AT+CUAD            USIM卡应用发现
ATA                 接电话(answer)
ATD                 拨打电话(dial)
ATE                 打开命令回显(echo)
ATH                 挂断电话(hangup)
AT+ICCID            读取ICCID      (展讯不支持)
AT+CCHO             打开逻辑通道
AT+CCHC=<sessionid> 关闭逻辑通道

4.分析

读取Kc
命令  "AT+CRSM=176,20306,0,0,9\r"
响应  +CRSM: 144,0,A9FCB522A7062D5303

读取ICCID
命令   AT+CRSM=176,12258,0,0,10
响应   +CRSM: 144,0,98686091010005689312

读取IMSI
命令   "AT+CRSM=176,28423,0,0,9\r"

5.命令参数

AT+CRSM=instruction, file_id, P1, P2, P3, data, path_id

instruction可以为
B0  读二进制
B2  读记录
C0  得到响应(一般为取fcp)
D6  更新二进制
DC  更新记录
F2  取状态

AT+CSIM=length, instruction






在新标准中, 
AT+CGLA 逻辑通道访问,就是AT+CSIM一样的功能 AT+CRLA 就是 AT+CRSM
多了个session_id参数 GRLA命令参数 +CRLA=<sessionid>,<command>[,<fileid>[,<P1>,<P2>,<P3>[,<data>[,<pathid>]]]] CGLA命令参数 +CGLA=<sessionid>,<length>,<command>

6. 其他

展讯和高通都不支持AT+CSIM 展讯和联发科,都支持 新的逻辑通道命令,高通不支持

echo "AT+CCHO=\"A0000000871002FF86FFFF89FFFFFFFF\"\r" > /dev/stty_lte1
echo "AT+CGLA=1, 14, \"00A40004023F00\"\r" > /dev/stty_lte1
echo "AT+CCHC=1\r" > /dev/stty_lte1
文件不存在
echo "AT+CRSM=192,28648,0,0,0,\"\",\"3F007FFF\"\r" > /dev/stty_lte1
和
echo "AT+CRSM=176,28648,0,0,120,\"\",\"3F007FFF\"\r" > /dev/stty_lte1
都是
回应
+CRSM: 106,130

在飞行模式下,这个AT命令也是可以用的

实例
Mi Max2 (MSM8953)

一个adb shell 执行 cat /dev/at_mdm0    
另外执行 echo 'AT+CRSM=176,12258,0,0,10\r\n' > /dev/at_mdm0
前面那个就能读到 ICCID
                                                                                                          
AT+CRSM=176,12258,0,0,10
+CRSM: 144,0,"98681002098103218863"

OK
--------------------

echo 'AT+CSIM=30,80AA00000AA9088100820101830107\r\n' > /dev/at_mdm0

+CME ERROR: operation not supported
高通不支持CSIM

解开分卷压缩的tar.gz

文件名从 tar.gz00 到 tar.gz20

其中一种能正常工作的命令是

cat   softsim.tar.gz00   ...  softsim.tar.gz20  |  tar xvz

另外一种避免手动输入文件名的命令

ls  softsim.tar.gz* | xargs cat |  tar xvz

不能正常工作的命令是

tar xvzf  softsim.tar.gz00

hal_extRadio_hwservice

allow embmsd hal_extRadio_hwservice : hwservice_manager find ;
allow thermald hal_extRadio_hwservice : hwservice_manager find ;
allow sprd_engineermode_app hal_extRadio_hwservice : hwservice_manager find ;
allow engpc hal_extRadio_hwservice : hwservice_manager { add find } ;
allow radio hal_extRadio_hwservice : hwservice_manager find ;
allow srtd hal_extRadio_hwservice : hwservice_manager find ;
allow sprd_logmanager_app hal_extRadio_hwservice : hwservice_manager find ;
allow hal_audio_default hal_extRadio_hwservice : hwservice_manager find ;
allow mlogservice hal_extRadio_hwservice : hwservice_manager find ;
allow system_app hal_extRadio_hwservice : hwservice_manager find ;
allow rild hal_extRadio_hwservice : hwservice_manager add ;
allow sprd_validationtools_app hal_extRadio_hwservice : hwservice_manager find ;
allow sprd_autoslt_app hal_extRadio_hwservice : hwservice_manager find ;


allow engpc rild : binder call ;

allow engpc hal_extRadio_hwservice : hwservice_manager { add find } ;

allow engpc hwservicemanager : binder { call transfer } ;

allow hwservicemanager engpc : file { read open } ;

allow hwservicemanager engpc : process getattr ;
allow hwservicemanager engpc : dir search ;
allow hwservicemanager engpc : binder { call transfer } ;

allow rild engpc : file { read write open } ;

allow rild engpc : dir search ;

allow servicemanager engpc : binder transfer ;


allow hwservicemanager system_app : binder { call transfer } ;

allow system_app hidl_manager_hwservice : hwservice_manager find ;
allow system_app hal_extRadio_hwservice : hwservice_manager find ;

allow system_app hwservicemanager : binder { call transfer } ;

allow system_app rild : binder { call transfer } ;
allow rild system_app : binder call ;

magiskpolicy --live "allow untrusted_app hal_extRadio_hwservice hwservice_manager find"
magiskpolicy --live "allow untrusted_app rild binder call"
magiskpolicy --live "allow untrusted_app rild binder transfer"

magiskpolicy --live "allow rild untrusted_app  binder call "

hidl java client

hidl生成java代码,需要在aosp编译环境

cd aosp
. build/envsetup.sh
lunch sdk_phone_x86_64-userdebug
hidl-gen -o /tmp -Ljava   -randroid.hardware:hardware/interfaces   -randroid.hidl:system/libhidl/transport android.hardware.memtrack@1.0

将在 /tmp/android/hardware/memtrack/V1_0/ 目录生成 java代码

在 aosp/hardware/interfaces/memtrack/1.0 下有 IMemtrack.hal types.hal两个hal文件

在手机上,运行 lshal可以查看 hal接口

编译frida

先安装nodejs
添加如下内容到/etc/apt/sources.list.d/nodejs.list

deb https://deb.nodesource.com/node_14.x sid main

添加key

curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key |  apt-key add -

安装编译系统

apt install build-essential curl git  g++-multilib  gcc-multilib  nodejs python3-dev

再获取frida源代码

git clone --recurse-submodules https://github.com/frida/frida.git

获取编译工具
sdk-android-arm.tar.bz2
sdk-android-arm64.tar.bz2
sdk-linux-x86.tar.bz2
sdk-linux-x86_64.tar.bz2
toolchain-linux-x86_64.tar.bz2
放到frida/build目录 (这步骤可以跳过,make时会自动下载)

准备环境变量

export ANDROID_NDK_ROOT=/Android/Sdk/ndk/21.3.6528147
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8

编译
make core-android-arm64
make python-linux-x86_64 PYTHON=/usr/bin/python3
make tools-linux-x86_64

对于frida而言,gcc-multilib中只需要libc6-dev-i386
g++-multilib中只需要g++-10-multilib
不过 build aosp用得着

紫光展锐vsim相关AT命令

vsim的hidl接口 framework/boot-radio_interactor_common

vendor.sprd.hardware.radio.V1_0.IExtRadio下的
public void sendCmdAsync(int serial, String cmd);
public String sendCmdSync(int phoneId, String cmd); 这个接口用来发送AT命令给modem
public void setAtcResponseFunctions(IAtcRadioResponse radioResponse, IAtcRadioIndication radioIndication);

void vsimSendCmd(int arg1, int arg2, String arg3);
void simGetAtr(int arg1);

vendor.sprd.hardware.radio.V1_0.IAtcRadioIndication下
public void vsimRSimReqInd(int type, String data);

vendor.sprd.hardware.radio.V1_0.IAtcRadioResponse下
public void vsimSendCmdResponse(RadioResponseInfo info, String response);

=============================
AT+VIRTUALSIMINIT=%d
初始化模式,设置为2
2表示软卡

AT+VIRTUALSIMINIT?

查询虚拟卡模式

AT+SPVSIMAUTHSET=%d
支持哪种鉴权算法,Milenage, Comp128

AT+SPVSIMAUTHSET?

AT+RSIMRSP=
发送rAPDU给modem

启用vsim功能

AT+RSIMRSP="VSIM",1

VSIM_INIT:AT+RSIMRSP=”VSIM”,1

关闭

AT+RSIMRSP="VSIM",0

VSIM_EXIT:AT+RSIMRSP=”VSIM”,0

设置超时
VSIM_TIMEOUT:%d”

=============
命令从 用CRSM发送过来
AT+CRSM=%d,%d,%d,%d,%d
AT^MBAU=

===================
流程
AT+VIRTUALSIMINIT=2
注册循环处理函数setAtcResponseFunctions AtcRadioIndication AtcRadioResponse
VSIM_INIT:AT+RSIMRSP=”VSIM”,1

=========
关闭VirtualSIM功能 (写入到NV)
AT+VIRTUALSIMINIT=0,1

===========
鉴权命令格式

AT^MBAU=?
回应
^MBAU::rand,autn
第1个是状态码
se相关问题

magiskpolicy --live "allow untrusted_app hal_extRadio_hwservice hwservice_manager find"
magiskpolicy --live "allow untrusted_app  binder { call transfer }"
magiskpolicy --live "allow rild untrusted_app binder call "
void requestSendAT(RIL_SOCKET_ID socket_id, const char *data, size_t datalen,
                   RIL_Token t, char *atResp, int responseLen) {
...
...  
 } else if (strStartsWith(ATcmd, "VSIM_INIT")) {
        char *cmd = NULL;
        RLOGD("vsim init");
        cmd = ATcmd;
        at_tok_start(&cmd);
        err = at_send_command(socket_id, cmd, &p_response);
    } else if (strStartsWith(ATcmd, "VSIM_EXIT")) {
        char *cmd = ATcmd;

        //send AT
        at_tok_start(&cmd);
        int simState = getSIMStatus(RIL_EXT_REQUEST_SIMMGR_GET_SIM_STATUS, socket_id);
        if (simState != SIM_ABSENT) {
            at_send_command(socket_id, "AT+RSIMRSP=\"ERRO\",2", NULL);
            err = at_send_command(socket_id, cmd, &p_response);
            if (err >= 0 && p_response->success != 0) {
                onSimDisabled(socket_id);
            }
        } else {
            RLOGD("no vsim!!");
        }
    }  else if (strStartsWith(ATcmd, "VSIM_TIMEOUT")) {
        int time = -1;
        char *cmd = ATcmd;

        at_tok_start(&cmd);
        err = at_tok_nextint(&cmd, &time);
        RLOGD("VSIM_TIMEOUT:%d", time);
        if (time > 0) {
            s_timevalCloseVsim.tv_sec = time;
        }
    } 

开启

void requestVsimCmd(RIL_SOCKET_ID socket_id, void *data, size_t datalen,
                           RIL_Token t) {
    RIL_UNUSED_PARM(data);
    RIL_UNUSED_PARM(datalen);

    int i = 0, err = -1;
    char *ATcmd = (char *)data;
    char buf[AT_RESPONSE_LEN] = {0};
    char *response[1] = {NULL};
    ATLine *p_cur = NULL;
    ATResponse *p_response = NULL;

    if (ATcmd == NULL) {
        RLOGE("Invalid AT command");
        goto error;
    }

    if (strStartsWith(ATcmd, "VSIM_INIT")) {
        char *cmd = NULL;
        RLOGD("vsim init");
        cmd = ATcmd;
        at_tok_start(&cmd);
        err = at_send_command(socket_id, cmd, &p_response);
    } else if (strStartsWith(ATcmd, "VSIM_EXIT")) {
        char *cmd = NULL;

        // send AT
        cmd = ATcmd;
        at_tok_start(&cmd);
        int simState = getSIMStatus(RIL_EXT_REQUEST_SIMMGR_GET_SIM_STATUS, socket_id);
        if (simState != SIM_ABSENT) {
            at_send_command(socket_id, "AT+RSIMRSP=\"ERRO\",2", NULL);
            err = at_send_command(socket_id, cmd, &p_response);
            if (err >= 0 && p_response->success != 0) {
                onSimDisabled(socket_id);
            }
        } else {
            RLOGD("no vsim!!");
        }
    }  else if (strStartsWith(ATcmd, "VSIM_TIMEOUT")) {
        int time = -1;
        char *cmd = NULL;
        cmd = ATcmd;
        at_tok_start(&cmd);
        err = at_tok_nextint(&cmd, &time);
        RLOGD("VSIM_TIMEOUT:%d",time);
        if (time > 0) {
            s_timevalCloseVsim.tv_sec = time;
        }
    } else {
        err = at_send_command_multiline(socket_id, ATcmd, "",
                                        &p_response);
    }

    if (err < 0 || p_response->success == 0) {
        if (p_response != NULL) {
            strlcat(buf, p_response->finalResponse, sizeof(buf));
            strlcat(buf, "\r\n", sizeof(buf));
            response[0] = buf;
            RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, response,
                                  sizeof(char *));
        } else {
            goto error;
        }
    } else {
        p_cur = p_response->p_intermediates;
        for (i = 0; p_cur != NULL; p_cur = p_cur->p_next, i++) {
            strlcat(buf, p_cur->line, sizeof(buf));
            strlcat(buf, "\r\n", sizeof(buf));
        }
        strlcat(buf, p_response->finalResponse, sizeof(buf));
        strlcat(buf, "\r\n", sizeof(buf));
        response[0] = buf;

        RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(char *));
        if (!strncasecmp(ATcmd, "AT+SFUN=5", strlen("AT+SFUN=5"))) {
            setRadioState(socket_id, RADIO_STATE_OFF);
        }
    }
    at_response_free(p_response);
    return;

error:
    if (t != NULL) {
        memset(buf, 0 ,sizeof(buf));
        strlcat(buf, "ERROR", sizeof(buf));
        strlcat(buf, "\r\n", sizeof(buf));
        response[0] = buf;
        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, response,
                              sizeof(char *));
    }
    at_response_free(p_response);
}

处理modem来的sim cmd

int processMiscUnsolicited(RIL_SOCKET_ID socket_id, const char *s) {
...

} else if (strStartsWith(s, "%RSIMREQ:")) {
        char *tmp = NULL;
        char *response = NULL;

        line = strdup(s);
        tmp = line;
        at_tok_start(&tmp);

        skipWhiteSpace(&tmp);
        response = (char *)calloc((strlen(tmp) + 5), sizeof(char));
        snprintf(response, strlen(tmp) + 4, "%d,%s\r\n", socket_id, tmp);
        RIL_onUnsolicitedResponse(RIL_ATC_UNSOL_VSIM_RSIM_REQ, response,
                                  strlen(response) + 1, socket_id);
        free(response);
    }
...

/vendor/bin/hw/sprdrild

E RILC : vsimRSimReqInd: radioService[0]->mAtcRadioIndication == NULL
I RILC : RIL_SOCKET_1 UNSOLICITED: UNSOL_VSIM_RSIM_REQ length:37

紫光展锐读写IMEI

frida调用
imei.js

setImmediate(function() { //prevent timeout
    Java.perform(function(){
        console.log("start hook....");
        
        
        Java.choose("com.sprd.vsimservice.VSIMInterfaceService", {
            onMatch: function (instance) {
                console.log("VSIMInterfaceService Found.");    
                var imei = instance.sendATCmdNative(1, "AT+CGSN");
                console.log("imei=" + imei);
            },
            onComplete: function () { }

        });

    });
    
});

工程模式中提供了下发at命令的接口,通过IATUtils.java中的
sendATCmd(String cmd, String serverName)可以实现。
读IMEI的AT命令
IATUtils.sendATCmd(“AT+SPIMEI?”, “atchannel0”);
IATUtils.sendATCmd(“AT+SPIMEI?”, “atchannel1”);

IATUtils.sendATCmd(‘AT+SPIMEI=0,”353957100590169″‘, “atchannel”);
IATUtils.sendATCmd(‘AT+SPIMEI=1,”353957100590169″‘, “atchannel”);

setools-android

https://github.com/xmikos/setools-android
./seinfo /sys/fs/selinux/policy (默认的binary sepolicy不在 /sepolicy了)

static int search_policy_binary_file(char **path)

USIM卡鉴权信息序列号SQN

USIM 卡鉴权信息序列号 SQN 的存储: SQN=SEQ+IND(序列号+索引)
USIM 保留上次鉴权成功后最大的 SEQ 值作为 SEQ (终端)

USIM 对 网络 进行认证的机制如下

SEQ(网络)  - SEQ(终端)  <   2^28
SEQ(终端)  -  SEQ(网络)  <   L
SEQ(网络)   >   SEQk

一般情况下,条件 1 和条件 3 比较容易满足,主要问题集中在第 2 个验证条件。

对于 CSFB语音方案, 存在 CS/PS 交替鉴权。
如果一个域使用了之前 MSC/SGSN/MME 预取的鉴权向量,
并且在上次预取后,在另一个域 生成鉴权向量并鉴权, 就会发生 USIM 侧存储的 SEQ 值大于第一个域鉴权时使用的 SEQ 值,
即 SEQ (终端) >SEQ (网络);
如果这个差值过大,达到了 SEQ (终端) -SEQ (网络) > L, 就会发生鉴权失败发起重同步。

目前, USIM 中 L 值普遍设为 32。
某些的厂家鉴权中心(AuC)是基于时间机制产生 SEQ。
若 USIM 中的 L 值取为 32,即二进制100000, 后 4 位 0000 为时钟的 0.1 s, 前 2 位 10 为时钟的 s, 10 也就是 2s。
因此,只要使用的鉴权向量是在另一个域鉴权 2 s 之前生成的,就会发生鉴权失败。

鉴权重同步:
当发生鉴权失败时, USIM 将当前的 SEQ (终端)上报给网络,并携带该值到 AuC 重新获取鉴权。
AuC 返回大于此值的 SEQ 作为 SEQ (网络)。
某些厂家在鉴权重同步时, AuC 并不重新基于时间生成 SEQ (其他场景 AuC 均基于绝对时间生成新的SEQ),
而是在 USIM 上报的 SEQ 基础上增加一个较小值Δ, 作为重新下发鉴权向量中的 SEQ (网络),
导致若在进行 CS 域鉴权重同步过程中,插入 PS 域鉴权过程,CS 域二次鉴权也会失败,呼叫失败

针对 USIM 新卡,建议取消 L 值。考虑到 L 值的判断条件在国际规范为可选项,是否采用取决运营商安全策略,从目前及将来网络看,对安全不会产生影响,可采取取消 USIM 中 L 值判断的解决方案。


USIM卡的EF_SQN
ADF/6F1D 也就是 7FF0/6F1D (每家卡商实现得不一样, 金普斯是这个地址,华虹是FF06)

当完成一次成功的鉴权后, 当次计算出的SQN 必须存储到卡的 EF_SQN文件中, 共有32条记录
SQN有SEQ和IND两部分组成: SQN = SEQ || IND
其中SEQ长43bits, IND长度为5bits, 共48bits, 6个字节
其中SEQ_MS(i)表示 USIM中保存的SEQ数组中的第i个值。USIM在做SQN验证时,应该以IND作为索引,比较收到的SQN的SEQ和对应IND的SEQ_MS(IND)


有些USIM卡中,有33条记录,用来保存 SEQ和IND
其中 #2到#33 保存IND 0~31的SEQ
当IND_net = 00 且鉴权成功后, USIM卡将把本次的SEQ_net保存在
#2记录,标识为 SEQ0, 其他以此类推。
同时, USIM总是将#2到#33记录的各个SEQ中,最大的那个
保存到#1记录,标识为 SEQ_ms和IND_ms
当USIM进行鉴权同步判决是,应遵循这3个条件:
1) 将网络下发的 鉴权消息中,提取SEQ_net 与 USIM #1记录的SEQ_ms进行比较
SEQ_net – SEQ_ms < Δ (Δ取值很大)
2) SEQ_ms – SEQ_ms < L
也就是 下发比较晚的 鉴权消息中的 SEQ要比之前的SEQ要大
即使新来的小, 也不能小很多, 最多小L (L一般取32)

PS域和CS域的 鉴权频次 相差一般较大
当PS域开启Service Request鉴权时,对智能终端而言,PS域的鉴权频次 将远高于CS域;
PS域关闭Service Request鉴权,而CS域名 开启位置更新鉴权,语音业务,短信业务鉴权时,CS域将远高于PS域

对于新的USIM卡,应该取消第2个条件的判断。
3) SEQ_net > SEQ_k
将 k = IND_net 条记录的 SEQ_k(IND永远小于33) 与 SEQ_NET 比较:
SEQ_net > SEQ_k(不能等于)
大部分厂家的HLR/Auc设备,对于PS和CS的IND分配都是隔开的(0~15分给CS, 16-31分给PS)


当网络收到Synch Failure的Authentication Failure消息时,允许网络侧触发 重同步机制。
MSC或者SGSN将重新向HLR/Auc申请新的鉴权向量(5元组或4元组), 并在请求消息中,将USIM卡传来的
AUTS参数发给HLR/Auc.
HLR/Auc可以根据AUTS算出 SEQ_ms, 从而确保 HLR/Auc新生成的 鉴权向量中的SEQ_net能够比上次鉴权同步
失败时,USIM中保存的SEQ_ms更大。


HE/Auc会发送多组 鉴权向量 给 VLR/SGSN, 鉴权向量 以SQN为序依次存好。
当VLR/SGSN发起一次鉴权是,他从 排好序的数组中,选取下一条鉴权向量,发送RAND,AUTN参数给用户。

USIM检查AUTN是否能接受,如果能,产生一个RES响应,发挥给VLR/SGSN.

如果一个用户长期不注册到网络, SEQ会被初始化为 00 00 00 00 01 00


一般情况下,VLR/SGSN对每个鉴权向量(5元组)只使用一次。但也有例外:
VLR/SGSN已经用某个特定的5元组,发出一个鉴权请求,但是没有从移动台(Mobile Station)收到响应消息(鉴权响应或者鉴权失败)。
它可能会用同样的5元组,重新发送鉴权请求。 多次重传都没有响应, VLR/SGSN应该删除这个5元组。

在MS侧,为了允许这样的重传,而不引起 额外的重新同步过程,ME应该为PS域(以及可选地为CS域名也做同样的事情)存储最后收到的RAND,以及算出来的RES, CK, IK.
如果ME发现受到的鉴权请求中的RAND是重复的,就直接重发响应给基站,就好了,根本不需要再问USIM卡。


SQN包含两部分: SEQ和IND
SQN = SEQ || IND
USIM维护着有a个数组,存储这 SEQ_ms(0), EQ_ms(1), … SEQ_ms(a-1)
这个数组里的a个元素的,初始值都是0

  1. 如果收到的 SEQ > SEQ_ms (i), 那么,USIM应该认为这个序列号是新的, 接下来将 SEQ_ms(i)设置为SEQ
  2. 如果 SEQ <= SEQ_ms(i), 那么,USIM应该生成一个 同步失败的消息,带上 本sim卡中 曾经接收到所有SEQ中,最大的那个, 也就是SQN_ms
    USIM也可以在 SEQ_ms和SEQ 放一个限制L. 也就是 SEQ_ms – SQE < L都能接受。

USIM卡安全功能

ETSI TS 131 102 V16.4.0 (2020-07)第6节
在 TS 33.102 和 TS 33.103 中 定义了 3G的安全性。本节给出 USIM支持的安全功能
1)向网络认证usim
2) 向usim认证网络
3) 想usim认证用户
4)通过无线电接口的数据机密性
5) 文件访问条件
6) 兼容GSM参数的转化功能

认证和密钥协商过程
本接描述了由网络调用的认证机制\加密\完整性密钥生成。对于USIM/UE接口的相应过程,请参考第5节.
该机制通过在用户和网络之间共享一个密钥K来实现相互认证。密钥只在USIM和用户归属的Auc之间共享。此外,为了支持网络鉴权,USIM和用户归属环境还分别保持对计数值 SQN_ms和 SQN_he的追踪。SQN_he是一个在HLR/Auc中保存的,对于每个用户而言都是独立的计数值。SQN_ms表示USIM接受的最大的序列值。
当SN/VLR(服务的网络,拜访位置寄存器)启动身份认证和密钥协商后,它将选择下一条认证向量,并发送RAND和AUTN(authentication token)参数给用户.每个AUTN含有:SQN, AMF(Authenticaiton Management Field), 通过RAND/SQN/AMF计算出的MAC(message authentication code).
USIM检查AUTN是否可以接受,如果可以,产生一个响应RES,发回给 SN/VLR.
SN/VLR将接收到的RES和XRES(鉴权向量的一个元素)进行比较,如果匹配,SN/VLR就认为 认证和密钥协定成功。
USIM还将计算出Ck和Ik,被MEI用来执行加密和完整性功能。

在认证过程中,会用到密钥K, 它的长度为128位或者256位,存储在USIM中。
在USIM中可以存储多个K, 在AUTN的AMF标识使用哪个K

第7节
认证命令
几种不同的安全上下文:
1) UE位于UTRAN,或者通过 GSM无线网络接入到 3G的VLR/SGSN,使用3G安全上下文,也就是使用3G authentication vectors (RAND, XRES, CK, IK, AUTN)
2) UE位于没有3G能力GSM无线接入网内,使用GSM认证数据,这就是GSM安全上下文
3) VGCS/VBS认证数据可用时,处于 VGCS/VB安全上下文
4) 请求 GBA 自举过程时, 处于 GBA_U 安全上下文
5) MBMS
6) 本地密钥实施

在3G安全环境下, USIM首先通过 f5算出 AK(anonymity key), 从而可以算出SQN
然后,用f1 (SQN|RAND|AMF)算出 XMAC,并与AUTN中的MA比较。如果不同,中止功能。
接下来,usim验证收到的 SQN是不是以前没有用过的。如果没用用过,并且比 SQN_MS小, 就接受。
如果SQN是最后收到32个SQN, 也可以接受。
所以, usim的sqn 列表最少应该有32个。

如果usim检测到sqn不合法,那么就认为同步失败。应该中止功能,发回 AUTS响应。
AUTS = Conc(SQN_ms ) || MACS

Conc(SQN_ms ) = SQN_ms ⊕ f5* (RAND) 就是SQN_ms的加密值
MACS = f1* (SQN_ms || RAND || AMF)

如果SQN是在正确的范围,那么 usim将计算 RES = f2 (RAND), CK = f3 (RAND), IK = f4 (RAND)
为了更有效的返回 响应给网络, usim 在收到RAND后,就可以提前计算 res, ck, ik

错误码:
9862:: Authentication error, incorrect MAC
9864:: Authentication error, security context not supported
9865:: Key freshness failure
9866:: Authentication error, no memory space available
9867:: Authentication error, no memory space available in EF MUK