Mifare Ultra Light 非接触式IC卡发卡总结
概述:
1、 容量512bit,分为16个page,每个page占4byte
2、 每个page可以通过编程的方式锁定为只读功能
3、 384位(从page4往后)用户读写区域
4、 唯一7字节物理卡号(page0前3个byte加page1)
存储结构:
页号 |
Byte0 |
Byte1 |
Byte2 |
Byte3 |
说明 |
0 |
SN0 |
SN1 |
SN2 |
BCC0 |
只读,存放卡的序列号:Page0前3字节+整个Page1 |
1 |
SN3 |
SN4 |
SN5 |
SN6 |
|
2 |
BCC1 |
保留 |
LOCK0 |
LOCK1 |
只读,通过设置LOCK0和LOCK1可以讲16个page设为只读 |
3 |
OTP0 |
OTP1 |
OTP2 |
OTP3 |
可读写,一次性交易计数器,不可逆 |
4 |
Data0 |
Data1 |
Data2 |
Data3 |
可读写,数据存放区域 |
5 |
Data0 |
Data1 |
Data2 |
Data3 |
|
6 |
Data0 |
Data1 |
Data2 |
Data3 |
|
7 |
Data0 |
Data1 |
Data2 |
Data3 |
|
8 |
Data0 |
Data1 |
Data2 |
Data3 |
|
9 |
Data0 |
Data1 |
Data2 |
Data3 |
|
10 |
Data0 |
Data1 |
Data2 |
Data3 |
|
11 |
Data0 |
Data1 |
Data2 |
Data3 |
|
12 |
Data0 |
Data1 |
Data2 |
Data3 |
|
13 |
Data0 |
Data1 |
Data2 |
Data3 |
|
14 |
Data0 |
Data1 |
Data2 |
Data3 |
|
15 |
Data0 |
Data1 |
Data2 |
Data3 |
总的来说,你可以把UltraLight卡简单地看成是一种存储介质,对它的操作也就是对扇区中每个Page的读取和写入的过程。
UltraLight卡的发卡流程:
第一步:寻卡
dc_card(icdev, cardMode, snr)
dc_anticoll2(icdev, 0, snr2)
dc_select2(icdev, snr2, size)
第二步:写卡
获得想要写入卡片的数据(十六进制字符串形式),调用dc_write_hex函数,写入对应page
关于这个函数有个比较怪的问题,文档中规定,对于Ultralight卡,一次必须写入4个字节,也就是一个Page,但你仍需将你写入的数据以后补0的方式补足16字节,尽管它实际写入的只是前4个字节。自己写的功能函数:
''' <summary> ''' 将进制串写入指定地址的卡片内存中 ''' </summary> ''' <param name="start">要写入的起始块地址</param> ''' <param name="finish">要写入的结束块地址</param> ''' <param name="dataBufHex">要写入的串</param> ''' <returns>写卡是否成功</returns> ''' <remarks></remarks> Private Function Write(ByVal start As Short, ByVal finish As Short, ByVal dataBufHex As String) Dim i As Byte '循环标记 Write = False '假设dataBufHex为字8节,start为4,finsh为5,但对Ultralight来说,一次只能写4个字节,即 '一次只能写一个块,因此需要分两次来写。虽然每次只能写四个字节,但 'dc_write_hex函数规定写入的数据必须为16字节,因此需要做右补0操作 For i = 0 To (finish - start) Dim tmp As String tmp = Mid(dataBufHex, i * 8 + 1, 8) '补0 If Len(tmp) < 32 Then tmp = tmp & New String("0", 32 - Len(tmp)) End If Log("往Page" & (start + i) & "中写数据:" & tmp) st = dc_write_hex(icdev, start + i, tmp) If (st <> 0) Then '写卡失败 Write = False Exit Function End If Next Write = True End Function
第三步:读卡
发好卡后,需要验证写入的数据是否正确,这时你就需要调用dc_read_hex函数读入卡片中的数据,有例子:
st = dc_read_hex(icdev, address, dataBufHex)
这里icdev是通讯设备标识符,address是要读入的起始页地址,dataBufHex是存放读入数据的变量。
dc_read_hex函数一次性读入16字节数据,因此dataBufHex字符串长度最长为32,但是不管你的dataBufHex设成任何长度(只要不大于32),该函数仍然读出16字节数据,只不过它会截取前面的部分放到dataBufHex中返还给你罢了。
其他:
关于发行验证码和交易TAC的计算方法,等过几天总结了CPU卡和M1卡的发卡流程之后再写出来。还有就是卡片的应用,我发的UltraLight是拿来作为单程票的,它的消费充值等流程是由其他人来做的,而且跟具体的卡结构有关,不好讲。