The core library of chameleon-ultra.js. You need to register exactly one adapter to the ChameleonUltra instance.

You can learn how to use @taichunmin/buffer from here.

Click here to expend import example.

Example of import the library using import or require:

// import
import { Buffer, ChameleonUltra } from 'chameleon-ultra.js'
import SerialPortAdapter from 'chameleon-ultra.js/plugin/SerialPortAdapter'
import WebbleAdapter from 'chameleon-ultra.js/plugin/WebbleAdapter'
import WebserialAdapter from 'chameleon-ultra.js/plugin/WebserialAdapter'

// require
const { Buffer, ChameleonUltra } = require('chameleon-ultra.js')
const SerialPortAdapter = require('chameleon-ultra.js/plugin/SerialPortAdapter')
const WebbleAdapter = require('chameleon-ultra.js/plugin/WebbleAdapter')
const WebserialAdapter = require('chameleon-ultra.js/plugin/WebserialAdapter')

Example of import the library in Browser (place at the end of body):

<!-- script -->
<script src="https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/index.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/WebbleAdapter.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/WebserialAdapter.global.js"></script>
<script>
const { Buffer, ChameleonUltra, WebbleAdapter, WebserialAdapter } = window.ChameleonUltraJS
</script>

<!-- module -->
<script type="module">
import { Buffer, ChameleonUltra } from 'https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm'
import WebbleAdapter from 'https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/WebbleAdapter.mjs/+esm'
import WebserialAdapter from 'https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/WebserialAdapter.mjs/+esm'
</script>

<!-- module + async import -->
<script type="module">
const { Buffer, ChameleonUltra } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
const { default: WebbleAdapter } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/WebbleAdapter.mjs/+esm')
const { default: WebserialAdapter } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/WebserialAdapter.mjs/+esm')
</script>

After importing the SDK, you need to register exactly one adapter to the ChameleonUltra instance:

const ultraUsb = new ChameleonUltra()
ultraUsb.use(new WebserialAdapter())
const ultraBle = new ChameleonUltra()
ultraBle.use(new WebbleAdapter())

Constructors

Connection Related

Device Related

Slot Related

Reader Related

Emulator Related

Mifare Classic Related

Mifare Ultralight Related

DFU Related

Internal

Constructors

Connection Related

Device Related

VERSION_SUPPORTED: {
    gte: "2.0";
    lt: "3.0";
} = VERSION_SUPPORTED

