You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NTAG215卡写入受保护数值与JWT的正确逻辑实现问询

NTAG215 存储可修改数值与只读JWT的正确实现方案

核心逻辑梳理

  1. 数值存储优化
    不要用字符串存储金额,而是将十进制数值转换为整数(比如5432.50 × 100 = 543250),用4字节无符号整数存在单个页面(如页面4)。这样修改余额时直接操作整数,避免字符串解析的错误和开销,还能节省存储空间。

  2. JWT存储与只读锁定
    NTAG215的用户可用页面范围是页面4到230(页面231及之后是密码、锁定控制等系统区域,不可用于数据存储)。JWT从页面5开始写入,按每页4字节分块处理,最后一页不足4字节时补0填充。写完JWT后,通过锁定命令将对应页面设置为只读,确保后续无法修改。

  3. 认证与操作权限
    只有密码认证成功后,才能修改数值页面;JWT页面锁定后,即使认证通过也无法修改,符合只读需求。

完善后的代码实现

import android.nfc.Tag
import android.nfc.tech.MifareUltralight
import android.util.Log
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.ByteOrder

fun writeAndProtectTag(intent: Intent) {
    Thread {
        val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return@Thread
        var mifare: MifareUltralight? = null

        try {
            mifare = MifareUltralight.get(tag)
            mifare.connect()

            // 密码认证(PWD_AUTH命令0x1B)
            val pwd = "-_bA".toByteArray()
            val expectedPack = "cC".toByteArray()
            val authResponse = mifare.transceive(byteArrayOf(0x1B.toByte(), pwd[0], pwd[1], pwd[2], pwd[3]))

            if (authResponse?.size != 2 || authResponse[0] != expectedPack[0] || authResponse[1] != expectedPack[1]) {
                Log.d("NFC", "认证失败:PACK不匹配")
                return@Thread
            }

            // 1. 写入可修改的数值(示例:5432.50 → 转换为543250,用4字节无符号整数存储)
            val amount = 543250 // 代表5432.50
            val amountBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(amount).array()
            mifare.writePage(4, amountBytes)

            // 2. 写入JWT并锁定对应页面
            val jwt = "这里替换为你的350字符左右的JWT字符串"
            val jwtBytes = jwt.encodeToByteArray()
            val startPage = 5
            var currentPage = startPage

            // 分块写入JWT
            for (i in jwtBytes.indices step 4) {
                val pageData = ByteArray(4)
                System.arraycopy(jwtBytes, i, pageData, 0, minOf(4, jwtBytes.size - i))
                mifare.writePage(currentPage++, pageData)
            }

            // 可选:锁定JWT所在页面(使其只读)
            // NTAG215的锁定控制页是页面231,每个字节控制8个页面的锁定状态
            // 计算JWT占用的页面范围,设置对应锁定位(1表示锁定只读)
            // 示例:锁定页面5到页面X,需根据实际占用页面数计算锁定位
            // lockBytes[0] 控制页面0-7,lockBytes[1]控制8-15,以此类推
            // 修改后写入锁定页:mifare.writePage(lockPage, lockBytes)

            Log.d("NFC", "数据写入与保护完成")

        } catch (e: IOException) {
            Log.e("NFC", "IO异常:${e.message}", e)
        } catch (e: Exception) {
            Log.e("NFC", "未知异常:${e.message}", e)
        } finally {
            try {
                mifare?.close()
            } catch (e: IOException) {
                Log.e("NFC", "关闭标签失败:${e.message}", e)
            }
        }
    }.start()
}

关键细节说明

  • 数值存储:用ByteBuffer将整数转换为4字节大端序字节数组,确保跨设备读取的一致性,修改余额时只需重新计算整数并写入页面4即可。
  • JWT分块写入:通过循环按4字节分割JWT字节数组,不足4字节的页面自动补0,符合NTAG215每页4字节的写入要求。
  • 页面锁定(可选):若需严格保证JWT只读,可修改页面231的锁定控制字节,将JWT所在页面的锁定位设为1(具体位映射需参考NTAG215官方手册),锁定后即使认证成功也无法修改这些页面。
  • 错误处理:移除了无用的while (!mifare.isConnected)循环,增加了日志输出,避免空指针异常。

内容的提问来源于stack exchange,提问作者Orlay Garcia Duconge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:25:02