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>

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

    Returns Promise<string>

    The ble address of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdBleGetAddress()) // 'E8:B6:3D:04:B6:FE'
    })(vm.ultra)
  • Get current ble pairing key of device.

    Returns Promise<string>

    The ble pairing key.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdBleGetPairingKey()) // '123456'
    })(vm.ultra)
  • Get the ble pairing mode of device.

    Returns Promise<boolean>

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

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdBleGetPairingMode()) // false
    })(vm.ultra)
  • Set the ble pairing key of device.

    Parameters

    • key: string

      The new ble pairing key.

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdBleSetPairingKey('123456')
    })(vm.ultra)
  • 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>

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

    Parameters

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { DeviceMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdChangeDeviceMode(DeviceMode.TAG)
    })(vm.ultra)
  • Get the animation mode of device while wake-up and sleep.

    Returns Promise<AnimationMode>

    The animation mode of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • Get current firmware version of device.

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

    Current firmware version of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdGetAppVersion()) // '1.0'
    })(vm.ultra)
  • Get the battery info of device.

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

    The battery info of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const battery = await ultra.cmdGetBatteryInfo()
    console.log(JSON.stringify(battery)) // { "voltage": 4192, "level": 99 }
    })(vm.ultra)
  • Get the button long press action of specified button.

    Parameters

    Returns Promise<ButtonAction>

    The button long press action of specified button.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • Get the button press action of specified button.

    Parameters

    Returns Promise<ButtonAction>

    The button press action of specified button.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • Get chipset id of device in hex format.

    Returns Promise<string>

    Chipset id of device in hex format.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdGetDeviceChipId()) // 'db1c624228d9634c'
    })(vm.ultra)
  • Get current mode of device.

    Returns Promise<DeviceMode>

    Current mode of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • Get the device is ChameleonUltra or ChameleonLite.

    Returns Promise<DeviceModel>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • Get the settings of device.

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

    The settings of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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"
    * }
    */
    })(vm.ultra)
  • Get the git version of firmware.

    Returns Promise<string>

    The git version of firmware.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdGetGitVersion()) // '98605be'
    })(vm.ultra)
  • Get the cmds supported by device.

    Returns Promise<Set<Cmd>>

    The cmds supported by device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const cmds = await ultra.cmdGetSupportedCmds()
    console.log(cmds.size) // 67
    })(vm.ultra)
  • Reset the settings of device to default values.

    Returns Promise<void>

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

    Returns Promise<void>

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

    Parameters

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { AnimationMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSetAnimationMode(AnimationMode.SHORT)
    })(vm.ultra)
  • Set the button long press action of specified button.

    Parameters

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • Set the button press action of specified button.

    Parameters

    Returns Promise<void>

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

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdWipeFds()
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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
    })(vm.ultra)
  • Check if the firmware version is supported by SDK.

    Returns Promise<boolean>

    true if the firmware version is supported, false otherwise.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    if (await ultra.isSupportedAppVersion()) throw new Error('Firmware version is not supported. Please update the firmware.')
    })(vm.ultra)

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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • Delete the nick name of the slot

    Parameters

    Returns Promise<boolean>

    true if success, false if slot name is empty.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Slot, FreqType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotDeleteFreqType(Slot.SLOT_1, FreqType.HF)
    })(vm.ultra)
  • Get the active emulation tag slot of device.

    Returns Promise<Slot>

    The active slot of device.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • Get the slot info of all slots.

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

    The slot info of all slots.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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 }
    * ]
    */
    })(vm.ultra)
  • Get enabled slots.

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

    Enabled slots.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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 }
    // ]
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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()
    })(vm.ultra)
  • Change the active emulation tag slot of device.

    Parameters

    • slot: Slot

      The slot to be active.

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Slot } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdSlotSetActive(Slot.SLOT_1)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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')
    })(vm.ultra)
  • Helper function to change slot to tagType, reset to default tagType data, enable slot, save settings and set active slot.

    Parameters

    • slot: Slot

      The target slot.

    • OptionalhfTagType: null | TagType

      The hf tagType to be change. If null, the hf of slot will be skip.

    • OptionallfTagType: null | TagType

      The lf tagType to be change. If null, the lf of slot will be skip.

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Slot, TagType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.slotChangeTagTypeAndActive(Slot.SLOT_1, TagType.MIFARE_1024, TagType.EM410X)
    })(vm.ultra)

Reader Related

  • Scan em410x tag and print id

    Returns Promise<Buffer>

    The id of em410x tag.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const id = await ultra.cmdEm410xScan()
    console.log(id.toString('hex')) // 'deadbeef88'
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const antiColl = _.first(await ultra.cmdHf14aScan())
    console.log(_.mapValues(antiColl, val => val.toString('hex')))
    // { uid: '040dc4420d2981', atqa: '4400', sak: '00', ats: ''}
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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: '' }
    })(vm.ultra)

Emulator Related

  • Get the em410x id of actived slot.

    Returns Promise<Buffer>

    The em410x id of actived slot.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const id = await ultra.cmdEm410xGetEmuId()
    console.log(id.toString('hex')) // 'deadbeef88'
    })(vm.ultra)
  • Set the em410x id of actived slot.

    Parameters

    • id: Buffer

      The em410x id of actived slot.

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdEm410xSetEmuId(Buffer.from('deadbeef88', 'hex'))
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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": [] }
    // }
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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')
    })
    })(vm.ultra)

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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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"
    // }
    })(vm.ultra)

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

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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')}`)
    })(vm.ultra)
  • 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
    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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 },
    // ]
    // }
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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' },
    // ],
    // }
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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
    })(vm.ultra)
  • 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.
    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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))
    })(vm.ultra)
    // {
    // "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,
    // ]
    // }
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.cmdMf1EmuReadBlock(1)
    console.log(data.toString('hex')) // '00000000000000000000000000000000'
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMf1EmuWriteBlock(1, Buffer.alloc(16))
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1GetAntiCollMode()) // false
    })(vm.ultra)
  • Get the count of mifare MFKey32 detections.

    Returns Promise<number>

    The count of mifare MFKey32 detections.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1GetDetectionCount()) // 0
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1GetDetectionEnable()) // false
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'),
    * }
    */
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const mf1Settings = await ultra.cmdMf1GetEmuSettings()
    console.log(JSON.stringify(mf1Settings))
    /**
    * {
    * "detection": false,
    * "gen1a": false,
    * "gen2": false,
    * "antiColl": false,
    * "write": 0
    * }
    */
    })(vm.ultra)
  • Set the mifare gen1a mode of actived slot.

    Returns Promise<boolean>

    The mifare gen1a mode of actived slot.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1GetGen1aMode()) // false
    })(vm.ultra)
  • Get the mifare gen2 mode of actived slot.

    Returns Promise<boolean>

    The mifare gen2 mode of actived slot.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1GetGen2Mode()) // false
    })(vm.ultra)
  • Get the mifare write mode of actived slot.

    Returns Promise<Mf1EmuWriteMode>

    The mifare write mode of actived slot.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1GetWriteMode()) // 0
    })(vm.ultra)
  • Test whether it is mifare classic tag.

    Returns Promise<boolean>

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

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMf1IsSupport()) // true
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdMf1SetAntiCollMode(false)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdMf1SetDetectionEnable(true)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdMf1SetGen1aMode(false)
    })(vm.ultra)
  • 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>

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

    Parameters

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Mf1EmuWriteMode } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMf1SetWriteMode(Mf1EmuWriteMode.NORMAL)
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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 },
    // ]
    // }
    })(vm.ultra)
  • Check the nt level of mifare protocol.

    Returns Promise<Mf1PrngType>

    The nt level of mifare protocol.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Mf1PrngType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(Mf1PrngType[await ultra.cmdMf1TestPrngType()]) // 'WEAK'
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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))
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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,
    })
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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" }
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const card = await ultra.mf1Gen1aReadBlocks(0, 64)
    console.log(_.map(card.chunk(16), chunk => chunk.toString('hex')).join('\n'))
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.mf1Gen1aWriteBlocks(1, new Buffer(16))
    })(vm.ultra)
  • Send Mifare Classic HALT command and close RF field.

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.mf1Halt()
    })(vm.ultra)
  • Read a block data of Mifare Classic by given keys.

    Parameters

    • block: number

      The block number to be read.

    • keys: Buffer[]

      The keys dictionary.

    Returns Promise<Buffer>

    The block data read from a mifare tag. An error is thrown if the block cannot be read.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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 = await ultra.mf1ReadBlockByKeys(0, keys)
    console.log(data.toString('hex'))
    })(vm.ultra)
  • Read a 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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] }
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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))
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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))
    })(vm.ultra)
  • Write a block data to Mifare Classic by given keys.

    Parameters

    • block: number

      The block number to be written.

    • keys: Buffer[]

      The keys dictionary.

    • data: Buffer

      Block data

    Returns Promise<void>

    An error is thrown if the block cannot be write.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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.from('00000000000000000000000000000000', 'hex')
    await ultra.mf1WriteBlockByKeys(1, keys, data)
    })(vm.ultra)
  • Write a sector data to 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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]
    })(vm.ultra)
  • Generate block 0 (manufacturer block) for magic mifare classic tag.

    Parameters

    • opts: {
          atqa?: Buffer;
          buf?: Buffer;
          sak?: Buffer;
          uid: Buffer;
      }
      • Optionalatqa?: Buffer

        The ATQA of the tag.

      • Optionalbuf?: Buffer

        If provided, the data will be written to this buffer.

      • Optionalsak?: Buffer

        The SAK of the tag.

      • uid: Buffer

        The UID of the tag.

    Returns Buffer

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    ;(() => {
    const { Buffer, ChameleonUltra } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const block0 = ChameleonUltra.mf1GenMagicBlock0({
    uid: Buffer.from('deadbeef', 'hex'),
    atqa: Buffer.from('0004', 'hex').reverse(),
    sak: Buffer.from('08', 'hex'),
    })
    console.log(block0.toString('hex')) // deadbeef220804000000000000000000
    })()
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    ;(() => {
    const { Buffer, ChameleonUltra } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(ChameleonUltra.mf1IsValidAcl(Buffer.from('ff078069', 'hex'))) // true
    })()
  • Get the blockNo of sector trailer.

    Parameters

    • sector: number

      The sector number.

    Returns number

    The blockNo of sector trailer.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    ;(() => {
    const { ChameleonUltra } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    console.log(ChameleonUltra.mf1TrailerBlockNoOfSector(0)) // 3
    })()

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.
    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMfuGetEmuCounter(0))
    // { "counter": 0, "tearing": false }
    })(vm.ultra)
  • Get the number of pages available in the actived slot.

    Returns Promise<number>

    The number of pages available in the actived slot.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMfuGetEmuPageSize()) // 135
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.cmdMfuGetEmuSignature()
    console.log(data.toString('hex')) // '0000000000000000000000000000000000000000000000000000000000000000'
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.cmdMfuGetEmuVersion()
    console.log(data.toString('hex')) // '0004040201001103'
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMfuGetMagicMode()) // false
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.cmdMfuReadEmuPage(1)
    console.log(data.toString('hex')) // 'fa5c6480'
    })(vm.ultra)
  • Reset the authentication failed counter of actived slot.

    Returns Promise<number>

    The original value of the unsuccessful auth counter before reset.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    console.log(await ultra.cmdMfuResetEmuAuthFailedCounter()) // 0
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdMfuSetEmuCounter({ addr: 0, counter: 1 })
    console.log(await ultra.cmdMfuGetEmuCounter(0))
    // { "counter": 1, "tearing": false }
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMfuSetEmuVersion(Buffer.from('0004040201001103', 'hex'))
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdMfuSetMagicMode(false)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    await ultra.cmdMfuWriteEmuPage(1, Buffer.from('fa5c6480', 'hex'))
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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'
    })(vm.ultra)
  • 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<NxpMfuType>

    The tag infomation of detected tag.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const { NxpMfuTypeName } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
    const NxpMfuType = await ultra.mfuDetectTagType()
    console.log(`tagType = ${NxpMfuTypeName.get(NxpMfuType)}`)
    })(vm.ultra)
  • 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)

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.mfuFastReadPages({ start: 0, end: 3 })
    console.log(data.toString('hex')) // '047c79896cb62a8171480000e1103e00'
    })(vm.ultra)
  • 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.
    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.mfuGetEmuSettings()
    console.log(data)
    })(vm.ultra)
  • 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
    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.mfuGetVersion()
    console.log(data.toString('hex')) // '0004040201001103'
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const cnt = await ultra.mfuReadCounter({ addr: 2 })
    console.log(cnt) // 0
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const dump = await ultra.mfuReadDump()
    console.log(`Read ${dump.length} bytes.`) // Read 160 bytes.
    return dump
    })(vm.ultra)
  • Get the mifare ultralight emulator data of actived slot.

    Returns Promise<Buffer>

    The mifare ultralight emulator data of actived slot.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const dump = await ultra.mfuReadEmuDump()
    console.log(`Read ${dump.length} bytes.`)
    })(vm.ultra)
  • 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)

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.mfuReadPages({ start: 0 })
    console.log(data.toString('hex')) // '040dc445420d2981e7480000e1100600'
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    const data = await ultra.mfuReadSignature()
    console.log(data.toString('base64url')) // 'w9dq8MPprf1Ro-C1si32rg3y7cO8UChrtXlNyjLScS4'
    })(vm.ultra)
  • Write new dump to the actived slot.

    Parameters

    • dump: Buffer

      New dump to be write to actived slot.

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)
  • 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>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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') })
    })(vm.ultra)

DFU Related

  • Abort the DFU procedure.

    Returns Promise<void>

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

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

    Returns Promise<void>

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdDfuEnter()
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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
    })(vm.ultra)
  • 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.

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

    Returns Promise<undefined | number>

    The preferred MTU size on this request.

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

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuGetMtu()) // Print: 1025
    await ultra.cmdDfuAbort()
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuGetProtocol()) // Print: 1
    await ultra.cmdDfuAbort()
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async ultra => {
    await ultra.cmdDfuEnter()
    console.log(await ultra.cmdDfuPing(1)) // Print: 1
    await ultra.cmdDfuAbort()
    })(vm.ultra)
  • 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.

    // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
    await (async 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)
    })(vm.ultra)

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