Static
VERSION_The supported version of SDK.
Automatically change the device mode to mode
if the current device mode is not equal to mode
.
Change device mode to tag reader or tag emulator.
The mode to be changed.
Get the animation mode of device while wake-up and sleep.
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 the button long press action of specified button.
The button to be get.
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.
The button to be get.
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 current mode of device.
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.
// 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.
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)
Set the animation mode of device while wake-up and sleep.
The animation mode to be set.
Set the button long press action of specified button.
The button to be set.
The button long press action to be set.
// 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.
The button to be set.
The button press action to be set.
// 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)
Delete the nick name of the slot
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)
Get the nickname of specified freq type in specified slot.
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.
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.
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)
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.
// 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)
Helper function to change slot to tagType, reset to default tagType data, enable slot, save settings and set active slot.
// 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)
Write id of em410x tag to t55xx tag.
The id of em410x tag.
The new key of t55xx tag.
The keys to be checked. Maximum length is 125
.
// 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.
Optional
activateSet true
to activate RF field. If data
is not empty or autoSelect
is true, activateRfField
will be set to true
.
Optional
appendSet true
to add CRC before sending data.
Optional
autoSet true
to automatically select card before sending data.
Optional
checkSet 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.
Optional
data?: BufferThe data to be send. If appendCrc
is true
, the maximum length of data is 62
, otherwise is 64
.
Optional
dataNumber of bits to send. Useful for send partial byte. dataBitLength
is incompatible with appendCrc
.
Optional
keepSet true
to keep the RF field active after sending.
Optional
timeout?: numberDefault value is 1000 ms
. Maximum timeout for reading tag response in ms while waitResponse
is true
.
Optional
waitDefault value is true
. Set false
to skip reading tag response.
The response from tag.
Scan 14a tag, and return basic information. The device mode must be set to READER before using this command.
The basic infomation of scanned tag.
// 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()
.
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)
Get anti-collision data from actived slot.
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.
2 bytes
, the new atqa to be set.
Optional
ats?: BufferThe new ats to be set.
1 byte
, the new sak to be set.
The new uid to be set.
// 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)
Magic auth helper function for mifare gen1a tag.
The callback function to be executed after auth.
The result of callback function.
Acquire the data from mifare darkside attack.
The target block.
The target key type.
true
if this is the first attack.
The max sync count of darkside attack.
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.
The info of known key.
The block of known key.
The known key.
The key type of known key.
The info of target key to be attack.
The block of target key.
The key type of target key.
The result of mifare 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.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.
The info of known key.
The block of known key.
The known key.
The key type of known key.
The info of target key to be attack.
The block of target key.
The key type of target key.
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.
The info of key to be checked.
The block of key to be checked.
The key to be checked.
The type of key to be checked.
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()
.
The keys to be checked. Maximum length is 83
.
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.
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 data of mifare MFKey32 detections.
The start log of detections to be get.
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.
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)
Get the mifare write mode of actived slot.
The mifare write mode of actived slot.
Read block data from a mifare tag.
The block to be read and the key info of the block.
The block to be read.
The key of the block.
The key type of the block.
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 mifare write mode of actived slot.
The mifare write mode of actived slot.
Dectect the nt distance of mifare protocol.
The info of known key.
The block of known key.
The known key.
The key type of known key.
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.
The nt level of mifare protocol.
MIFARE Classic manipulate value block
X
(0
~ 2147483647
) from src to dstX
(0
~ 2147483647
) from src to dstThe key info of src block.
The block of src block.
The key of src block.
The key type of src block.
The operator of value block.
The operand of value block.
The key info of dst block.
The block of dst block.
The key of dst block.
The key type of dst 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))
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.
The block to be written and the key info of the block.
The block to be written.
The block data to be written.
The key of the block.
The key type of the 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 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.
Optional
chunkkeys
will be chunked by this size.
The keys to be checked.
Optional
mask?: BufferThe 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.
Optional
maxThe max sectors to be check.
Optional
onThe callback function to be invoked before checking every chunk of keys.
Given a list of keys, check which is the correct key A and key B of the sector.
The sector number to be checked.
The keys dictionary.
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 a block data of Mifare Classic by given keys.
The block number to be read.
The keys dictionary.
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.
The sector number to be read.
The keys dictionary.
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)
The key info of opts
block.
The block of opts
block.
The key of opts
block.
The key type of opts
block.
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)
The key info of dst
block.
The block of dst
block.
The key of dst
block.
The key type of dst
block.
The value and address to be set.
Optional
adr?: numberThe address to be set. Default is dst.block
.
Optional
value?: numberThe value to be set. Default is 0
.
// 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.
The block number to be written.
The keys dictionary.
Block data
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.
The sector number to be written.
The key dictionary.
Sector data
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)
Static
mf1Generate block 0 (manufacturer block) for magic mifare classic tag.
Optional
atqa?: BufferThe ATQA of the tag.
Optional
buf?: BufferIf provided, the data will be written to this buffer.
Optional
sak?: BufferThe SAK of the tag.
The UID of the tag.
// 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
})()
Static
mf1Static
mf1Read 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.
The address of the counter.
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.
The signature of actived slot.
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.
The version of actived slot.
Get the magic mode of actived slot.
If the actived slot is in magic mode, all read and write protection is bypassed.
The magic mode of actived slot.
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.
Optional
addr?: numberThe address of the counter.
Optional
counter?: numberThe counter to be write. The counter must be a 24-bit unsigned integer.
Optional
resettrue
to reset tearing.
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.
The signature. The signature must be a 32 bytes Buffer.
// 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.
The version of actived slot.
Set the magic mode of actived slot.
If the actived slot is in magic mode, all read and write protection is bypassed.
The magic mode of actived slot.
Assert the tag type of actived slot is Mifare Ultralight like. Throw an error if the tag type is not Mifare Ultralight like.
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.
Optional
autotrue
to enable auto-select, false
to disable auto-select.
Optional
keeptrue
to keep RF field after auth, false
to disable RF field.
The password to be verified. The password must be a 4 bytes Buffer.
Optional
timeout?: numberThe password authentication acknowledge, PACK
Detect Mifare Ultralight tag and return the tag infomation.
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.
end page address
Optional
key?: BufferThe password to be verified. The password must be a 4 bytes Buffer.
start page address
Optional
timeout?: number4 pages (16 bytes)
Get the mifare ultralight settings of actived emulator slot.
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.
Optional
timeout?: numberByte 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 |
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.
Optional
addr?: numberThe counter addr to read. Must be 0
, 1
or 2
. Default is 2
.
Optional
key?: BufferThe password to be verified. The password must be a 4 bytes Buffer.
Read the dump of Mifare Ultralight tag.
Optional
end?: numberend page address
Optional
key?: BufferThe key to read pages if tag is read protected.
Optional
start?: numberstart page address
The dump of Mifare Ultralight tag.
Read 4 pages (16 bytes) from Mifare Ultralight
Optional
key?: BufferThe password to be verified. The password must be a 4 bytes Buffer.
start page address
Optional
timeout?: number4 pages (16 bytes)
Write new dump to the actived slot.
New dump to be write to actived slot.
// 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
4 bytes
, the page data to be written.
Optional
key?: BufferThe password to be verified. The password must be a 4 bytes Buffer.
start page address
// 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)
Abort the DFU procedure.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Create selected object.
Object type.
Object size in bytes.
crc32
: Current CRC.offset
: Current offset.Please refer to nRF5 SDK: DFU Protocol for more infomation.
Execute selected object.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Retrieve firmware version.
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.
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.
The preferred MTU size on this request.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Request CRC of selected object.
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.
Protocol version.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Ping.
Ping ID that will be returned in response.
The received ID which is echoed back.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Select object.
Object type.
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.
If set to 0
, then the CRC response is never sent after Write request. Otherwise, it is sent every prn
'th Write request.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Upload DFU image.
The DFU image.
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)
DFU: Upload object of image.
Object type.
Data.
Please refer to nRF5 SDK: DFU Protocol for more infomation.
Internal
Register a hook.
The hook name.
The function to register.
Internal
Invoke a hook with context.
The hook name.
The context will be passed to every middleware.
Optional
next: MiddlewareComposeFnThe next middleware function.
The return value depent on the middlewares
Internal
Register a plugin.
The plugin to register.
Optional
option: anyThe option to pass to plugin.install().
The core library of
chameleon-ultra.js
. You need to register exactly one adapter to theChameleonUltra
instance.See
You can learn how to use
@taichunmin/buffer
from here.Example
Click here to expend import example.
Example of import the library using
import
orrequire
:Example of import the library in Browser (place at the end of body):
After importing the SDK, you need to register exactly one adapter to the
ChameleonUltra
instance: