NTAG21X(含NTAG215)密码写保护设置异常求助
NTAG215密码写保护失效问题排查
我编写了一段为NTAG设置密码写保护的代码,通过NFC Tools的内存读取功能已确认密码保护状态生效且写保护开启,但使用自研代码及NFC Tools仍可无需密码写入记录。目标是实现无密码无法写入任何记录的效果,当前测试对象为NTAG215,求排查问题根源。
相关代码
static Future setPasswordWithTag({required NfcTag tag, required String password}) async { bool statusOfTag = false; final pass = password.codeUnits; if (pass.length != 4) { log('Password length should be 4 characters'); return statusOfTag; } MiFare? c = MiFare.from(tag); NfcA? nfcA = NfcA.from(tag); var ndef = Ndef.from(tag); final tagSize = ndef!.maxSize; Uint8List? writePasswordApu, writePackApu, setAuth0Apu; if (tagSize <= 144) { // NTAG213 print("NTAG213"); print(pass); final writePassword = [ 0xA2, 0x2B, int.parse('0x${pass[0]}'), int.parse('0x${pass[1]}'), int.parse('0x${pass[2]}'), int.parse('0x${pass[3]}') ]; final writePack = [0xA2, 0x2C, int.parse('0x${pass[0]}'), int.parse('0x${pass[1]}'), 0xFF, 0xFF]; final setAuth0 = [ 0xA2, 0x29, 0x00, // PROT = 0 (仅写入需密码) 0x00, 0x00, 0x2B // AUTH0 = 0x2B (从此页开始保护) ]; writePasswordApu = Uint8List.fromList(writePassword); writePackApu = Uint8List.fromList(writePack); setAuth0Apu = Uint8List.fromList(setAuth0); } else if (tagSize > 144 && tagSize <= 520) { // NTAG215 print("NTAG215"); final writePassword = [ 0xA2, 0x85, // Password page for NTAG215 int.parse('0x${pass[0]}'), int.parse('0x${pass[1]}'), int.parse('0x${pass[2]}'), int.parse('0x${pass[3]}') ]; print(writePassword); final writePack = [0xA2, 0x86, 0x12, 0x34, 0xFF, 0xFF]; // PACK final setAuth0 = [ 0xA2, 0x83, // ACCESS + AUTH0 config 0x00, // PROT = 0 (仅写保护) 0x00, 0x00, 0x85 // AUTH0 = 0x85 (从密码页开始保护) ]; writePasswordApu = Uint8List.fromList(writePassword); writePackApu = Uint8List.fromList(writePack); setAuth0Apu = Uint8List.fromList(setAuth0); } else if (tagSize > 520) { // NTAG216 print("NTAG216"); final writePassword = [ 0xA2, 0xE5, int.parse('0x${pass[0]}'), int.parse('0x${pass[1]}'), int.parse('0x${pass[2]}'), int.parse('0x${pass[3]}') ]; final writePack = [0xA2, 0xE6, 0x5D, 0x6E, 0xFF, 0xFF]; final setAuth0 = [ 0xA2, 0xE3, 0x00, // PROT = 0 0x00, 0x00, 0xE5 // AUTH0 = 0xE5 ]; writePasswordApu = Uint8List.fromList(writePassword); writePackApu = Uint8List.fromList(writePack); setAuth0Apu = Uint8List.fromList(setAuth0); } try { if (Platform.isIOS) { await c!.sendMiFareCommand(writePasswordApu!); await c.sendMiFareCommand(writePackApu!); await c.sendMiFareCommand(setAuth0Apu!); } else if (Platform.isAndroid) { var a= await nfcA!.transceive(data: writePasswordApu!); var b = await nfcA.transceive(data: writePackApu!); var c = await nfcA.transceive(data: setAuth0Apu!); print("PWD write: $a"); print("PACK write: $b"); print("ACCESS/AUTH0 write: $c"); } await checkPasswordProtection(tag: tag); statusOfTag = true; } catch (e) { print(e.toString()); statusOfTag = false; } return statusOfTag; }
问题根源及修复方案
1. AUTH0配置错误(核心问题)
NTAG215的用户数据页范围是0x04到0x84,你代码中设置AUTH0 = 0x85,仅会对密码页(0x85)及之后的配置页启用认证,所有用户数据页都不在保护范围内,因此无需密码即可写入。
修复:将NTAG215的AUTH0值改为0x00,从页0开始(包含所有用户数据页)强制认证写入:
final setAuth0 = [ 0xA2, 0x83, 0x00, // PROT = 0 (仅写入需密码) 0x00, 0x00, 0x00 // AUTH0 = 0x00 (保护所有页) ];
2. 密码写入逻辑错误
代码中int.parse('0x${pass[0]}')的转换逻辑错误:password.codeUnits返回的是字符的ASCII整数值(比如字符"1"的codeUnit是49),而int.parse('0x49')会将其解析为十六进制的73,导致实际设置的密码与输入不符。
修复:直接使用pass数组的原始整数值:
final writePassword = [ 0xA2, 0x85, pass[0], pass[1], pass[2], pass[3] ];
3. PACK值建议与密码关联
当前代码中PACK值写死为0x1234,虽不影响认证功能,但建议将PACK设置为与密码相关的数值,增强安全性:
final writePack = [0xA2, 0x86, pass[0], pass[1], 0xFF, 0xFF];
4. 验证写入结果
Android平台下,NTAG写命令成功会返回Uint8List.fromList([0x0A]),可在代码中添加判断逻辑确认配置是否生效:
if (!listEquals(a, Uint8List.fromList([0x0A]))) { print("密码页写入失败"); statusOfTag = false; return statusOfTag; }
内容的提问来源于stack exchange,提问作者Csaba Gergely
相关产品推荐
相关产品推荐

