mirror of
https://github.com/RfidResearchGroup/ChameleonMini.git
synced 2026-05-12 11:20:37 -07:00
Merge branch 'RfidResearchGroup:proxgrind' into ProxgrindMifareFix
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
name: Firmware Build (Pull Request, Firmware Modified, Artifact in build job)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "Firmware/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Make a firmware build folder
|
||||
run: mkdir FirmwareBuild
|
||||
- name: Print Kernel Ver
|
||||
run: uname -a
|
||||
- name: Update APT
|
||||
run: sudo apt-get update -yqq
|
||||
- name: Install AVR GCC Suite
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-avr binutils-avr gdb-avr avr-libc avrdude
|
||||
- name: Make Firmware
|
||||
run: make
|
||||
working-directory: Firmware/Chameleon-Mini/
|
||||
- name: Move hex file to FirmwareBuild
|
||||
run: mv Chameleon*.hex $GITHUB_WORKSPACE/FirmwareBuild/
|
||||
working-directory: Firmware/Chameleon-Mini/
|
||||
- name: Move eep file to FirmwareBuild
|
||||
run: mv Chameleon*.eep $GITHUB_WORKSPACE/FirmwareBuild/
|
||||
working-directory: Firmware/Chameleon-Mini/
|
||||
- name: Upload Build Artifact to Action
|
||||
uses: actions/upload-artifact@v2.1.4
|
||||
with:
|
||||
name: "ChameleonBuild"
|
||||
path: "FirmwareBuild/**"
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Firmware Build (proxgrind Branch Push, Pre-release with Artifacts)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ proxgrind ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Make a firmware build folder
|
||||
run: mkdir FirmwareBuild
|
||||
- name: Print Kernel Ver
|
||||
run: uname -a
|
||||
- name: Update APT
|
||||
run: sudo apt-get update -yqq
|
||||
- name: Install AVR GCC Suite
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-avr binutils-avr gdb-avr avr-libc avrdude
|
||||
- name: Make Firmware
|
||||
run: make
|
||||
working-directory: Firmware/Chameleon-Mini/
|
||||
- name: Move hex file to FirmwareBuild
|
||||
run: mv Chameleon*.hex $GITHUB_WORKSPACE/FirmwareBuild/
|
||||
working-directory: Firmware/Chameleon-Mini/
|
||||
- name: Move eep file to FirmwareBuild
|
||||
run: mv Chameleon*.eep $GITHUB_WORKSPACE/FirmwareBuild/
|
||||
working-directory: Firmware/Chameleon-Mini/
|
||||
- name: Upload Build Artifact to Action
|
||||
uses: actions/upload-artifact@v2.1.4
|
||||
with:
|
||||
name: "ChameleonBuild"
|
||||
path: "FirmwareBuild/**"
|
||||
- name: Create a Pre-release
|
||||
uses: actions/create-release@v1.1.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: "${{ format('Build-{0}', github.sha) }}"
|
||||
release_name: Firmware Build ${{ github.sha }}
|
||||
body: Built at commit ${{ github.sha }} from ${{ github.actor }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
- name: Upload Pre-release Artifacts
|
||||
uses: linuxgemini/github-upload-release-artifacts-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
created_tag: "${{ format('Build-{0}', github.sha) }}"
|
||||
args: "FirmwareBuild/"
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
.DS_Store
|
||||
*.pyc
|
||||
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
* `RECALL_MEM` | Recalls a setting from the permanent Flash memory. Equivalent to the `RECALL` command.
|
||||
* `TOGGLE_FIELD` | Activates the reader field if it was deactivated, deactivates the reader field if it was activated.
|
||||
* `STORE_LOG` | Writes the current log from SRAM to FRAM and clears the SRAM log. Equivalent to the `STORE_LOG` command.
|
||||
* `CLONE_MFU` | Triggers the clone of a Mifare Ultralight card in range of the antenna to the selected slot and configures it to emulate it. Equivalent to the `CLONE_MFU` command.
|
||||
*
|
||||
* Note the UID commands have no effect when the slot is configured as reader.
|
||||
*/
|
||||
@@ -111,6 +111,7 @@
|
||||
* `SEND_RAW <BYTEVALUE>`| Does NOT add parity bits, sends the given byte string <BYTEVALUE> and returns the cards answer
|
||||
* `GETUID` | Obtains the UID of a card that is in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command".
|
||||
* `DUMP_MFU` | Reads the whole content of a Mifare Ultralight card that is in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command".
|
||||
* `CLONE_MFU` | Clones a Mifare Ultralight card that is in the range of the antenna to the current slot, which is then accordingly configured to emulate it. This command is a \ref Anchor_TimeoutCommands "Timeout command".
|
||||
* `IDENTIFY` | Identifies the type of a card in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command".
|
||||
* `THRESHOLD=?` | Returns the possible number range for the reader threshold.
|
||||
* `THRESHOLD=<NUMBER>` | Globally sets the reader threshold. The <NUMBER> influences the reader function and range. Setting a wrong value may result in malfunctioning of the reader. DEFAULT: 400
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
static inline
|
||||
void AntennaLevelInit(void) {
|
||||
ADCA.CAL = (PRODSIGNATURES_ADCACAL1 << 8) | PRODSIGNATURES_ADCACAL0; /* Load calibration data, source: https://www.avrfreaks.net/comment/2080211#comment-2080211 */
|
||||
ADCA.CTRLA = ADC_ENABLE_bm;
|
||||
ADCA.CTRLB = ADC_RESOLUTION_12BIT_gc;
|
||||
ADCA.REFCTRL = ADC_REFSEL_INT1V_gc | ADC_BANDGAP_bm;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "TITagitstandard.h"
|
||||
#include "Sniff14443A.h"
|
||||
#include "EM4233.h"
|
||||
#include "NTAG215.h"
|
||||
#include "Sniff15693.h"
|
||||
|
||||
/* Function wrappers */
|
||||
INLINE void ApplicationInit(void) {
|
||||
@@ -53,4 +55,20 @@ INLINE void ApplicationSetUid(ConfigurationUidType Uid) {
|
||||
LogEntry(LOG_INFO_UID_SET, Uid, ActiveConfiguration.UidSize);
|
||||
}
|
||||
|
||||
INLINE void ApplicationGetSak(uint8_t * Sak) {
|
||||
ActiveConfiguration.ApplicationGetSakFunc(Sak);
|
||||
}
|
||||
|
||||
INLINE void ApplicationSetSak(uint8_t Sak) {
|
||||
ActiveConfiguration.ApplicationSetSakFunc(Sak);
|
||||
}
|
||||
|
||||
INLINE void ApplicationGetAtqa(uint16_t * Atqa) {
|
||||
ActiveConfiguration.ApplicationGetAtqaFunc(Atqa);
|
||||
}
|
||||
|
||||
INLINE void ApplicationSetAtqa(uint16_t Atqa) {
|
||||
ActiveConfiguration.ApplicationSetAtqaFunc(Atqa);
|
||||
}
|
||||
|
||||
#endif /* APPLICATION_H_ */
|
||||
|
||||
@@ -23,9 +23,6 @@ static enum {
|
||||
} State;
|
||||
|
||||
bool loggedIn;
|
||||
uint8_t MyAFI; /* This variable holds current tag's AFI (is used in inventory) */
|
||||
|
||||
CurrentFrame FrameInfo;
|
||||
|
||||
void EM4233AppInit(void) {
|
||||
State = STATE_READY;
|
||||
@@ -38,7 +35,7 @@ void EM4233AppInit(void) {
|
||||
FrameInfo.Selected = false;
|
||||
loggedIn = false;
|
||||
MemoryReadBlock(&MyAFI, EM4233_MEM_AFI_ADDRESS, 1);
|
||||
|
||||
MemoryReadBlock(&Uid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize);
|
||||
}
|
||||
|
||||
void EM4233AppReset(void) {
|
||||
@@ -51,6 +48,8 @@ void EM4233AppReset(void) {
|
||||
FrameInfo.Addressed = false;
|
||||
FrameInfo.Selected = false;
|
||||
loggedIn = false;
|
||||
MemoryReadBlock(&MyAFI, EM4233_MEM_AFI_ADDRESS, 1);
|
||||
MemoryReadBlock(&Uid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize);
|
||||
}
|
||||
|
||||
void EM4233AppTask(void) {
|
||||
@@ -62,7 +61,7 @@ void EM4233AppTick(void) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Lock_Block(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t BlockAddress = *FrameInfo.Parameters;
|
||||
uint8_t LockStatus = 0;
|
||||
|
||||
@@ -92,7 +91,7 @@ uint16_t EM4233_Lock_Block(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Write_Single(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t BlockAddress = *FrameInfo.Parameters;
|
||||
uint8_t *Dataptr = FrameInfo.Parameters + 0x01; /* Data to write begins on 2nd byte of the frame received by the reader */
|
||||
uint8_t LockStatus = 0;
|
||||
@@ -127,7 +126,7 @@ uint16_t EM4233_Write_Single(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t FramePtr; /* holds the address where block's data will be put */
|
||||
uint8_t BlockAddress = FrameInfo.Parameters[0];
|
||||
uint8_t LockStatus = 0;
|
||||
@@ -138,7 +137,7 @@ uint16_t EM4233_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
if (BlockAddress >= EM4233_NUMBER_OF_BLCKS) { /* check if the reader is requesting a sector out of bound */
|
||||
if (FrameInfo.Addressed) { /* If the request is addressed */
|
||||
FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR;
|
||||
FrameBuf[ISO15693_RES_ADDR_PARAM] = 0x0F; /* Magic number from real tag */
|
||||
FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC;
|
||||
ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */
|
||||
}
|
||||
return ResponseByteCount; /* If not addressed real tag does not respond */
|
||||
@@ -168,7 +167,7 @@ uint16_t EM4233_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t FramePtr; /* holds the address where block's data will be put */
|
||||
uint8_t BlockAddress = FrameInfo.Parameters[0];
|
||||
uint8_t BlocksNumber = FrameInfo.Parameters[1] + 0x01; /* according to ISO standard, we have to read 0x08 blocks if we get 0x07 in request */
|
||||
@@ -179,7 +178,7 @@ uint16_t EM4233_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
if (BlockAddress >= EM4233_NUMBER_OF_BLCKS) { /* the reader is requesting a block out of bound */
|
||||
if (FrameInfo.Addressed) { /* If the request is addressed */
|
||||
FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR;
|
||||
FrameBuf[ISO15693_RES_ADDR_PARAM] = 0x0F; /* Magic number from real tag */
|
||||
FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC;
|
||||
ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */
|
||||
}
|
||||
return ResponseByteCount; /* If not addressed real tag does not respond */
|
||||
@@ -224,7 +223,7 @@ uint16_t EM4233_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Write_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t AFI = FrameInfo.Parameters[0];
|
||||
uint8_t LockStatus = 0;
|
||||
|
||||
@@ -251,7 +250,7 @@ uint16_t EM4233_Write_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Lock_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t LockStatus = 0;
|
||||
|
||||
if (FrameInfo.ParamLen != 0)
|
||||
@@ -278,7 +277,7 @@ uint16_t EM4233_Lock_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Write_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t DSFID = FrameInfo.Parameters[0];
|
||||
uint8_t LockStatus = 0;
|
||||
|
||||
@@ -304,7 +303,7 @@ uint16_t EM4233_Write_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Lock_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t LockStatus = 0;
|
||||
|
||||
if (FrameInfo.ParamLen != 0)
|
||||
@@ -331,7 +330,7 @@ uint16_t EM4233_Lock_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint8_t EM4233_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t FramePtr; /* holds the address where block's data will be put */
|
||||
|
||||
if (FrameInfo.ParamLen != 0)
|
||||
@@ -354,8 +353,6 @@ uint8_t EM4233_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
ResponseByteCount += 1; /* Increment the response count */
|
||||
|
||||
/* Then append UID */
|
||||
uint8_t Uid[ActiveConfiguration.UidSize];
|
||||
EM4233GetUid(Uid);
|
||||
ISO15693CopyUid(&FrameBuf[FramePtr], Uid);
|
||||
FramePtr += ISO15693_GENERIC_UID_SIZE; /* Move forward the buffer data pointer */
|
||||
ResponseByteCount += ISO15693_GENERIC_UID_SIZE; /* Increment the response count */
|
||||
@@ -398,7 +395,7 @@ uint8_t EM4233_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Get_Multi_Block_Sec_Stat(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t FramePtr; /* holds the address where block's data will be put */
|
||||
uint8_t BlockAddress = FrameInfo.Parameters[0];
|
||||
uint8_t BlocksNumber = FrameInfo.Parameters[1] + 0x01;
|
||||
@@ -427,7 +424,7 @@ uint16_t EM4233_Get_Multi_Block_Sec_Stat(uint8_t *FrameBuf, uint16_t FrameBytes)
|
||||
}
|
||||
|
||||
uint16_t EM4233_Select(uint8_t *FrameBuf, uint16_t FrameBytes, uint8_t *Uid) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
/* I've no idea how this request could generate errors ._.
|
||||
if ( ) {
|
||||
FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR;
|
||||
@@ -463,7 +460,7 @@ uint16_t EM4233_Select(uint8_t *FrameBuf, uint16_t FrameBytes, uint8_t *Uid) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Reset_To_Ready(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
/* I've no idea how this request could generate errors ._.
|
||||
if ( ) {
|
||||
FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR;
|
||||
@@ -487,7 +484,7 @@ uint16_t EM4233_Reset_To_Ready(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Login(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t Password[4] = { 0 };
|
||||
|
||||
if (FrameInfo.ParamLen != 4 || !FrameInfo.Addressed || !(FrameInfo.Selected && State == STATE_SELECTED))
|
||||
@@ -523,7 +520,7 @@ uint16_t EM4233_Login(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Auth1(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
// uint8_t KeyNo = *FrameInfo.Parameters; /* Right now this parameter is unused, but it will be useful */
|
||||
|
||||
if (FrameInfo.ParamLen != 1) /* Malformed: not enough or too much data */
|
||||
@@ -548,7 +545,7 @@ uint16_t EM4233_Auth1(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233_Auth2(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
// uint8_t A2 = FrameInfo.Parameters;
|
||||
// uint8_t f = FrameInfo.Parameters + 0x08;
|
||||
// uint8_t g[3] = { 0 }; /* Names according to EM Marin definitions */
|
||||
@@ -566,9 +563,7 @@ uint16_t EM4233_Auth2(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
|
||||
uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
uint8_t Uid[ActiveConfiguration.UidSize];
|
||||
EM4233GetUid(Uid);
|
||||
ResponseByteCount = ISO15693_APP_NO_RESPONSE;
|
||||
|
||||
if ((FrameBytes < ISO15693_MIN_FRAME_SIZE) || !ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE))
|
||||
/* malformed frame */
|
||||
@@ -585,8 +580,8 @@ uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
return ISO15693_APP_NO_RESPONSE;
|
||||
|
||||
if (State == STATE_READY || State == STATE_SELECTED) {
|
||||
|
||||
if (*FrameInfo.Command == ISO15693_CMD_INVENTORY) {
|
||||
switch (*FrameInfo.Command) {
|
||||
case ISO15693_CMD_INVENTORY:
|
||||
if (FrameInfo.ParamLen == 0)
|
||||
return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */
|
||||
|
||||
@@ -596,59 +591,77 @@ uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
ISO15693CopyUid(&FrameBuf[ISO15693_RES_ADDR_PARAM + 0x01], Uid);
|
||||
ResponseByteCount += 10;
|
||||
}
|
||||
break;
|
||||
|
||||
} else if ((*FrameInfo.Command == ISO15693_CMD_STAY_QUIET) && FrameInfo.Addressed) {
|
||||
State = STATE_QUIET;
|
||||
case ISO15693_CMD_STAY_QUIET:
|
||||
if (FrameInfo.Addressed)
|
||||
State = STATE_QUIET;
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_READ_SINGLE) {
|
||||
case ISO15693_CMD_READ_SINGLE:
|
||||
ResponseByteCount = EM4233_Read_Single(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_WRITE_SINGLE) {
|
||||
case ISO15693_CMD_WRITE_SINGLE:
|
||||
ResponseByteCount = EM4233_Write_Single(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_LOCK_BLOCK) {
|
||||
case ISO15693_CMD_LOCK_BLOCK:
|
||||
ResponseByteCount = EM4233_Lock_Block(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_READ_MULTIPLE) {
|
||||
case ISO15693_CMD_READ_MULTIPLE:
|
||||
ResponseByteCount = EM4233_Read_Multiple(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_WRITE_AFI) {
|
||||
case ISO15693_CMD_WRITE_AFI:
|
||||
ResponseByteCount = EM4233_Write_AFI(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_LOCK_AFI) {
|
||||
case ISO15693_CMD_LOCK_AFI:
|
||||
ResponseByteCount = EM4233_Lock_AFI(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_WRITE_DSFID) {
|
||||
case ISO15693_CMD_WRITE_DSFID:
|
||||
ResponseByteCount = EM4233_Write_DSFID(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_LOCK_DSFID) {
|
||||
case ISO15693_CMD_LOCK_DSFID:
|
||||
ResponseByteCount = EM4233_Lock_DSFID(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_GET_SYS_INFO) {
|
||||
case ISO15693_CMD_GET_SYS_INFO:
|
||||
ResponseByteCount = EM4233_Get_SysInfo(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_GET_BLOCK_SEC) {
|
||||
case ISO15693_CMD_GET_BLOCK_SEC:
|
||||
ResponseByteCount = EM4233_Get_Multi_Block_Sec_Stat(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) {
|
||||
case ISO15693_CMD_RESET_TO_READY:
|
||||
ResponseByteCount = EM4233_Reset_To_Ready(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == EM4233_CMD_LOGIN) {
|
||||
case EM4233_CMD_LOGIN:
|
||||
ResponseByteCount = EM4233_Login(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == EM4233_CMD_AUTH1) {
|
||||
case EM4233_CMD_AUTH1:
|
||||
ResponseByteCount = EM4233_Auth1(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else if (*FrameInfo.Command == EM4233_CMD_AUTH2) {
|
||||
case EM4233_CMD_AUTH2:
|
||||
ResponseByteCount = EM4233_Auth2(FrameBuf, FrameBytes);
|
||||
break;
|
||||
|
||||
} else {
|
||||
default:
|
||||
if (FrameInfo.Addressed) {
|
||||
FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR;
|
||||
FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP;
|
||||
ResponseByteCount = 2;
|
||||
} /* EM4233 respond with error flag only to addressed commands */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (State == STATE_QUIET) {
|
||||
if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) {
|
||||
@@ -656,12 +669,6 @@ uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ResponseByteCount > 0) {
|
||||
/* There is data to send. Append CRC */
|
||||
ISO15693AppendCRC(FrameBuf, ResponseByteCount);
|
||||
ResponseByteCount += ISO15693_CRC16_SIZE;
|
||||
}
|
||||
|
||||
return ResponseByteCount;
|
||||
}
|
||||
|
||||
@@ -669,6 +676,7 @@ void EM4233GetUid(ConfigurationUidType Uid) {
|
||||
MemoryReadBlock(&Uid[0], EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize);
|
||||
}
|
||||
|
||||
void EM4233SetUid(ConfigurationUidType Uid) {
|
||||
MemoryWriteBlock(Uid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize);
|
||||
void EM4233SetUid(ConfigurationUidType NewUid) {
|
||||
memcpy(Uid, NewUid, ActiveConfiguration.UidSize);
|
||||
MemoryWriteBlock(NewUid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
#include "../Common.h"
|
||||
#include <util/crc16.h>
|
||||
|
||||
CurrentFrame FrameInfo;
|
||||
uint8_t Uid[ISO15693_GENERIC_UID_SIZE];
|
||||
uint8_t MyAFI;
|
||||
uint16_t ResponseByteCount;
|
||||
|
||||
//Refer to ISO/IEC 15693-3:2001 page 41
|
||||
uint16_t calculateCRC(void *FrameBuf, uint16_t FrameBufSize) {
|
||||
uint16_t reg = ISO15693_CRC16_PRESET;
|
||||
|
||||
@@ -85,6 +85,10 @@ typedef struct {
|
||||
bool Addressed;
|
||||
bool Selected;
|
||||
} CurrentFrame;
|
||||
extern CurrentFrame FrameInfo; /* Holds current frame information */
|
||||
extern uint8_t Uid[];
|
||||
extern uint8_t MyAFI; /* Holds current tag's AFI, used during inventory */
|
||||
extern uint16_t ResponseByteCount; /* Length of response, used when building response frames */
|
||||
|
||||
void ISO15693AppendCRC(uint8_t *FrameBuf, uint16_t FrameBufSize);
|
||||
bool ISO15693CheckCRC(void *FrameBuf, uint16_t FrameBufSize);
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* Author: skuser
|
||||
*
|
||||
* ChangeLog
|
||||
* 2019-09-22 willok 加入了UID模式开关,加入了SAK模式开关
|
||||
* 2019-10-05 Willok 将侦测卡功能整合进来,以减少程序大小
|
||||
* 2019-09-22 willok Added UID mode switch and SAK mode switch
|
||||
* 2019-10-05 Willok Integrate detection card function to reduce program size
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
#define CMD_TRANSFER 0xB0
|
||||
#define CMD_TRANSFER_FRAME_SIZE 2 /* Bytes without CRCA */
|
||||
|
||||
// 白卡相关的指令
|
||||
// White card related instructions
|
||||
#define CMD_CHINESE_UNLOCK 0x40
|
||||
#define CMD_CHINESE_WIPE 0x41
|
||||
#define CMD_CHINESE_UNLOCK_RW 0x43
|
||||
@@ -455,7 +455,7 @@ void DetectionInit(void) {
|
||||
|
||||
// Download log
|
||||
bool RfLogMemLoadBlock(void *Buffer, uint32_t BlockAddress, uint16_t ByteCount) {
|
||||
// 位置超出尾部了,结束
|
||||
// The position is beyond the end
|
||||
if (BlockAddress < (DetectionLogPtr - FRAM_DETECTION_START_ADDR)) {
|
||||
MemoryReadBlock(Buffer, BlockAddress + FRAM_DETECTION_START_ADDR, ByteCount);
|
||||
if (0 == BlockAddress)
|
||||
@@ -1300,3 +1300,19 @@ void MifareClassicSetUid(ConfigurationUidType Uid) {
|
||||
MemoryWriteBlock(&BCC, MEM_UID_BCC1_ADDRESS, ISO14443A_CL_BCC_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void MifareClassicGetAtqa(uint16_t * Atqa) {
|
||||
*Atqa = CardATQAValue;
|
||||
}
|
||||
|
||||
void MifareClassicSetAtqa(uint16_t Atqa) {
|
||||
CardATQAValue = Atqa;
|
||||
}
|
||||
|
||||
void MifareClassicGetSak(uint8_t * Sak) {
|
||||
*Sak = CardSAKValue;
|
||||
}
|
||||
|
||||
void MifareClassicSetSak(uint8_t Sak) {
|
||||
CardSAKValue = Sak;
|
||||
}
|
||||
@@ -33,5 +33,9 @@ uint16_t MifareClassicAppProcess(uint8_t *Buffer, uint16_t BitCount);
|
||||
void MifareClassicGetUid(ConfigurationUidType Uid);
|
||||
void MifareClassicSetUid(ConfigurationUidType Uid);
|
||||
|
||||
void MifareClassicGetAtqa(uint16_t * Atqa);
|
||||
void MifareClassicSetAtqa(uint16_t Atqa);
|
||||
void MifareClassicGetSak(uint8_t * Sak);
|
||||
void MifareClassicSetSak(uint8_t Sak);
|
||||
|
||||
#endif /* MIFARECLASSIC_H_ */
|
||||
|
||||
@@ -112,6 +112,8 @@ static uint8_t CompatWritePageAddress;
|
||||
static bool Authenticated;
|
||||
static uint8_t FirstAuthenticatedPage;
|
||||
static bool ReadAccessProtected;
|
||||
static uint16_t CardATQAValue;
|
||||
static uint8_t CardSAKValue;
|
||||
static uint8_t RNDBBuff [8];
|
||||
static uint8_t InitialVector[8] = {0};
|
||||
static uint8_t TripleDesKey [16];
|
||||
@@ -153,6 +155,8 @@ static void AppInitCommon(void) {
|
||||
FromHalt = false;
|
||||
Authenticated = false;
|
||||
ArmedForCompatWrite = false;
|
||||
CardATQAValue = ATQA_VALUE;
|
||||
CardSAKValue = SAK_CL1_VALUE;
|
||||
}
|
||||
void MifareUltralightCAppInit(void) {
|
||||
Flavor = UL_C;
|
||||
@@ -285,7 +289,7 @@ static uint16_t AppProcess(uint8_t *const Buffer, uint16_t ByteCount) {
|
||||
|
||||
//Handle MF ULC counter
|
||||
if (CompatWritePageAddress == MF_ULC_COUNTER_ADDRESS && Flavor == UL_C) {
|
||||
if (IncrementCounter(&Buffer[2])) {
|
||||
if (IncrementCounter(&Buffer[0])) {
|
||||
Buffer[0] = ACK_VALUE;
|
||||
return ACK_FRAME_SIZE;
|
||||
} else {
|
||||
@@ -294,7 +298,7 @@ static uint16_t AppProcess(uint8_t *const Buffer, uint16_t ByteCount) {
|
||||
}
|
||||
}
|
||||
|
||||
AppWritePage(CompatWritePageAddress, &Buffer[2]);
|
||||
AppWritePage(CompatWritePageAddress, &Buffer[0]);
|
||||
Buffer[0] = ACK_VALUE;
|
||||
return ACK_FRAME_SIZE;
|
||||
}
|
||||
@@ -673,3 +677,22 @@ void MifareUltralightSetUid(ConfigurationUidType Uid) {
|
||||
MemoryWriteBlock(&BCC2, UID_BCC2_ADDRESS, ISO14443A_CL_BCC_SIZE);
|
||||
}
|
||||
|
||||
void MifareUltralightGetAtqa(uint16_t * Atqa)
|
||||
{
|
||||
*Atqa = CardATQAValue;
|
||||
}
|
||||
|
||||
void MifareUltralightSetAtqa(uint16_t Atqa)
|
||||
{
|
||||
CardATQAValue = Atqa;
|
||||
}
|
||||
|
||||
void MifareUltralightGetSak(uint8_t * Sak)
|
||||
{
|
||||
*Sak = CardSAKValue;
|
||||
}
|
||||
|
||||
void MifareUltralightSetSak(uint8_t Sak)
|
||||
{
|
||||
CardSAKValue = Sak;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ uint16_t MifareUltralightAppProcess(uint8_t *Buffer, uint16_t BitCount);
|
||||
void MifareUltralightGetUid(ConfigurationUidType Uid);
|
||||
void MifareUltralightSetUid(ConfigurationUidType Uid);
|
||||
|
||||
|
||||
void MifareUltralightGetAtqa(uint16_t * Atqa);
|
||||
void MifareUltralightSetAtqa(uint16_t Atqa);
|
||||
void MifareUltralightGetSak(uint8_t * Sak);
|
||||
void MifareUltralightSetSak(uint8_t Sak);
|
||||
|
||||
#endif /* MIFAREULTRALIGHT_H_ */
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* NTAG215.c
|
||||
*
|
||||
* Created on: 20.02.2019
|
||||
* Author: Giovanni Cammisa (gcammisa)
|
||||
* Still missing support for:
|
||||
* - The management of both static and dynamic lock bytes
|
||||
* - Bruteforce protection (AUTHLIM COUNTER)
|
||||
* Thanks to skuser for the MifareUltralight code used as a starting point
|
||||
*/
|
||||
|
||||
#include "ISO14443-3A.h"
|
||||
#include "../Codec/ISO14443-2A.h"
|
||||
#include "../Memory.h"
|
||||
#include "NTAG215.h"
|
||||
|
||||
// DEFINE ATQA and SAK
|
||||
#define ATQA_VALUE 0x0044
|
||||
#define SAK_VALUE 0x00
|
||||
|
||||
#define SAK_CL1_VALUE ISO14443A_SAK_INCOMPLETE
|
||||
#define SAK_CL2_VALUE ISO14443A_SAK_COMPLETE_NOT_COMPLIANT
|
||||
|
||||
// ACK and NACK
|
||||
#define ACK_VALUE 0x0A
|
||||
#define ACK_FRAME_SIZE 4 /* Bits */
|
||||
#define NAK_INVALID_ARG 0x00
|
||||
#define NAK_CRC_ERROR 0x01
|
||||
#define NAK_NOT_AUTHED 0x04
|
||||
#define NAK_EEPROM_ERROR 0x05
|
||||
#define NAK_FRAME_SIZE 4
|
||||
|
||||
// DEFINING COMMANDS
|
||||
/* ISO commands */
|
||||
#define CMD_HALT 0x50
|
||||
// NTAG COMMANDS
|
||||
#define CMD_GET_VERSION 0x60
|
||||
#define CMD_READ 0x30
|
||||
#define CMD_FAST_READ 0x3A
|
||||
#define CMD_WRITE 0xA2
|
||||
#define CMD_COMPAT_WRITE 0xA0
|
||||
#define CMD_READ_CNT 0x39
|
||||
#define CMD_PWD_AUTH 0x1B
|
||||
#define CMD_READ_SIG 0x3C
|
||||
|
||||
// MEMORY LAYOUT STUFF, addresses and sizes in bytes
|
||||
// UID stuff
|
||||
#define UID_CL1_ADDRESS 0x00
|
||||
#define UID_CL1_SIZE 3
|
||||
#define UID_BCC1_ADDRESS 0x03
|
||||
#define UID_CL2_ADDRESS 0x04
|
||||
#define UID_CL2_SIZE 4
|
||||
#define UID_BCC2_ADDRESS 0x08
|
||||
// LockBytes stuff
|
||||
#define STATIC_LOCKBYTE_0_ADDRESS 0x0A
|
||||
#define STATIC_LOCKBYTE_1_ADDRESS 0x0B
|
||||
// CONFIG stuff
|
||||
#define CONFIG_AREA_START_ADDRESS NTAG215_PAGE_SIZE * 0x83
|
||||
#define CONFIG_AREA_SIZE 8
|
||||
// CONFIG offsets, relative to config start address
|
||||
#define CONF_AUTH0_OFFSET 0x03
|
||||
#define CONF_ACCESS_OFFSET 0x04
|
||||
#define CONF_PASSWORD_OFFSET 0x08
|
||||
#define CONF_PACK_OFFSET 0x0C
|
||||
|
||||
// WRITE STUFF
|
||||
#define BYTES_PER_WRITE 4
|
||||
#define PAGE_WRITE_MIN 0x02
|
||||
|
||||
// CONFIG masks to check individual needed bits
|
||||
#define CONF_ACCESS_PROT 0x80
|
||||
|
||||
#define VERSION_INFO_LENGTH 8 //8 bytes info lenght + crc
|
||||
|
||||
#define BYTES_PER_READ NTAG215_PAGE_SIZE * 4
|
||||
|
||||
// SIGNATURE Lenght
|
||||
#define SIGNATURE_LENGTH 32
|
||||
|
||||
|
||||
static enum {
|
||||
STATE_HALT,
|
||||
STATE_IDLE,
|
||||
STATE_READY1,
|
||||
STATE_READY2,
|
||||
STATE_ACTIVE
|
||||
} State;
|
||||
|
||||
static bool FromHalt = false;
|
||||
static uint8_t PageCount;
|
||||
static bool ArmedForCompatWrite;
|
||||
static uint8_t CompatWritePageAddress;
|
||||
static bool Authenticated;
|
||||
static uint8_t FirstAuthenticatedPage;
|
||||
static bool ReadAccessProtected;
|
||||
static uint8_t Access;
|
||||
|
||||
|
||||
void NTAG215AppInit(void)
|
||||
{
|
||||
|
||||
State = STATE_IDLE;
|
||||
FromHalt = false;
|
||||
ArmedForCompatWrite = false;
|
||||
Authenticated = false;
|
||||
PageCount = NTAG215_PAGES;
|
||||
|
||||
/* Fetch some of the configuration into RAM */
|
||||
MemoryReadBlock(&FirstAuthenticatedPage, CONFIG_AREA_START_ADDRESS + CONF_AUTH0_OFFSET, 1);
|
||||
MemoryReadBlock(&Access, CONFIG_AREA_START_ADDRESS + CONF_ACCESS_OFFSET, 1);
|
||||
ReadAccessProtected = !!(Access & CONF_ACCESS_PROT);
|
||||
}
|
||||
|
||||
void NTAG215AppReset(void)
|
||||
{
|
||||
State = STATE_IDLE;
|
||||
}
|
||||
|
||||
void NTAG215AppTask(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Verify authentication
|
||||
static bool VerifyAuthentication(uint8_t PageAddress)
|
||||
{
|
||||
/* If authenticated, no verification needed */
|
||||
if (Authenticated) {
|
||||
return true;
|
||||
}
|
||||
/* Otherwise, verify the accessed page is below the limit */
|
||||
return PageAddress < FirstAuthenticatedPage;
|
||||
}
|
||||
|
||||
// Writes a page
|
||||
static uint8_t AppWritePage(uint8_t PageAddress, uint8_t* const Buffer)
|
||||
{
|
||||
if (!ActiveConfiguration.ReadOnly) {
|
||||
MemoryWriteBlock(Buffer, PageAddress * NTAG215_PAGE_SIZE, NTAG215_PAGE_SIZE);
|
||||
} else {
|
||||
/* If the chameleon is in read only mode, it silently
|
||||
* ignores any attempt to write data. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Basic sketch of the command handling stuff
|
||||
static uint16_t AppProcess(uint8_t* const Buffer, uint16_t ByteCount)
|
||||
{
|
||||
uint8_t Cmd = Buffer[0];
|
||||
|
||||
/* Handle the compatibility write command */
|
||||
if (ArmedForCompatWrite) {
|
||||
ArmedForCompatWrite = false;
|
||||
|
||||
AppWritePage(CompatWritePageAddress, &Buffer[2]);
|
||||
Buffer[0] = ACK_VALUE;
|
||||
return ACK_FRAME_SIZE;
|
||||
}
|
||||
|
||||
switch (Cmd) {
|
||||
case CMD_GET_VERSION: {
|
||||
/* Provide hardcoded version response */ //VERSION RESPONSE FOR NTAG 215
|
||||
Buffer[0] = 0x00;
|
||||
Buffer[1] = 0x04;
|
||||
Buffer[2] = 0x04;
|
||||
Buffer[3] = 0x02;
|
||||
Buffer[4] = 0x01;
|
||||
Buffer[5] = 0x00;
|
||||
Buffer[6] = 0x11;
|
||||
Buffer[7] = 0x03;
|
||||
ISO14443AAppendCRCA(Buffer, VERSION_INFO_LENGTH);
|
||||
return (VERSION_INFO_LENGTH + ISO14443A_CRCA_SIZE) * 8;
|
||||
}
|
||||
|
||||
case CMD_READ: {
|
||||
uint8_t PageAddress = Buffer[1];
|
||||
uint8_t PageLimit;
|
||||
uint8_t Offset;
|
||||
|
||||
PageLimit = PageCount;
|
||||
|
||||
/* if protected and not autenticated, ensure the wraparound is at the first protected page */
|
||||
if (ReadAccessProtected && !Authenticated) {
|
||||
PageLimit = FirstAuthenticatedPage;
|
||||
}
|
||||
else {
|
||||
PageLimit = PageCount;
|
||||
}
|
||||
|
||||
/* Validation */
|
||||
if (PageAddress >= PageLimit) {
|
||||
Buffer[0] = NAK_INVALID_ARG;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
/* Read out, emulating the wraparound */
|
||||
for (Offset = 0; Offset < BYTES_PER_READ; Offset += 4) {
|
||||
MemoryReadBlock(&Buffer[Offset], PageAddress * NTAG215_PAGE_SIZE, NTAG215_PAGE_SIZE);
|
||||
PageAddress++;
|
||||
if (PageAddress == PageLimit) { // if arrived ad the last page, start reading from page 0
|
||||
PageAddress = 0;
|
||||
}
|
||||
}
|
||||
ISO14443AAppendCRCA(Buffer, BYTES_PER_READ);
|
||||
return (BYTES_PER_READ + ISO14443A_CRCA_SIZE) * 8;
|
||||
}
|
||||
|
||||
case CMD_FAST_READ: {
|
||||
uint8_t StartPageAddress = Buffer[1];
|
||||
uint8_t EndPageAddress = Buffer[2];
|
||||
/* Validation */
|
||||
if ((StartPageAddress > EndPageAddress) || (StartPageAddress >= PageCount) || (EndPageAddress >= PageCount)) {
|
||||
Buffer[0] = NAK_INVALID_ARG;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
|
||||
/* Check authentication only if protection is read&write (instead of only write protection) */
|
||||
if (ReadAccessProtected) {
|
||||
if (!VerifyAuthentication(StartPageAddress) || !VerifyAuthentication(EndPageAddress)) {
|
||||
Buffer[0] = NAK_NOT_AUTHED;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
ByteCount = (EndPageAddress - StartPageAddress + 1) * NTAG215_PAGE_SIZE;
|
||||
MemoryReadBlock(Buffer, StartPageAddress * NTAG215_PAGE_SIZE, ByteCount);
|
||||
ISO14443AAppendCRCA(Buffer, ByteCount);
|
||||
return (ByteCount + ISO14443A_CRCA_SIZE) * 8;
|
||||
}
|
||||
|
||||
case CMD_PWD_AUTH: {
|
||||
uint8_t Password[4];
|
||||
|
||||
/* For now I don't care about bruteforce protection, so: */
|
||||
/* TODO: IMPLEMENT COUNTER AUTHLIM */
|
||||
|
||||
/* Read and compare the password */
|
||||
MemoryReadBlock(Password, CONFIG_AREA_START_ADDRESS + CONF_PASSWORD_OFFSET, 4);
|
||||
if (Password[0] != Buffer[1] || Password[1] != Buffer[2] || Password[2] != Buffer[3] || Password[3] != Buffer[4]) {
|
||||
Buffer[0] = NAK_NOT_AUTHED;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
/* Authenticate the user */
|
||||
//RESET AUTHLIM COUNTER, CURRENTLY NOT IMPLEMENTED
|
||||
Authenticated = 1;
|
||||
/* Send the PACK value back */
|
||||
MemoryReadBlock(Buffer, CONFIG_AREA_START_ADDRESS + CONF_PACK_OFFSET, 2);
|
||||
ISO14443AAppendCRCA(Buffer, 2);
|
||||
return (2 + ISO14443A_CRCA_SIZE) * 8;
|
||||
}
|
||||
|
||||
case CMD_WRITE: {
|
||||
/* This is a write command containing 4 bytes of data that
|
||||
* should be written to the given page address. */
|
||||
uint8_t PageAddress = Buffer[1];
|
||||
/* Validation */
|
||||
if ((PageAddress < PAGE_WRITE_MIN) || (PageAddress >= PageCount)) {
|
||||
Buffer[0] = NAK_INVALID_ARG;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
if (!VerifyAuthentication(PageAddress)) {
|
||||
Buffer[0] = NAK_NOT_AUTHED;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
AppWritePage(PageAddress, &Buffer[2]);
|
||||
Buffer[0] = ACK_VALUE;
|
||||
return ACK_FRAME_SIZE;
|
||||
}
|
||||
|
||||
case CMD_COMPAT_WRITE: {
|
||||
uint8_t PageAddress = Buffer[1];
|
||||
/* Validation */
|
||||
if ((PageAddress < PAGE_WRITE_MIN) || (PageAddress >= PageCount)) {
|
||||
Buffer[0] = NAK_INVALID_ARG;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
if (!VerifyAuthentication(PageAddress)) {
|
||||
Buffer[0] = NAK_NOT_AUTHED;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
/* CRC check passed and page-address is within bounds.
|
||||
* Store address and proceed to receiving the data. */
|
||||
CompatWritePageAddress = PageAddress;
|
||||
ArmedForCompatWrite = true; //TODO:IMPLEMENT ARMED COMPAT WRITE
|
||||
Buffer[0] = ACK_VALUE;
|
||||
return ACK_FRAME_SIZE;
|
||||
}
|
||||
|
||||
|
||||
case CMD_READ_SIG: {
|
||||
/* Hardcoded response */
|
||||
memset(Buffer, 0xCA, SIGNATURE_LENGTH);
|
||||
ISO14443AAppendCRCA(Buffer, SIGNATURE_LENGTH);
|
||||
return (SIGNATURE_LENGTH + ISO14443A_CRCA_SIZE) * 8;
|
||||
}
|
||||
|
||||
//PART OF ISO STANDARD, NOT OF NTAG DATASHEET
|
||||
case CMD_HALT: {
|
||||
/* Halts the tag. According to the ISO14443, the second
|
||||
* byte is supposed to be 0. */
|
||||
if (Buffer[1] == 0) {
|
||||
/* According to ISO14443, we must not send anything
|
||||
* in order to acknowledge the HALT command. */
|
||||
State = STATE_HALT;
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
} else {
|
||||
Buffer[0] = NAK_INVALID_ARG;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* Command not handled. Switch to idle. */
|
||||
|
||||
State = STATE_IDLE;
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// FINITE STATE MACHINE STUFF, SHOULD BE THE VERY SIMILAR TO Mifare Ultralight
|
||||
uint16_t NTAG215AppProcess(uint8_t* Buffer, uint16_t BitCount)
|
||||
{
|
||||
uint8_t Cmd = Buffer[0];
|
||||
uint16_t ByteCount;
|
||||
|
||||
switch(State) {
|
||||
case STATE_IDLE:
|
||||
case STATE_HALT:
|
||||
FromHalt = State == STATE_HALT;
|
||||
if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) {
|
||||
/* We received a REQA or WUPA command, so wake up. */
|
||||
State = STATE_READY1;
|
||||
return BitCount;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_READY1:
|
||||
if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) {
|
||||
State = FromHalt ? STATE_HALT : STATE_IDLE;
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
} else if (Cmd == ISO14443A_CMD_SELECT_CL1) {
|
||||
/* Load UID CL1 and perform anticollision. Since
|
||||
* MF Ultralight use a double-sized UID, the first byte
|
||||
* of CL1 has to be the cascade-tag byte. */
|
||||
uint8_t UidCL1[ISO14443A_CL_UID_SIZE] = { [0] = ISO14443A_UID0_CT };
|
||||
|
||||
MemoryReadBlock(&UidCL1[1], UID_CL1_ADDRESS, UID_CL1_SIZE);
|
||||
|
||||
if (ISO14443ASelect(Buffer, &BitCount, UidCL1, SAK_CL1_VALUE)) {
|
||||
/* CL1 stage has ended successfully */
|
||||
State = STATE_READY2;
|
||||
}
|
||||
|
||||
return BitCount;
|
||||
} else {
|
||||
/* Unknown command. Enter halt state */
|
||||
State = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_READY2:
|
||||
if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) {
|
||||
State = FromHalt ? STATE_HALT : STATE_IDLE;
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
} else if (Cmd == ISO14443A_CMD_SELECT_CL2) {
|
||||
/* Load UID CL2 and perform anticollision */
|
||||
uint8_t UidCL2[ISO14443A_CL_UID_SIZE];
|
||||
|
||||
MemoryReadBlock(UidCL2, UID_CL2_ADDRESS, UID_CL2_SIZE);
|
||||
|
||||
if (ISO14443ASelect(Buffer, &BitCount, UidCL2, SAK_CL2_VALUE)) {
|
||||
/* CL2 stage has ended successfully. This means
|
||||
* our complete UID has been sent to the reader. */
|
||||
State = STATE_ACTIVE;
|
||||
}
|
||||
|
||||
return BitCount;
|
||||
} else {
|
||||
/* Unknown command. Enter halt state */
|
||||
State = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
// Only ACTIVE state, no AUTHENTICATED state, PWD_AUTH is handled in commands.
|
||||
case STATE_ACTIVE:
|
||||
/* Preserve incoming data length */
|
||||
ByteCount = (BitCount + 7) >> 3;
|
||||
if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) {
|
||||
State = FromHalt ? STATE_HALT : STATE_IDLE;
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
}
|
||||
/* At the very least, there should be 3 bytes in the buffer. */
|
||||
if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) {
|
||||
State = STATE_IDLE;
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
}
|
||||
/* All commands here have CRCA appended; verify it right away */
|
||||
ByteCount -= 2;
|
||||
if (!ISO14443ACheckCRCA(Buffer, ByteCount)) {
|
||||
Buffer[0] = NAK_CRC_ERROR;
|
||||
return NAK_FRAME_SIZE;
|
||||
}
|
||||
return AppProcess(Buffer, ByteCount);
|
||||
|
||||
default:
|
||||
/* Unknown state? Should never happen. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* No response has been sent, when we reach here */
|
||||
return ISO14443A_APP_NO_RESPONSE;
|
||||
}
|
||||
|
||||
// HELPER FUNCTIONS
|
||||
void NTAG215GetUid(ConfigurationUidType Uid)
|
||||
{
|
||||
/* Read UID from memory */
|
||||
MemoryReadBlock(&Uid[0], UID_CL1_ADDRESS, UID_CL1_SIZE);
|
||||
MemoryReadBlock(&Uid[UID_CL1_SIZE], UID_CL2_ADDRESS, UID_CL2_SIZE);
|
||||
}
|
||||
|
||||
void NTAG215SetUid(ConfigurationUidType Uid)
|
||||
{
|
||||
/* Calculate check bytes and write everything into memory */
|
||||
uint8_t BCC1 = ISO14443A_UID0_CT ^ Uid[0] ^ Uid[1] ^ Uid[2];
|
||||
uint8_t BCC2 = Uid[3] ^ Uid[4] ^ Uid[5] ^ Uid[6];
|
||||
|
||||
MemoryWriteBlock(&Uid[0], UID_CL1_ADDRESS, UID_CL1_SIZE);
|
||||
MemoryWriteBlock(&BCC1, UID_BCC1_ADDRESS, ISO14443A_CL_BCC_SIZE);
|
||||
MemoryWriteBlock(&Uid[UID_CL1_SIZE], UID_CL2_ADDRESS, UID_CL2_SIZE);
|
||||
MemoryWriteBlock(&BCC2, UID_BCC2_ADDRESS, ISO14443A_CL_BCC_SIZE);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* NTAG215.h
|
||||
*
|
||||
* Created on: 20.02.2019
|
||||
* Author: gcammisa
|
||||
*/
|
||||
|
||||
#ifndef NTAG215_H_
|
||||
#define NTAG215_H_
|
||||
|
||||
#include "Application.h"
|
||||
#include "ISO14443-3A.h"
|
||||
|
||||
#define NTAG215_UID_SIZE ISO14443A_UID_SIZE_DOUBLE // 7 bytes UID
|
||||
#define NTAG215_PAGE_SIZE 4 // bytes per page
|
||||
#define NTAG215_PAGES 135 // 135 pages total, from 0 to 134
|
||||
#define NTAG215_MEM_SIZE ( NTAG215_PAGE_SIZE * NTAG215_PAGES )
|
||||
|
||||
void NTAG215AppInit(void);
|
||||
void NTAG215AppReset(void);
|
||||
void NTAG215AppTask(void);
|
||||
|
||||
uint16_t NTAG215AppProcess(uint8_t* Buffer, uint16_t BitCount);
|
||||
|
||||
void NTAG215GetUid(ConfigurationUidType Uid);
|
||||
void NTAG215SetUid(ConfigurationUidType Uid);
|
||||
#endif
|
||||
@@ -20,6 +20,9 @@
|
||||
|
||||
// TODO replace remaining magic numbers
|
||||
|
||||
uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE];
|
||||
uint16_t ReaderSendBitCount;
|
||||
|
||||
static bool Selected = false;
|
||||
Reader14443Command Reader14443CurrentCommand = Reader14443_Do_Nothing;
|
||||
|
||||
@@ -684,6 +687,7 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
case Reader14443_Clone_MF_Ultralight:
|
||||
case Reader14443_Read_MF_Ultralight: {
|
||||
static uint8_t MFURead_CurrentAdress = 0;
|
||||
static uint8_t MFUContents[64];
|
||||
@@ -718,18 +722,28 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) {
|
||||
if (MFURead_CurrentAdress == 16) {
|
||||
Selected = false;
|
||||
MFURead_CurrentAdress = 0;
|
||||
Reader14443CurrentCommand = Reader14443_Do_Nothing;
|
||||
|
||||
char tmpBuf[135]; // 135 = 128 hex digits + 3 * \r\n + \0
|
||||
BufferToHexString(tmpBuf, 135, MFUContents, 16);
|
||||
snprintf(tmpBuf + 32, 135 - 32, "\r\n");
|
||||
BufferToHexString(tmpBuf + 32 + 2, 135 - 32 - 2, MFUContents + 16, 16);
|
||||
snprintf(tmpBuf + 32 + 2 + 32, 135 - 32 - 2 - 32, "\r\n");
|
||||
BufferToHexString(tmpBuf + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2, MFUContents + 32, 16);
|
||||
snprintf(tmpBuf + 32 + 2 + 32 + 2 + 32, 135 - 32 - 2 - 32 - 2 - 32, "\r\n");
|
||||
BufferToHexString(tmpBuf + 32 + 2 + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2 - 32 - 2, MFUContents + 48, 16);
|
||||
CodecReaderFieldStop();
|
||||
CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf);
|
||||
if (Reader14443CurrentCommand == Reader14443_Read_MF_Ultralight) { // dump
|
||||
Reader14443CurrentCommand = Reader14443_Do_Nothing;
|
||||
char tmpBuf[135]; // 135 = 128 hex digits + 3 * \r\n + \0
|
||||
BufferToHexString(tmpBuf, 135, MFUContents, 16);
|
||||
snprintf(tmpBuf + 32, 135 - 32, "\r\n");
|
||||
BufferToHexString(tmpBuf + 32 + 2, 135 - 32 - 2, MFUContents + 16, 16);
|
||||
snprintf(tmpBuf + 32 + 2 + 32, 135 - 32 - 2 - 32, "\r\n");
|
||||
BufferToHexString(tmpBuf + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2, MFUContents + 32, 16);
|
||||
snprintf(tmpBuf + 32 + 2 + 32 + 2 + 32, 135 - 32 - 2 - 32 - 2 - 32, "\r\n");
|
||||
BufferToHexString(tmpBuf + 32 + 2 + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2 - 32 - 2, MFUContents + 48, 16);
|
||||
CodecReaderFieldStop();
|
||||
CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf);
|
||||
} else { // clone
|
||||
Reader14443CurrentCommand = Reader14443_Do_Nothing;
|
||||
CodecReaderFieldStop();
|
||||
MemoryUploadBlock(&MFUContents, 0, 64);
|
||||
CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Card Cloned to Slot");
|
||||
ConfigurationSetById(CONFIG_MF_ULTRALIGHT);
|
||||
MemoryStore();
|
||||
SettingsSave();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Buffer[0] = 0x30; // MiFare Ultralight read command
|
||||
@@ -803,17 +817,17 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) {
|
||||
if (CardCandidatesIdx == 1) {
|
||||
int cfgid = -1;
|
||||
switch (CardCandidates[0]) {
|
||||
#ifdef CONFIG_MF_ULTRALIGHT_SUPPORT
|
||||
case CardType_NXP_MIFARE_Ultralight: {
|
||||
cfgid = CONFIG_MF_ULTRALIGHT;
|
||||
// TODO: enter MFU clone mdoe
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CardType_NXP_MIFARE_Classic_1k:
|
||||
case CardType_Infineon_MIFARE_Classic_1k: {
|
||||
if (CardCharacteristics.UIDSize == UIDSize_Single) {
|
||||
#ifdef CONFIG_MF_CLASSIC_1K_SUPPORT
|
||||
cfgid = CONFIG_MF_CLASSIC_1K;
|
||||
#endif
|
||||
#ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT
|
||||
} else if (CardCharacteristics.UIDSize == UIDSize_Double) {
|
||||
cfgid = CONFIG_MF_CLASSIC_1K_7B;
|
||||
@@ -825,8 +839,10 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) {
|
||||
case CardType_Nokia_MIFARE_Classic_4k_emulated_6212:
|
||||
case CardType_Nokia_MIFARE_Classic_4k_emulated_6131: {
|
||||
if (CardCharacteristics.UIDSize == UIDSize_Single) {
|
||||
#ifdef CONFIG_MF_CLASSIC_4K_SUPPORT
|
||||
cfgid = CONFIG_MF_CLASSIC_4K;
|
||||
#ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT
|
||||
#endif
|
||||
#ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT
|
||||
} else if (CardCharacteristics.UIDSize == UIDSize_Double) {
|
||||
cfgid = CONFIG_MF_CLASSIC_4K_7B;
|
||||
#endif
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#define CRC_INIT 0x6363
|
||||
|
||||
uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE];
|
||||
uint16_t ReaderSendBitCount;
|
||||
extern uint8_t ReaderSendBuffer[];
|
||||
extern uint16_t ReaderSendBitCount;
|
||||
|
||||
void Reader14443AAppInit(void);
|
||||
void Reader14443AAppReset(void);
|
||||
@@ -30,7 +30,8 @@ typedef enum {
|
||||
Reader14443_Autocalibrate,
|
||||
Reader14443_Read_MF_Ultralight,
|
||||
Reader14443_Identify,
|
||||
Reader14443_Identify_Clone
|
||||
Reader14443_Identify_Clone,
|
||||
Reader14443_Clone_MF_Ultralight
|
||||
} Reader14443Command;
|
||||
|
||||
|
||||
|
||||
@@ -141,12 +141,6 @@ uint16_t Sl2s2002AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ResponseByteCount > 0) {
|
||||
/* There is data to be sent. Append CRC */
|
||||
ISO15693AppendCRC(FrameBuf, ResponseByteCount);
|
||||
ResponseByteCount += ISO15693_CRC16_SIZE;
|
||||
}
|
||||
|
||||
return ResponseByteCount;
|
||||
|
||||
} else { // Invalid CRC
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user