The supported version of SDK.

  • Delete all ble bindings.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdBleDeleteAllBonds()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the ble address of device.

    Returns Promise<string>

    The ble address of device.

    async function run (ultra) {
    console.log(await ultra.cmdBleGetAddress()) // 'E8:B6:3D:04:B6:FE'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get current ble pairing key of device.

    Returns Promise<string>

    The ble pairing key.

    async function run (ultra) {
    console.log(await ultra.cmdBleGetPairingKey()) // '123456'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the ble pairing mode of device.

    Returns Promise<boolean>

    true if pairing is required to connect to device, otherwise return false.

    async function run (ultra) {
    console.log(await ultra.cmdBleGetPairingMode()) // false
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the ble pairing key of device.

    Parameters

    • key: string

      The new ble pairing key.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdBleSetPairingKey('123456')
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set if the ble pairing is required when connecting to device.

    Parameters

    • enable: number | boolean

      true to enable pairing mode, false to disable pairing mode.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdBleSetPairingMode(false)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Change device mode to tag reader or tag emulator.

    Parameters

    Returns Promise<void>

    async function run (ultra) {
    const { DeviceMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdChangeDeviceMode(DeviceMode.TAG)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the animation mode of device while wake-up and sleep.

    Returns Promise<AnimationMode>

    The animation mode of device.

    async function run (ultra) {
    const { AnimationMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const mode = await ultra.cmdGetAnimationMode()
    console.log(AnimationMode[mode]) // 'FULL'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get current firmware version of device.

    Returns Promise<`${number}.${number}`>

    Current firmware version of device.

    async function run (ultra) {
    console.log(await ultra.cmdGetAppVersion()) // '1.0'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the battery info of device.

    Returns Promise<{
        level: number;
        voltage: number;
    }>

    The battery info of device.

    async function run (ultra) {
    const battery = await ultra.cmdGetBatteryInfo()
    console.log(JSON.stringify(battery)) // { "voltage": 4192, "level": 99 }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the button long press action of specified button.

    Parameters

    Returns Promise<ButtonAction>

    The button long press action of specified button.

    async function run (ultra) {
    const { ButtonAction, ButtonType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const btnAction = await ultra.cmdGetButtonLongPressAction(ButtonType.BUTTON_A)
    console.log(ButtonAction[btnAction]) // 'CLONE_IC_UID'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the button press action of specified button.

    Parameters

    Returns Promise<ButtonAction>

    The button press action of specified button.

    async function run (ultra) {
    const { ButtonAction, ButtonType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const btnAction = await ultra.cmdGetButtonPressAction(ButtonType.BUTTON_A)
    console.log(ButtonAction[btnAction]) // 'CYCLE_SLOT_INC'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get chipset id of device in hex format.

    Returns Promise<string>

    Chipset id of device in hex format.

    async function run (ultra) {
    console.log(await ultra.cmdGetDeviceChipId()) // 'db1c624228d9634c'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get current mode of device.

    Returns Promise<DeviceMode>

    Current mode of device.

    async function run (ultra) {
    const { DeviceMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const deviceMode = await ultra.cmdGetDeviceMode()
    console.log(DeviceMode[deviceMode]) // 'TAG'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the device is ChameleonUltra or ChameleonLite.

    Returns Promise<DeviceModel>

    async function run (ultra) {
    const { DeviceModel } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const model = await ultra.cmdGetDeviceModel()
    console.log(DeviceModel[model]) // 'ULTRA'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the settings of device.

    Returns Promise<{
        animation: AnimationMode;
        blePairingKey: string;
        blePairingMode: boolean;
        buttonLongPressAction: ButtonAction[];
        buttonPressAction: ButtonAction[];
        version: number;
    }>

    The settings of device.

    async function run (ultra) {
    const settings = await ultra.cmdGetDeviceSettings()
    console.log(JSON.stringify(settings)
    /**
    * {
    * "version": 5,
    * "animation": 0,
    * "buttonPressAction": [1, 2],
    * "buttonLongPressAction": [3, 3],
    * "blePairingMode": false,
    * "blePairingKey": "123456"
    * }
    */
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the git version of firmware.

    Returns Promise<string>

    The git version of firmware.

    async function run (ultra) {
    console.log(await ultra.cmdGetGitVersion()) // '98605be'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the cmds supported by device.

    Returns Promise<Set<Cmd>>

    The cmds supported by device.

    async function run (ultra) {
    const cmds = await ultra.cmdGetSupportedCmds()
    console.log(cmds.size) // 67
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Reset the settings of device to default values.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdResetSettings()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Save the settings of device to persistent storage.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdSaveSettings()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the animation mode of device while wake-up and sleep.

    Parameters

    Returns Promise<void>

    async function run (ultra) {
    const { AnimationMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSetAnimationMode(AnimationMode.SHORT)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the button long press action of specified button.

    Parameters

    Returns Promise<void>

    async function run (ultra) {
    const { ButtonAction, ButtonType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSetButtonLongPressAction(ButtonType.BUTTON_A, ButtonAction.CYCLE_SLOT_INC)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the button press action of specified button.

    Parameters

    Returns Promise<void>

    async function run (ultra) {
    const { ButtonAction, ButtonType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSetButtonPressAction(ButtonType.BUTTON_A, ButtonAction.CYCLE_SLOT_INC)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Permanently wipes Chameleon to factory settings. This will delete all your slot data and custom settings. There's no going back.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdWipeFds()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • To check if the specified cmd is supported by device.

    Parameters

    Returns Promise<boolean>

    true if the specified cmd is supported by device, otherwise return false.

    async function run (ultra) {
    const { Cmd } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(await ultra.isCmdSupported(Cmd.GET_APP_VERSION)) // true
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Check if the firmware version is supported by SDK.

    Returns Promise<boolean>

    true if the firmware version is supported, false otherwise.

    async function run (ultra) {
    if (await ultra.isSupportedAppVersion()) throw new Error('Firmware version is not supported. Please update the firmware.')
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

Slot Related

  • Change the emulation tag type of specified slot.

    Parameters

    • slot: Slot

      The slot to be set.

    • tagType: TagType

      The tag type to be set.

    Returns Promise<void>

    async function run (ultra) {
    const { Slot, TagType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotChangeTagType(Slot.SLOT_1, TagType.MIFARE_1024)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Delete the nick name of the slot

    Parameters

    Returns Promise<boolean>

    true if success, false if slot name is empty.

    async function run (ultra) {
    const { Slot, FreqType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(await ultra.cmdSlotDeleteFreqName(Slot.SLOT_1, FreqType.HF)) // true
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Delete the emulation tag data of specified freq type in specified slot.

    Parameters

    • slot: Slot

      The slot to be deleted.

    • freq: FreqType

      The freq type of slot.

    Returns Promise<void>

    async function run (ultra) {
    const { Slot, FreqType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotDeleteFreqType(Slot.SLOT_1, FreqType.HF)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the active emulation tag slot of device.

    Returns Promise<Slot>

    The active slot of device.

    async function run (ultra) {
    const { Slot } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const slot = await ultra.cmdSlotGetActive()
    console.log(Slot[slot]) // 'SLOT_1'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the nickname of specified freq type in specified slot.

    Parameters

    • slot: Slot

      The slot to be get.

    • freq: FreqType

      The freq type to be get.

    Returns Promise<undefined | string>

    The nickname of specified freq type in specified slot.

    async function run (ultra) {
    const { Slot, FreqType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const name = await ultra.cmdSlotGetFreqName(Slot.SLOT_1, FreqType.HF)
    console.log(name) // 'My Tag'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the slot info of all slots.

    Returns Promise<{
        hfTagType: TagType;
        lfTagType: TagType;
    }[]>

    The slot info of all slots.

    async function run (ultra) {
    const slots = await ultra.cmdSlotGetInfo()
    console.log(JSON.stringify(slots))
    /**
    * [
    * { "hfTagType": 1001, "lfTagType": 100 },
    * { "hfTagType": 1001, "lfTagType": 0 },
    * { "hfTagType": 0, "lfTagType": 100 },
    * { "hfTagType": 0, "lfTagType": 0 },
    * { "hfTagType": 0, "lfTagType": 0 },
    * { "hfTagType": 0, "lfTagType": 0 },
    * { "hfTagType": 0, "lfTagType": 0 },
    * { "hfTagType": 0, "lfTagType": 0 }
    * ]
    */
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get enabled slots.

    Returns Promise<{
        hf: boolean;
        lf: boolean;
    }[]>

    Enabled slots.

    async function run (ultra) {
    const enabledSlots = await ultra.cmdSlotGetIsEnable()
    console.log(JSON.stringify(enabledSlots))
    // [
    // { "hf": true, "lf": true },
    // { "hf": true, "lf": false },
    // { "hf": false, "lf": true },
    // { "hf": false, "lf": false },
    // { "hf": false, "lf": false },
    // { "hf": false, "lf": false },
    // { "hf": false, "lf": false },
    // { "hf": true, "lf": false }
    // ]
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Reset the emulation tag data of specified tag type in specified slot to default values.

    Parameters

    • slot: Slot

      The slot to be reset.

    • tagType: TagType

      The tag type to be reset.

    Returns Promise<void>

    async function run (ultra) {
    const { Slot, TagType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotResetTagType(Slot.SLOT_1, TagType.MIFARE_1024)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • The SlotSettings, hf tag data and lf tag data will be written to persistent storage. But the slot nickname is not affected by this command.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMf1EmuWriteBlock(1, Buffer.alloc(16))
    await ultra.cmdSlotSaveSettings()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Change the active emulation tag slot of device.

    Parameters

    • slot: Slot

      The slot to be active.

    Returns Promise<void>

    async function run (ultra) {
    const { Slot } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotSetActive(Slot.SLOT_1)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Enable or disable the specified slot.

    Parameters

    • slot: Slot

      The slot to be enable/disable.

    • freq: FreqType
    • enable: number | boolean

      true to enable the slot, false to disable the slot.

    Returns Promise<void>

    async function run (ultra) {
    const { FreqType, Slot } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotSetEnable(Slot.SLOT_1, FreqType.HF, true)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the nickname of specified freq type in specified slot.

    Parameters

    • slot: Slot

      The slot to be set.

    • freq: FreqType

      The freq type to be set.

    • name: string

      The name to be set. The byteLength of name should between 1 and 32.

    Returns Promise<void>

    async function run (ultra) {
    const { Slot, FreqType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotSetFreqName(Slot.SLOT_1, FreqType.HF, 'My Tag')
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

Reader Related

  • Scan em410x tag and print id

    Returns Promise<Buffer>

    The id of em410x tag.

    async function run (ultra) {
    const id = await ultra.cmdEm410xScan()
    console.log(id.toString('hex')) // 'deadbeef88'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Write id of em410x tag to t55xx tag.

    Parameters

    • id: Buffer

      The id of em410x tag.

    • newKey: Buffer

      The new key of t55xx tag.

    • oldKeys: Buffer[]

      The keys to be checked. Maximum length is 125.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const id = Buffer.from('deadbeef88', 'hex')
    // https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/t55xx_default_pwds.dic
    const newKey = Buffer.from('20206666', 'hex')
    const oldKeys = Buffer.from('5124364819920427', 'hex').chunk(4)
    await ultra.cmdEm410xWriteToT55xx(id, newKey, oldKeys)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Send raw NfcA data to a tag and receive the response.

    Parameters

    • opts: {
          activateRfField?: boolean;
          appendCrc?: boolean;
          autoSelect?: boolean;
          checkResponseCrc?: boolean;
          data?: Buffer;
          dataBitLength?: number;
          keepRfField?: boolean;
          timeout?: number;
          waitResponse?: boolean;
      }
      • OptionalactivateRfField?: boolean

        Set true to activate RF field. If data is not empty or autoSelect is true, activateRfField will be set to true.

      • OptionalappendCrc?: boolean

        Set true to add CRC before sending data.

      • OptionalautoSelect?: boolean

        Set true to automatically select card before sending data.

      • OptionalcheckResponseCrc?: boolean

        Set true to verify CRC of response and remove. If CRC of response is valid, CRC will be removed from response, otherwise will throw HF_ERR_CRC error.

      • Optionaldata?: Buffer

        The data to be send. If appendCrc is true, the maximum length of data is 62, otherwise is 64.

      • OptionaldataBitLength?: number

        Number of bits to send. Useful for send partial byte. dataBitLength is incompatible with appendCrc.

      • OptionalkeepRfField?: boolean

        Set true to keep the RF field active after sending.

      • Optionaltimeout?: number

        Default value is 1000 ms. Maximum timeout for reading tag response in ms while waitResponse is true.

      • OptionalwaitResponse?: boolean

        Default value is true. Set false to skip reading tag response.

    Returns Promise<Buffer>

    The response from tag.

  • Scan 14a tag, and return basic information. The device mode must be set to READER before using this command.

    Returns Promise<{
        atqa: Buffer;
        ats: Buffer;
        sak: Buffer;
        uid: Buffer;
    }[]>

    The basic infomation of scanned tag.

    This command will throw an error if tag not scanned or any error occured.

    async function run (ultra) {
    const antiColl = _.first(await ultra.cmdHf14aScan())
    console.log(_.mapValues(antiColl, val => val.toString('hex')))
    // { uid: '040dc4420d2981', atqa: '4400', sak: '00', ats: ''}
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the info composed of cmdHf14aScan() and cmdMf1TestNtLevel().

    Returns Promise<{
        antiColl: {
            atqa: Buffer;
            ats: Buffer;
            sak: Buffer;
            uid: Buffer;
        };
        nxpTypeBySak?: string;
        prngType?: Mf1PrngType;
    }[]>

    The info about 14a tag and mifare protocol.

    async function run (ultra) {
    const { Mf1PrngType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const tag = _.first(await ultra.hf14aInfo())
    console.log(tag.nxpTypeBySak) // 'MIFARE Classic 1K | Plus SE 1K | Plug S 2K | Plus X 2K'
    console.log(Mf1PrngType[tag.prngType]) // 'WEAK'
    console.log(_.mapValues(tag.antiColl, val => val.toString('hex')))
    // { uid: 'dbe3d63d', atqa: '0400', sak: '08', ats: '' }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

Emulator Related

  • Get the em410x id of actived slot.

    Returns Promise<Buffer>

    The em410x id of actived slot.

    async function run (ultra) {
    const id = await ultra.cmdEm410xGetEmuId()
    console.log(id.toString('hex')) // 'deadbeef88'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the em410x id of actived slot.

    Parameters

    • id: Buffer

      The em410x id of actived slot.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdEm410xSetEmuId(Buffer.from('deadbeef88', 'hex'))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get anti-collision data from actived slot.

    Returns Promise<null | {
        atqa: Buffer;
        ats: Buffer;
        sak: Buffer;
        uid: Buffer;
    }>

    The anti-collision data from actived slot.

    async function run (ultra) {
    const res = await ultra.cmdHf14aGetAntiCollData()
    console.log(JSON.stringify(res))
    // {
    // "uid": { "type": "Buffer", "data": [222, 173, 190, 239] },
    // "atqa": { "type": "Buffer", "data": [4, 0] },
    // "sak": { "type": "Buffer", "data": [8] },
    // "ats": { "type": "Buffer", "data": [] }
    // }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mifare anti-collision data of actived slot.

    Parameters

    • opts: {
          atqa: Buffer;
          ats?: Buffer;
          sak: Buffer;
          uid: Buffer;
      }
      • atqa: Buffer

        2 bytes, the new atqa to be set.

      • Optionalats?: Buffer

        The new ats to be set.

      • sak: Buffer

        1 byte, the new sak to be set.

      • uid: Buffer

        The new uid to be set.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdHf14aSetAntiCollData({
    atqa: Buffer.from('0400', 'hex'),
    sak: Buffer.from('08', 'hex'),
    uid: Buffer.from('01020304', 'hex')
    })
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

Mifare Classic Related

  • Acquire the data from mifare darkside attack.

    Parameters

    • block: number

      The target block.

    • keyType: Mf1KeyType

      The target key type.

    • isFirst: number | boolean

      true if this is the first attack.

    • syncMax: number = 30

      The max sync count of darkside attack.

    Returns Promise<{
        ar?: Buffer;
        ks?: Buffer;
        nr?: Buffer;
        nt?: Buffer;
        par?: Buffer;
        status: DarksideStatus;
        uid?: Buffer;
    }>

    The data from mifare darkside attack.

    async function run (ultra) {
    const { Mf1KeyType, DarksideStatus } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const res1 = await ultra.cmdMf1AcquireDarkside(0, Mf1KeyType.KEY_A, true)
    console.log(res1)
    const res2 = {
    status: `${DarksideStatus[res1.status]} (${res1.status})`,
    ...(res1.status !== DarksideStatus.OK ? {} : {
    ar: res1.ar.toString('hex'),
    ks: res1.ks.toString('hex'),
    nr: res1.nr.toString('hex'),
    nt: res1.nt.toString('hex'),
    par: res1.par.toString('hex'),
    uid: res1.uid.toString('hex'),
    }),
    }
    console.log(res2)
    // {
    // "ar": "00000000",
    // "ks": "0c0508080f04050a",
    // "nr": "00000000",
    // "nt": "b346fc3d",
    // "par": "0000000000000000",
    // "status": "OK (0)",
    // "uid": "d3efed0c"
    // }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

    If you want to use darkside attack to recover the key, you can use the following example code:

    async function run (ultra) {
    const { Buffer, DarksideStatus, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const block = 0
    const keyType = Mf1KeyType.KEY_A
    const key = await Crypto1.darkside(
    async attempt => {
    const acquired = await ultra.cmdMf1AcquireDarkside(block, keyType, attempt === 0)
    console.log(_.mapValues(acquired, buf => Buffer.isBuffer(buf) ? buf.toString('hex') : buf))
    if (acquired.status === DarksideStatus.LUCKY_AUTH_OK) throw new Error('LUCKY_AUTH_OK')
    if (acquired.status !== DarksideStatus.OK) throw new Error('card is not vulnerable to Darkside attack')
    return acquired
    },
    async key => {
    return await ultra.cmdMf1CheckBlockKey({ block, keyType, key })
    },
    )
    console.log(`key founded: ${key.toString('hex')}`)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Use a known key to do the mifare nested attack.

    Parameters

    • known: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The info of known key.

      • block: number

        The block of known key.

      • key: Buffer

        The known key.

      • keyType: Mf1KeyType

        The key type of known key.

    • target: {
          block: number;
          keyType: Mf1KeyType;
      }

      The info of target key to be attack.

      • block: number

        The block of target key.

      • keyType: Mf1KeyType

        The key type of target key.

    Returns Promise<{
        nt1: Buffer;
        nt2: Buffer;
        par: number;
    }[]>

    The result of mifare nested attack.

    • nt1: Unblocked explicitly random number
    • nt2: Random number of nested verification encryption
    • par: The puppet test of the communication process of nested verification encryption, only the 'low 3 digits', that is, the right 3
    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const res1 = await ultra.cmdMf1TestNtDistance({ block: 0, keyType: Mf1KeyType.KEY_A, key })
    const res2 = await ultra.cmdMf1AcquireNested(
    { block: 0, keyType: Mf1KeyType.KEY_A, key },
    { block: 4, keyType: Mf1KeyType.KEY_A },
    )
    const res = {
    uid: res1.uid.toString('hex'),
    dist: res1.dist.toString('hex'),
    atks: _.map(res2, item => ({
    nt1: item.nt1.toString('hex'),
    nt2: item.nt2.toString('hex'),
    par: item.par,
    }))
    }
    console.log(res)
    // {
    // uid: '877209e1',
    // dist: '00000080',
    // atks: [
    // { nt1: '35141fcb', nt2: '40430522', par: 7 },
    // { nt1: 'cff2b3ef', nt2: '825ba8ea', par: 5 },
    // ]
    // }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Use a known key to do the mifare static nested attack.

    Parameters

    • known: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The info of known key.

      • block: number

        The block of known key.

      • key: Buffer

        The known key.

      • keyType: Mf1KeyType

        The key type of known key.

    • target: {
          block: number;
          keyType: Mf1KeyType;
      }

      The info of target key to be attack.

      • block: number

        The block of target key.

      • keyType: Mf1KeyType

        The key type of target key.

    Returns Promise<{
        atks: {
            nt1: Buffer;
            nt2: Buffer;
        }[];
        uid: Buffer;
    }>

    The result of mifare static nested attack.

    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const res1 = await ultra.cmdMf1AcquireStaticNested({
    block: 0,
    keyType: Mf1KeyType.KEY_A,
    key
    }, {
    block: 4,
    keyType: Mf1KeyType.KEY_A
    })
    const res = {
    uid: res1.uid.toString('hex'),
    atks: _.map(res1.atks, item => ({ nt1: item.nt1.toString('hex'), nt2: item.nt2.toString('hex') })),
    }
    console.log(res)
    // {
    // uid: 'b908a16d',
    // atks: [
    // { nt1: '01200145', nt2: '81901975' },
    // { nt1: '01200145', nt2: 'cdd400f3' },
    // ],
    // }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Check if the key is valid for specified block and key type.

    Parameters

    • opts: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The info of key to be checked.

      • block: number

        The block of key to be checked.

      • key: Buffer

        The key to be checked.

      • keyType: Mf1KeyType

        The type of key to be checked.

    Returns Promise<boolean>

    true if the key is valid for specified block and key type.

    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    console.log(await ultra.cmdMf1CheckBlockKey({
    block: 0,
    keyType: Mf1KeyType.KEY_A,
    key,
    })) // true
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Given a list of keys, check which is the correct key A and key B of the sectors. If you want to check more than 83 keys, you can use mf1CheckKeysOfSectors().

    Parameters

    • opts: {
          keys: Buffer[];
          mask: Buffer;
      }
      • keys: Buffer[]

        The keys to be checked. Maximum length is 83.

      • mask: Buffer

        The mask of sectors. 80 bits, 2 bits/sector, the first bit is key A, the second bit is key B, 0b1 represent to skip checking the key.

    Returns Promise<null | {
        found: Buffer;
        sectorKeys: (null | Buffer)[];
    }>

    • found: 80 bits, 2 bits/sector, the first bit is key A, the second bit is key B, 0b1 represent key is found.
    • sectorKeys: 80 keys, 2 keys/sector, the first key is key A, the second key is key B. null represent key is not found.
    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const mask = Buffer.from('00000000FFFFFFFFFFFF', 'hex')
    const keys = Buffer.from('FFFFFFFFFFFF\n000000000000\nA0A1A2A3A4A5\nD3F7D3F7D3F7', 'hex').chunk(6)
    const tsStart = Date.now()
    const result = await ultra.cmdMf1CheckKeysOfSectors({ keys, mask })
    console.log(`Time: ${Date.now() - tsStart}ms`)
    const replacer = function (k, v) { return Buffer.isBuffer(this[k]) ? this[k].toString('hex') : v }
    console.log(JSON.stringify(result, replacer, 2))
    }
    // {
    // "found": "ffffffff000000000000",
    // "sectorKeys": [
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // "ffffffffffff", "ffffffffffff", "ffffffffffff", "ffffffffffff",
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // null, null, null, null,
    // ]
    // }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mifare block data of actived slot.

    Parameters

    • offset: number = 0

      The start block of actived slot.

    • length: number = 1

      The count of blocks to be get.

    Returns Promise<Buffer>

    The mifare block data of actived slot.

    async function run (ultra) {
    const data = await ultra.cmdMf1EmuReadBlock(1)
    console.log(data.toString('hex')) // '00000000000000000000000000000000'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mifare block data of actived slot.

    Parameters

    • offset: number

      The start block of actived slot.

    • data: Buffer

      The data to be set. the length of data should be multiples of 16.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMf1EmuWriteBlock(1, Buffer.alloc(16))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mode of actived slot that using anti-collision data from block 0 for 4 byte UID tags or not.

    Returns Promise<boolean>

    The mode of actived slot that using anti-collision data from block 0 for 4 byte UID tags or not.

    async function run (ultra) {
    console.log(await ultra.cmdMf1GetAntiCollMode()) // false
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the count of mifare MFKey32 detections.

    Returns Promise<number>

    The count of mifare MFKey32 detections.

    async function run (ultra) {
    console.log(await ultra.cmdMf1GetDetectionCount()) // 0
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the feature of mifare MFKey32 detections is enabled or not.

    Returns Promise<boolean>

    true if the feature of mifare MFKey32 detections is enabled, otherwise return false.

    async function run (ultra) {
    console.log(await ultra.cmdMf1GetDetectionEnable()) // false
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the data of mifare MFKey32 detections.

    Parameters

    • offset: number = 0

      The start log of detections to be get.

    Returns Promise<{
        ar: Buffer;
        block: number;
        isKeyB: boolean;
        isNested: boolean;
        nr: Buffer;
        nt: Buffer;
        uid: Buffer;
    }[]>

    The mifare MFKey32 detections.

    async function run (ultra) {
    const logs = await ultra.cmdMf1GetDetectionLogs(0)
    console.log(logs)
    /**
    * {
    * "block": 2,
    * "isKeyB": 1,
    * "isNested": 0,
    * "uid": Buffer.from('65535d33', 'hex'),
    * "nt": Buffer.from('cb7b9ed9', 'hex'),
    * "nr": Buffer.from('5a8ffec6', 'hex'),
    * "ar": Buffer.from('5c7c6f89', 'hex'),
    * }
    */
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mifare settings of actived slot.

    Returns Promise<{
        antiColl: boolean;
        detection: boolean;
        gen1a: boolean;
        gen2: boolean;
        write: Mf1EmuWriteMode;
    }>

    The mifare settings of actived slot.

    async function run (ultra) {
    const mf1Settings = await ultra.cmdMf1GetEmuSettings()
    console.log(JSON.stringify(mf1Settings))
    /**
    * {
    * "detection": false,
    * "gen1a": false,
    * "gen2": false,
    * "antiColl": false,
    * "write": 0
    * }
    */
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mifare gen1a mode of actived slot.

    Returns Promise<boolean>

    The mifare gen1a mode of actived slot.

    async function run (ultra) {
    console.log(await ultra.cmdMf1GetGen1aMode()) // false
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mifare gen2 mode of actived slot.

    Returns Promise<boolean>

    The mifare gen2 mode of actived slot.

    async function run (ultra) {
    console.log(await ultra.cmdMf1GetGen2Mode()) // false
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mifare write mode of actived slot.

    Returns Promise<Mf1EmuWriteMode>

    The mifare write mode of actived slot.

    async function run (ultra) {
    console.log(await ultra.cmdMf1GetWriteMode()) // 0
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Test whether it is mifare classic tag.

    Returns Promise<boolean>

    true if tag is mifare classic tag, otherwise return false.

    async function run (ultra) {
    console.log(await ultra.cmdMf1IsSupport()) // true
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Read block data from a mifare tag.

    Parameters

    • opts: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The block to be read and the key info of the block.

      • block: number

        The block to be read.

      • key: Buffer

        The key of the block.

      • keyType: Mf1KeyType

        The key type of the block.

    Returns Promise<Buffer>

    The block data read from a mifare tag.

    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const block1 = await ultra.cmdMf1ReadBlock({
    block: 1,
    keyType: Mf1KeyType.KEY_A,
    key,
    })
    console.log(block1.toString('hex')) // '00000000000000000000000000000000'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mode of actived slot that using anti-collision data from block 0 for 4 byte UID tags or not.

    Parameters

    • enable: number | boolean

      true to enable the mode, false to disable the mode.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdMf1SetAntiCollMode(false)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Enable or disable the mifare MFKey32 detection and clear the data of detections.

    Parameters

    • enable: number | boolean

      true to enable the detection, false to disable the detection.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdMf1SetDetectionEnable(true)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mifare gen1a mode of actived slot.

    Parameters

    • enable: number | boolean

      true to enable the gen1a mode, false to disable the gen1a mode.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdMf1SetGen1aMode(false)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mifare gen2 mode of actived slot.

    Parameters

    • enable: number | boolean

      true to enable the gen2 mode, false to disable the gen2 mode.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdMf1SetGen2Mode(false)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the mifare write mode of actived slot.

    Parameters

    Returns Promise<void>

    async function run (ultra) {
    const { Mf1EmuWriteMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMf1SetWriteMode(Mf1EmuWriteMode.NORMAL)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Dectect the nt distance of mifare protocol.

    Parameters

    • known: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The info of known key.

      • block: number

        The block of known key.

      • key: Buffer

        The known key.

      • keyType: Mf1KeyType

        The key type of known key.

    Returns Promise<{
        dist: Buffer;
        uid: Buffer;
    }>

    The nt distance of mifare protocol.

    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const res1 = await ultra.cmdMf1TestNtDistance({ block: 0, keyType: Mf1KeyType.KEY_A, key })
    const res2 = await ultra.cmdMf1AcquireNested(
    { block: 0, keyType: Mf1KeyType.KEY_A, key },
    { block: 4, keyType: Mf1KeyType.KEY_A },
    )
    const res = {
    uid: res1.uid.toString('hex'),
    dist: res1.dist.toString('hex'),
    atks: _.map(res2, item => ({
    nt1: item.nt1.toString('hex'),
    nt2: item.nt2.toString('hex'),
    par: item.par,
    }))
    }
    console.log(res)
    // {
    // uid: '877209e1',
    // dist: '00000080',
    // atks: [
    // { nt1: '35141fcb', nt2: '40430522', par: 7 },
    // { nt1: 'cff2b3ef', nt2: '825ba8ea', par: 5 },
    // ]
    // }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Check the nt level of mifare protocol.

    Returns Promise<Mf1PrngType>

    The nt level of mifare protocol.

    async function run (ultra) {
    const { Mf1PrngType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(Mf1PrngType[await ultra.cmdMf1TestPrngType()]) // 'WEAK'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • MIFARE Classic manipulate value block

    • Decrement: decrement value by X (0 ~ 2147483647) from src to dst
    • Increment: increment value by X (0 ~ 2147483647) from src to dst
    • Restore: copy value from src to dst (Restore and Transfer)

    Parameters

    • src: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The key info of src block.

      • block: number

        The block of src block.

      • key: Buffer

        The key of src block.

      • keyType: Mf1KeyType

        The key type of src block.

    • operator: Mf1VblockOperator

      The operator of value block.

    • operand: number

      The operand of value block.

    • dst: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The key info of dst block.

      • block: number

        The block of dst block.

      • key: Buffer

        The key of dst block.

      • keyType: Mf1KeyType

        The key type of dst block.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer, Mf1KeyType, Mf1VblockOperator } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const src = { block: 4, keyType: Mf1KeyType.KEY_A, key }
    await ultra.mf1VblockSetValue(src, { value: 2 })
    console.log(await ultra.mf1VblockGetValue(src))
    await ultra.cmdMf1VblockManipulate(
    { block: 4, keyType: Mf1KeyType.KEY_A, key },
    Mf1VblockOperator.DECREMENT, 1,
    { block: 4, keyType: Mf1KeyType.KEY_A, key },
    )
    console.log(await ultra.mf1VblockGetValue(src))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Write data to a mifare tag.

    Parameters

    • opts: {
          block: number;
          data: Buffer;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The block to be written and the key info of the block.

      • block: number

        The block to be written.

      • data: Buffer

        The block data to be written.

      • key: Buffer

        The key of the block.

      • keyType: Mf1KeyType

        The key type of the block.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const block1 = Buffer.from('00000000000000000000000000000000', 'hex')
    await ultra.cmdMf1WriteBlock({
    block: 1,
    keyType: Mf1KeyType.KEY_A,
    key,
    data: block1,
    })
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Mifare Classic check keys of sectors.

    Parameters

    • opts: {
          chunkSize?: number;
          keys: Buffer[];
          mask?: Buffer;
          maxSectors?: number;
          onChunkKeys?: ((opts: {
              keys: Buffer[];
              mask: Buffer;
          }) => Promise<unknown>);
      }
      • OptionalchunkSize?: number

        keys will be chunked by this size.

      • keys: Buffer[]

        The keys to be checked.

      • Optionalmask?: Buffer

        The mask of sectors. 80 bits, 2 bits/sector, the first bit is key A, the second bit is key B, 0b1 represent to skip checking the key.

      • OptionalmaxSectors?: number

        The max sectors to be check.

      • OptionalonChunkKeys?: ((opts: {
            keys: Buffer[];
            mask: Buffer;
        }) => Promise<unknown>)

        The callback function to be invoked before checking every chunk of keys.

          • (opts): Promise<unknown>
          • Parameters

            • opts: {
                  keys: Buffer[];
                  mask: Buffer;
              }
              • keys: Buffer[]
              • mask: Buffer

            Returns Promise<unknown>

    Returns Promise<(null | Buffer)[]>

  • Given a list of keys, check which is the correct key A and key B of the sector.

    Parameters

    • sector: number

      The sector number to be checked.

    • keys: Buffer[]

      The keys dictionary.

    Returns Promise<{
        96?: Buffer;
        97?: Buffer;
    }>

    The Key A and Key B of the sector.

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const keys = Buffer.from('FFFFFFFFFFFF\n000000000000\nA0A1A2A3A4A5\nD3F7D3F7D3F7', 'hex').chunk(6)
    const sectorKey = await ultra.mf1CheckSectorKeys(0, keys)
    console.log(_.mapValues(sectorKey, key => key.toString('hex')))
    // { "96": "ffffffffffff", "97": "ffffffffffff" }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Read blocks from Mifare Classic Gen1a.

    Parameters

    • offset: number

      The start block of Mifare Classic Gen1a.

    • length: number = 1

      The amount of blocks to read.

    Returns Promise<Buffer>

    The blocks data.

    async function run (ultra) {
    const card = await ultra.mf1Gen1aReadBlocks(0, 64)
    console.log(_.map(card.chunk(16), chunk => chunk.toString('hex')).join('\n'))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Write blocks to Mifare Classic Gen1a.

    Parameters

    • offset: number

      The start block of Mifare Classic Gen1a.

    • data: Buffer

      The blocks data to write.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.mf1Gen1aWriteBlocks(1, new Buffer(16))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Send Mifare Classic HALT command and close RF field.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.mf1Halt()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Check acl bytes of ACL, block or sector.

    Parameters

    • data: Buffer

      Data of ACL, block or sector.

    Returns boolean

    true if the acl bytes is valid, false otherwise.

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(ultra.mf1IsValidAcl(Buffer.from('ff078069', 'hex'))) // true
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Read the sector data of Mifare Classic by given keys.

    Parameters

    • sector: number

      The sector number to be read.

    • keys: Buffer[]

      The keys dictionary.

    Returns Promise<{
        data: Buffer;
        success: boolean[];
    }>

    The sector data and the read status of each block.

    async function run (ultra) {
    const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const keys = Buffer.from('FFFFFFFFFFFF\n000000000000\nA0A1A2A3A4A5\nD3F7D3F7D3F7', 'hex').chunk(6)
    const { data, success } = await ultra.mf1ReadSectorByKeys(0, keys)
    console.log({ data: data.toString('hex'), success })
    // { "data": "...", "success": [true, true, true, true] }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get value from opts block (MIFARE Classic value block)

    Parameters

    • opts: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The key info of opts block.

      • block: number

        The block of opts block.

      • key: Buffer

        The key of opts block.

      • keyType: Mf1KeyType

        The key type of opts block.

    Returns Promise<{
        adr: number;
        value: number;
    }>

    The value and address of opts block.

    async function run (ultra) {
    const { Buffer, Mf1KeyType, Mf1VblockOperator } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const src = { block: 4, keyType: Mf1KeyType.KEY_A, key }
    await ultra.mf1VblockSetValue(src, { value: 2 })
    console.log(await ultra.mf1VblockGetValue(src))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set value X (-2147483647 ~ 2147483647) to dst block (MIFARE Classic value block)

    Parameters

    • dst: {
          block: number;
          key: Buffer;
          keyType: Mf1KeyType;
      }

      The key info of dst block.

      • block: number

        The block of dst block.

      • key: Buffer

        The key of dst block.

      • keyType: Mf1KeyType

        The key type of dst block.

    • val: {
          adr?: number;
          value?: number;
      }

      The value and address to be set.

      • Optionaladr?: number

        The address to be set. Default is dst.block.

      • Optionalvalue?: number

        The value to be set. Default is 0.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer, Mf1KeyType, Mf1VblockOperator } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const key = Buffer.from('FFFFFFFFFFFF', 'hex')
    const src = { block: 4, keyType: Mf1KeyType.KEY_A, key }
    await ultra.mf1VblockSetValue(src, { value: 2 })
    console.log(await ultra.mf1VblockGetValue(src))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Write the sector data of Mifare Classic by given keys.

    Parameters

    • sector: number

      The sector number to be written.

    • keys: Buffer[]

      The key dictionary.

    • data: Buffer

      Sector data

    Returns Promise<{
        success: boolean[];
    }>

    the write status of each block.

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const keys = Buffer.from('FFFFFFFFFFFF\n000000000000\nA0A1A2A3A4A5\nD3F7D3F7D3F7', 'hex').chunk(6)
    const data = Buffer.concat([
    Buffer.from('00000000000000000000000000000000', 'hex'),
    Buffer.from('00000000000000000000000000000000', 'hex'),
    Buffer.from('00000000000000000000000000000000', 'hex'),
    Buffer.from('ffffffffffffff078069ffffffffffff', 'hex'),
    ])
    const { success } = await ultra.mf1WriteSectorByKeys(1, keys, data)
    console.log(success)
    // [true, true, true, true]
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the blockNo of sector trailer.

    Parameters

    • sector: number

      The sector number.

    Returns number

    The blockNo of sector trailer.

    async function run () {
    const { ChameleonUltra } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(ChameleonUltra.mf1TrailerBlockNoOfSector(0))
    // 3
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

Mifare Ultralight Related

  • Read the counter and tearing of actived slot.

    NTAG21x features a NFC counter function. The NFC counter is enabled or disabled with the NFC_CNT_EN bit. This function enables NTAG21x to automatically increase the 24 bit counter value, triggered by the first valid READ or FAST_READ command after the NTAG21x tag is powered by an RF field.

    Parameters

    • addr: number

      The address of the counter.

    Returns Promise<{
        counter?: number;
        tearing?: boolean;
    }>

    • counter: The counter of the specified address.
    • tearing: The slot is in tearing mode or not.
    async function run (ultra) {
    console.log(await ultra.cmdMfuGetEmuCounter(0))
    // { "counter": 0, "tearing": false }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the number of pages available in the actived slot.

    Returns Promise<number>

    The number of pages available in the actived slot.

    async function run (ultra) {
    console.log(await ultra.cmdMfuGetEmuPageSize()) // 135
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the signature of actived slot. NTAG21x features a cryptographically supported originality check. The signature is used to verify with a certain confidence that the tag is using an IC manufactured by NXP Semiconductors. The signature digital is based on standard Elliptic Curve Cryptography (curve name secp128r1), according to the ECDSA algorithm.

    Returns Promise<undefined | Buffer>

    The signature of actived slot.

    async function run (ultra) {
    const data = await ultra.cmdMfuGetEmuSignature()
    console.log(data.toString('hex')) // '0000000000000000000000000000000000000000000000000000000000000000'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the version of actived slot. The version is used to retrieve information on the NTAG family, the product version, storage size and other product data required to identify the specific NTAG21x.

    Returns Promise<undefined | Buffer>

    The version of actived slot.

    async function run (ultra) {
    const data = await ultra.cmdMfuGetEmuVersion()
    console.log(data.toString('hex')) // '0004040201001103'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the magic mode of actived slot.

    If the actived slot is in magic mode, all read and write protection is bypassed.

    • The UID (page 0-1) can be write.
    • Static Lock Bytes (page 2) and Dynamic Lock Bytes can be write with any value.
    • The Capability Container CC of NTAG (page 3) can be write with any value.
    • PWD and PACK can be read.
    • All other pages can be read/write without authentication.
    • The counter of NTAG can be read without authentication.

    Returns Promise<boolean>

    The magic mode of actived slot.

    async function run (ultra) {
    console.log(await ultra.cmdMfuGetMagicMode()) // false
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the page data of actived slot.

    Parameters

    • offset: number = 0

      The start page of actived slot.

    • length: number = 1

      The count of pages to be get. Must satisfy: 1 <= length <= 128.

    Returns Promise<Buffer>

    The page data of actived slot.

    async function run (ultra) {
    const data = await ultra.cmdMfuReadEmuPage(1)
    console.log(data.toString('hex')) // 'fa5c6480'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Reset the authentication failed counter of actived slot.

    Returns Promise<number>

    The original value of the unsuccessful auth counter before reset.

    async function run (ultra) {
    console.log(await ultra.cmdMfuResetEmuAuthFailedCounter()) // 0
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the counter and reset tearing of actived slot.

    NTAG21x features a NFC counter function. The NFC counter is enabled or disabled with the NFC_CNT_EN bit. This function enables NTAG21x to automatically increase the 24 bit counter value, triggered by the first valid READ or FAST_READ command after the NTAG21x tag is powered by an RF field.

    Parameters

    • opts: {
          addr?: number;
          counter?: number;
          resetTearing?: boolean;
      }
      • Optionaladdr?: number

        The address of the counter.

      • Optionalcounter?: number

        The counter to be write. The counter must be a 24-bit unsigned integer.

      • OptionalresetTearing?: boolean

        true to reset tearing.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdMfuSetEmuCounter({ addr: 0, counter: 1 })
    console.log(await ultra.cmdMfuGetEmuCounter(0))
    // { "counter": 1, "tearing": false }
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the signature of actived slot. NTAG21x features a cryptographically supported originality check. The signature is used to verify with a certain confidence that the tag is using an IC manufactured by NXP Semiconductors. The signature digital is based on standard Elliptic Curve Cryptography (curve name secp128r1), according to the ECDSA algorithm.

    Parameters

    • signature: Buffer

      The signature. The signature must be a 32 bytes Buffer.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const signature = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
    await ultra.cmdMfuSetEmuSignature(signature)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the version of actived slot. The version is used to retrieve information on the NTAG family, the product version, storage size and other product data required to identify the specific NTAG21x.

    Parameters

    • version: Buffer

      The version of actived slot.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMfuSetEmuVersion(Buffer.from('0004040201001103', 'hex'))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the magic mode of actived slot.

    If the actived slot is in magic mode, all read and write protection is bypassed.

    • The UID (page 0-1) can be write.
    • Static Lock Bytes (page 2) and Dynamic Lock Bytes can be write with any value.
    • The Capability Container CC of NTAG (page 3) can be write with any value.
    • PWD and PACK can be read.
    • All other pages can be read/write without authentication.
    • The counter of NTAG can be read without authentication.

    Parameters

    • enable: number | boolean

      The magic mode of actived slot.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdMfuSetMagicMode(false)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Set the page data of actived slot.

    Parameters

    • offset: number

      The start page of actived slot.

    • data: Buffer

      The data to be write. Length of data must be multiples of 4 and satisfy: 4 <= data.length <= 508.

    Returns Promise<void>

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMfuWriteEmuPage(1, Buffer.from('fa5c6480', 'hex'))
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Assert the tag type of actived slot is Mifare Ultralight like. Throw an error if the tag type is not Mifare Ultralight like.

    Returns Promise<TagType>

    The tag type of actived slot.

    async function run (ultra) {
    const { TagType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const tagType = await ultra.mfuAssertEmuTagType()
    console.log(TagType[tagType]) // '040dc445420d2981e7480000e1100600'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • A protected memory area can be accessed only after a successful password verification using the PWD_AUTH command. The AUTH0 configuration byte defines the protected area. It specifies the first page that the password mechanism protects. The level of protection can be configured using the PROT bit either for write protection or read/write protection. The PWD_AUTH command takes the password as parameter and, if successful, returns the password authentication acknowledge, PACK. By setting the AUTHLIM configuration bits to a value larger than 000b, the number of unsuccessful password verifications can be limited. Each unsuccessful authentication is then counted in a counter featuring anti-tearing support. After reaching the limit of unsuccessful attempts, the memory access specified in PROT, is no longer possible.

    Parameters

    • opts: {
          autoSelect?: boolean;
          keepRfField?: boolean;
          key: Buffer;
          timeout?: number;
      }
      • OptionalautoSelect?: boolean

        true to enable auto-select, false to disable auto-select.

      • OptionalkeepRfField?: boolean

        true to keep RF field after auth, false to disable RF field.

      • key: Buffer

        The password to be verified. The password must be a 4 bytes Buffer.

      • Optionaltimeout?: number

    Returns Promise<Buffer>

    The password authentication acknowledge, PACK

  • Detect Mifare Ultralight tag and return the tag infomation.

    Returns Promise<MfuTagType>

    The tag infomation of detected tag.

    Proxmark3 hf mfu info

    async function run (ultra) {
    const { MfuTagTypeName } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const MfuTagType = await ultra.mfuDetectTagType()
    console.log(`tagType = ${MfuTagTypeName.get(MfuTagType)}`)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Read multiple pages from start to end. For example if the start address is 0x03 and the end address is 0x07 then pages 0x03, 0x04, 0x05, 0x06 and 0x07 are returned. If the addressed page is outside of accessible area, NTAG21x replies a NAK.

    Parameters

    • opts: {
          end: number;
          key?: Buffer;
          start: number;
          timeout?: number;
      }
      • end: number

        end page address

      • Optionalkey?: Buffer

        The password to be verified. The password must be a 4 bytes Buffer.

      • start: number

        start page address

      • Optionaltimeout?: number

    Returns Promise<Buffer>

    4 pages (16 bytes)

    MF0ICU1 MIFARE Ultralight contactless single-ticket IC

    async function run (ultra) {
    const data = await ultra.mfuFastReadPages({ start: 0, end: 3 })
    console.log(data.toString('hex')) // '047c79896cb62a8171480000e1103e00'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mifare ultralight settings of actived emulator slot.

    Returns Promise<{
        counters: (undefined | number)[];
        magic?: boolean;
        pageSize?: number;
        signature?: Buffer;
        tearing?: boolean;
        version?: Buffer;
    }>

    • counters: The value of the NFC one-way counter.
    • magic: The magic mode.
    • pageSize: The page size.
    • signature: The IC specific, 32-byte ECC signature.
    • tearing: The slot is in tearing mode or not.
    • version: The version information for the specific NTAG21x type.
    async function run (ultra) {
    const data = await ultra.mfuGetEmuSettings()
    console.log(data)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • The GET_VERSION command is used to retrieve information on the NTAG family, the product version, storage size and other product data required to identify the specific NTAG21x. This command is also available on other NTAG products to have a common way of identifying products across platforms and evolution steps. The GET_VERSION command has no arguments and replies the version information for the specific NTAG21x type.

    Parameters

    • opts: {
          timeout?: number;
      } = {}
      • Optionaltimeout?: number

    Returns Promise<Buffer>

    • response for NTAG213, NTAG215 and NTAG216
    Byte no. Description NTAG213 NTAG215 NTAG216 Interpretation
    0 fixed Header 0x00 0x00 0x00
    1 vendor ID 0x04 0x04 0x04 NXP Semiconductors
    2 product type 0x04 0x04 0x04 NTAG
    3 product subtype 0x02 0x02 0x02 50 pF
    4 major product version 0x01 0x01 0x01 1
    5 minor product version 0x00 0x00 0x00 V0
    6 storage size 0x0F 0x11 0x13 reference
    7 protocol 0x03 0x03 0x03 ISO/IEC 14443-3 compliant
    async function run (ultra) {
    const data = await ultra.mfuGetVersion()
    console.log(data.toString('hex')) // '0004040201001103'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • The READ_CNT command is used to read out the current value of the NFC one-way counter of the Mifare Ultralight. The command has a single argument specifying the counter number and returns the 24-bit counter value of the corresponding counter. If the NFC_CNT_PWD_PROT bit is set to 1b the counter is password protected and can only be read with the READ_CNT command after a previous valid password authentication.

    Parameters

    • opts: {
          addr?: number;
          key?: Buffer;
      }
      • Optionaladdr?: number

        The counter addr to read. Must be 0, 1 or 2. Default is 2.

      • Optionalkey?: Buffer

        The password to be verified. The password must be a 4 bytes Buffer.

    Returns Promise<number>

    async function run (ultra) {
    const cnt = await ultra.mfuReadCounter({ addr: 2 })
    console.log(cnt) // 0
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Read the dump of Mifare Ultralight tag.

    Parameters

    • opts: {
          end?: number;
          key?: Buffer;
          start?: number;
      } = {}
      • Optionalend?: number

        end page address

      • Optionalkey?: Buffer

        The key to read pages if tag is read protected.

      • Optionalstart?: number

        start page address

    Returns Promise<Buffer>

    The dump of Mifare Ultralight tag.

    async function run (ultra) {
    const dump = await ultra.mfuReadDump()
    console.log(`Read ${dump.length} bytes.`) // Read 160 bytes.
    return dump
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Get the mifare ultralight emulator data of actived slot.

    Returns Promise<Buffer>

    The mifare ultralight emulator data of actived slot.

    async function run (ultra) {
    const dump = await ultra.mfuReadEmuDump()
    console.log(`Read ${dump.length} bytes.`)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Read 4 pages (16 bytes) from Mifare Ultralight

    Parameters

    • opts: {
          key?: Buffer;
          start: number;
          timeout?: number;
      }
      • Optionalkey?: Buffer

        The password to be verified. The password must be a 4 bytes Buffer.

      • start: number

        start page address

      • Optionaltimeout?: number

    Returns Promise<Buffer>

    4 pages (16 bytes)

    MF0ICU1 MIFARE Ultralight contactless single-ticket IC

    async function run (ultra) {
    const data = await ultra.mfuReadPages({ start: 0 })
    console.log(data.toString('hex')) // '040dc445420d2981e7480000e1100600'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • The READ_SIG command returns an IC specific, 32-byte ECC signature, to verify NXP Semiconductors as the silicon vendor. The signature is programmed at chip production and cannot be changed afterwards.

    Returns Promise<Buffer>

    async function run (ultra) {
    const data = await ultra.mfuReadSignature()
    console.log(data.toString('base64url')) // 'w9dq8MPprf1Ro-C1si32rg3y7cO8UChrtXlNyjLScS4'
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Write new dump to the actived slot.

    Parameters

    • dump: Buffer

      New dump to be write to actived slot.

    Returns Promise<void>

    async function run (ultra) {
    const dump = new Buffer(540) // Dump size of NTAG_213 is 540 bytes.
    dump.set(Buffer.from('04689571fa5c648042480fe0', 'hex'))
    dump.set(Buffer.from('040000ff00000000ffffffff', 'hex'), 524)
    await ultra.mfuWriteEmuDump(dump)
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Write 1 page (4 bytes) to Mifare Ultralight

    Parameters

    • opts: {
          data: Buffer;
          key?: Buffer;
          start: number;
      }
      • data: Buffer

        4 bytes, the page data to be written.

      • Optionalkey?: Buffer

        The password to be verified. The password must be a 4 bytes Buffer.

      • start: number

        start page address

    Returns Promise<void>

    MF0ICU1 MIFARE Ultralight contactless single-ticket IC

    async function run (ultra) {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const data = await ultra.mfuWritePage({ start: 9, data: Buffer.from('00000000', 'hex') })
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

DFU Related

  • Abort the DFU procedure.

    Returns Promise<void>

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    await ultra.cmdDfuEnter()
    await ultra.cmdDfuAbort()
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Enter bootloader mode.

    Returns Promise<void>

    async function run (ultra) {
    await ultra.cmdDfuEnter()
    }

    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Retrieve firmware version.

    Parameters

    Returns Promise<{
        addr: number;
        len: number;
        type: DfuFwType;
        version: number;
    }>

    • addr: Firmware address in flash.
    • len: Firmware length in bytes.
    • type: Firmware type.
    • version: Firmware version.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    const { DfuFwId, DfuFwType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdDfuEnter()
    for (const fwId of [DfuFwId.BOOTLOADER, DfuFwId.APPLICATION, DfuFwId.SOFTDEVICE]) {
    const { type, version, addr, len } = await ultra.cmdDfuGetFirmwareVersion(fwId)
    console.log(`type = ${DfuFwType[type]}, version = ${version}, addr = 0x${addr.toString(16)}, len = ${len}`)
    }
    await ultra.cmdDfuAbort()
    // type = BOOTLOADER, version = 1, addr = 0xf3000, len = 45056
    // type = SOFTDEVICE, version = 7002000, addr = 0x1000, len = 159744
    // type = APPLICATION, version = 1, addr = 0x27000, len = 222844
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Retrieve hardware version.

    Returns Promise<{
        part: string;
        ramSize: number;
        romPageSize: number;
        romSize: number;
        variant: string;
    }>

    • part: Hardware part, from FICR register.
    • ramSize: RAM size, in bytes.
    • romPageSize: ROM flash page size, in bytes.
    • romSize: ROM size, in bytes.
    • variant: Hardware variant, from FICR register.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuGetHardwareVersion())
    await ultra.cmdDfuAbort()
    // {
    // "part": "nRF52840",
    // "variant": "AAD0",
    // "romSize": 1048576,
    // "ramSize": 262144,
    // "romPageSize": 4096
    // }
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Retrieve MTU size.

    Returns Promise<number>

    The preferred MTU size on this request.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuGetMtu()) // Print: 1025
    await ultra.cmdDfuAbort()
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Request CRC of selected object.

    Returns Promise<{
        crc32: number;
        offset: number;
    }>

    • crc32: Current CRC.
    • offset: Current offset.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

  • Retrieve DFU protocol version.

    Syntax and ID of this command is permanent. If protocol version changes other opcode may not be valid any more.

    Returns Promise<number>

    Protocol version.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuGetProtocol()) // Print: 1
    await ultra.cmdDfuAbort()
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Ping.

    Parameters

    • id: number

      Ping ID that will be returned in response.

    Returns Promise<number>

    The received ID which is echoed back.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuPing(1)) // Print: 1
    await ultra.cmdDfuAbort()
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
  • Select object.

    Parameters

    Returns Promise<{
        crc32: number;
        maxSize: number;
        offset: number;
    }>

    • crc32: Current CRC.
    • maxSize: Maximum size of selected object.
    • offset: Current offset.

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

  • Set receipt notification

    This request configures the frequency of sending CRC responses after Write request commands.

    Parameters

    • prn: number

      If set to 0, then the CRC response is never sent after Write request. Otherwise, it is sent every prn'th Write request.

    Returns Promise<void>

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

  • Upload DFU image.

    Parameters

    Returns Promise<void>

    Please refer to nRF5 SDK: DFU Protocol for more infomation.

    async function run (ultra) {
    const { DeviceModel } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const { default: DfuZip } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/plugin/DfuZip.mjs/+esm')
    const model = (await ultra.cmdGetDeviceModel()) === DeviceModel.ULTRA ? 'ultra' : 'lite'
    const dfuZipUrl = `https://taichunmin.idv.tw/ChameleonUltra-releases/dev/${model}-dfu-app.zip`
    const dfuZip = new DfuZip(new Buffer((await axios.get(dfuZipUrl, { responseType: 'arraybuffer' }))?.data))
    const image = await dfuZip.getAppImage()
    const imageGitVersion = await dfuZip.getGitVersion()
    console.log({ type: image.type, headerSize: image.header.length, bodySize: image.body.length, gitVersion: imageGitVersion })
    // {
    // "type": "application",
    // "headerSize": 141,
    // "bodySize": 222844,
    // "gitVersion": "v2.0.0-135-g3cadd47"
    // }
    const gitVersion = await ultra.cmdGetGitVersion()
    console.log(`gitVersion = ${gitVersion}`) // Print: gitVersion = v2.0.0-135-g3cadd47
    await ultra.cmdDfuEnter()
    ultra.emitter.on('progress', console.log)
    // {
    // "func": "dfuUpdateObject",
    // "offset": 0,
    // "size": 222844,
    // "type": 2
    // }
    await ultra.dfuUpdateImage(image)
    ultra.emitter.removeListener('progress', console.log)
    }
    await run(vm.ultra) // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html

Internal

  • Internal

    Invoke a hook with context.

    Parameters

    • hookName: string

      The hook name.

    • ctx: any = {}

      The context will be passed to every middleware.

    • Optionalnext: MiddlewareComposeFn

      The next middleware function.

    Returns Promise<unknown>

    The return value depent on the middlewares