【代码】Python3读写M1卡

前言

Python3读写M1卡

准备工作

  • ACR122U读卡器

下载依赖

1
pip3 install pyscard

工具类

is_key_a:是否使用密钥A验证

True:使用密钥A验证
False:使用密钥B验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
from smartcard.System import readers
from smartcard.CardConnection import CardConnection

class M1CardTool:

# 出厂默认密码
KEY_DEFAULT = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]

def __init__(self):
self.connection = None

def connect(self):
"""
建立连接

:return: 成功
"""
r = readers()
if len(r) == 0:
print("未发现读卡器")
return False
print(f"发现读卡器: {r[0]}")
self.connection = r[0].createConnection()
self.connection.connect(CardConnection.T1_protocol)
print(f"与读卡器建立连接成功: {r[0]}")
return True

def disconnect(self):
"""
断开连接
"""
if self.connection:
self.connection.disconnect()
print(f"与读卡器断开连接成功")

def authenticate_sector(self, block_addr, key=None, is_key_a=True):
"""
认证扇区

:param conn: 连接
:param block_addr: 区块编号,从0开始
:param key: 密码
:param is_key_a: 是否使用密钥A验证密码
:return: 成功
"""

# 使用出厂默认密码
if key is None:
key = self.KEY_DEFAULT

# 0x60 = KeyA, 0x61 = KeyB
key_type = 0x60 if is_key_a else 0x61

# ACR122U 认证指令
apdu = [0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, block_addr, key_type, 0x00] + key
_, sw1, sw2 = self.connection.transmit(apdu)
return sw1 == 0x90 and sw2 == 0x00

def read_block(self, block_addr):
"""
读取块

:param block_addr: 区块编号,从0开始
:return: 块数据
"""

# ACR122U 读取块指令
apdu = [0xFF, 0xB0, 0x00, block_addr, 0x10]
data, sw1, sw2 = self.connection.transmit(apdu)
if sw1 == 0x90 and sw2 == 0x00:
return data
else:
return False

def write_block(self, block_addr, data_16bytes):
"""
写入块

:param block_addr: 区块编号,从0开始
:param data_16bytes: 16字节的数据
:return: 成功
"""

if len(data_16bytes) != 16:
print("必须写入16字节数据")
return False

# ACR122U 写入块指令
apdu = [0xFF, 0xD6, 0x00, block_addr, 0x10] + data_16bytes
_, sw1, sw2 = self.connection.transmit(apdu)
return sw1 == 0x90 and sw2 == 0x00

复制数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
NULL_DATA = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
data_map = {}

input("已插入读卡器,回车确认")
m1 = M1CardTool()
if not m1.connect():
quit()

input("已放入卡片准备读取数据,回车确认")
for i in range(16 * 4):
# 不读密钥块
if i % 4 == 3:
continue
# 计算扇区
sector = i // 4
first_block = sector * 4
authenticate_success = m1.authenticate_sector(first_block)
# 认证扇区
if i == first_block:
if authenticate_success:
print(f"认证扇区成功: 扇区{sector}")
else:
print(f"认证扇区失败: 扇区{sector}")
# 读取数据
data = m1.read_block(i)
if data:
print(f"读取数据成功: 块{i}: {data}")
data_map[i] = data
else:
print(f"读取数据失败: 块{i}, 认证结果: {authenticate_success}")
data_map[i] = NULL_DATA

input("已放入卡片准备写入数据,回车确认")
for i in range(16 * 4):
# 不写密钥块
if i % 4 == 3:
continue
# 计算扇区
sector = i // 4
first_block = sector * 4
authenticate_success = m1.authenticate_sector(first_block)
# 认证扇区
if i == first_block:
if authenticate_success:
print(f"认证扇区成功: 扇区{sector}")
else:
print(f"认证扇区失败: 扇区{sector}")
# 写入数据
if data_map[i] is not None:
success = m1.write_block(i, data_map[i])
if success:
print(f"写入数据成功: 块{i}")
else:
print(f"写入数据失败: 块{i}, 认证结果: {authenticate_success}")
else:
print(f"写入数据失败,由于读取数据失败,此块跳过写入: 块{i}")

m1.disconnect()

完成