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 = TrueEnd 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是拿来作为单程票的,它的消费充值等流程是由其他人来做的,而且跟具体的卡结构有关,不好讲。