智能卡分接触式和非接触式两种。接触式就是平时看到的卡片上面带一片芯片的卡,早
些时候的公共电话卡,现在的医保卡,都有这样的芯片。非接触式就是看不到芯片,而是埋
在卡里面,通过线圈产生电磁感应进行供电和通信,一般学校食堂的饭卡、门禁卡多用这一
种。这两种卡都有相应的标准,大家可以自己翻翻(ISO7816, ISO14443)
上文也说到过,智能卡还可以分为存储卡和CPU 卡。存储卡是一种比较简单的卡,仅仅
提供了存储信息的功能,一些卡还带有密码,可以起到一些防范的作用,但是这些卡自身无
法进行运算。CPU 卡具有片上的 CPU、ROM、RAM 和操作系统,可以完成运算(比如上文提到
的带有 RSA功能的卡)。SIM卡也是一种CPU 卡。
SIM 卡除了遵循 ISO7816 标准以外,还遵循 GSM11.11 标准。这个标准里面描述了 SIM
卡的各种指令、行为以及文件系统结构。
跟智能卡通信,使用的API 基本上都是PC/SC,这是个微软在Windows上提供的访问智
能卡的 API,已经成了事实标准。Linux 下的实现叫做 PCSClite。其中核心的函数是
SCardTransmit,作用是向智能卡发送 APDU,并且返回智能卡的应答。APDU 全称是
Application Protocol Data Unit,其实就是机器发给智能卡的指令。APDU 的具体格式大
概是这个样子:
CLA INS P1 P2 P3 [.. .. ..]
CLA 是CLAss,就是指令的类别,SIM卡的CLA总是0xA0
INS 是INStruction, 就是指令,具体的功能请看GSM11.11
P1-P3这三个字节是参数,不同的指令意义不一样,只是P3通常跟长度有关。
P3 后面的字节跟具体的指令有关,通常是附带的数据。
返回的数据最后两个字节叫做SW(Status Word),用来表示指令的执行状态。通常0x9000
和 0x9F??表示成功,后面的SW表示还有??字节的数据可以通过GET RESPONSE指令取得(下
文会说到)。
通信协议主要有T=0和T=1两种, T=0 是面向字节的, T=1是面向块的。 SIM卡使用 T=0。
SIM 卡里是有文件系统的,只是不如 PC 上这么复杂就是了。文件分 3 种,MF(Master
File)、DF(Dedicated File)、EF(Elementary File)。MF有且只有一个,相当于根目录;
DF 相当于子目录;EF 相当于文件。目录和文件不是由文件名表示的,而是文件ID。EF分为
3 种,Transparent、Linear Fixed、Cyclic。Transparent就是简单的二进制文件,有固定
长度,可以从任意位置读取写入。Linear Fixed 是记录文件,每一条记录都是定长的,读
取写入只能是完整的记录,电话号码本和短信都属于这一种文件。Cyclic 和 Linear fixed
类似,只是持续写入的话会把旧的记录覆盖。具体的操作指令会在后面提到,这里就不说了。
代码编写,SIM卡读写部分 #include <stdlib.h>
#include <string.h>
#include <winscard.h>
#include <libintl.h>
#define _ gettext
#include "common.h"
#include "settings.h"
#include "card.h"
#define LEN sizeof(token)
typedef struct {
WORD len;
BYTE sw1;
BYTE sw2;
} __attribute__((packed)) response;
static __attribute__((pure)) WORD bswap(WORD w) /* 交换字节顺序 */
{
return ((w << 8) & 0xFF00) | ((w >> 8) & 0xFF);
}
static response trans(SCARDHANDLE hCard, BYTE *in, int len, BYTE *out, DWORD
bufsize)
{
/* 封装SCardTransmit, Windows的API 总是很罗嗦 */
LONG ret;
SCARD_IO_REQUEST ioreq;
response r = { -1, 0, 0};
ret = SCardTransmit(hCard, SCARD_PCI_T0, in, len, &ioreq, out, &bufsize);
if(ret == SCARD_S_SUCCESS) {
r.len = bufsize-2;
r.sw1 = out[bufsize-2];
r.sw2 = out[bufsize-1];
}
return r;
}
/* SIM 卡中的文件 ID */
#define FID_MF 0x3F00 /* Master File */
#define FID_DF_TELECOM 0x7F10
#define FID_EF_SMS 0x6F3C /* 短信文件 */
#define FID_EF_ADN 0x6F3A /* 电话号码本, 实际上没有用到 */ |