M5Unit-NFC 0.0.3 git rev:59f5362
Loading...
Searching...
No Matches
desfire_file_system.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_UNIFIED_NFC_NFC_ISODEP_DESFIRE_FILE_SYSTEM_HPP
11#define M5_UNIT_UNIFIED_NFC_NFC_ISODEP_DESFIRE_FILE_SYSTEM_HPP
12#include "file_system.hpp"
13#include "nfc/a/mifare.hpp"
14#include "nfc/ndef/ndef.hpp"
15#include <m5_utility/stl/expected.hpp>
16#include <array>
17#include <algorithm>
18#include <limits>
19
20namespace m5 {
21namespace nfc {
22class NFCLayerA;
23namespace a {
24namespace mifare {
29namespace desfire {
30
31constexpr uint8_t DESFIRE_APDU_CLA{0x90};
32constexpr uint8_t DESFIRE_LIGHT_INS_READ_DATA{0xAD};
33constexpr uint8_t DESFIRE_LIGHT_INS_WRITE_DATA{0x8D};
34
37using file_no_t = uint8_t;
41
43
44namespace detail {
45
46inline uint16_t clamp_u16_size(const size_t size)
47{
48 constexpr size_t max_u16 = std::numeric_limits<uint16_t>::max();
49 return static_cast<uint16_t>(size > max_u16 ? max_u16 : size);
50}
51
52inline uint16_t default_rx_capacity(const m5::nfc::isodep::IsoDEP& dep)
53{
54 const uint16_t cfg_rx = dep.config().max_frame_size_rx();
55 const uint16_t base = cfg_rx ? cfg_rx : 256;
56 return std::max<uint16_t>(256, base);
57}
58
59inline void pack_le24(uint8_t out[3], const uint32_t value)
60{
61 out[0] = static_cast<uint8_t>(value & 0xFF);
62 out[1] = static_cast<uint8_t>((value >> 8) & 0xFF);
63 out[2] = static_cast<uint8_t>((value >> 16) & 0xFF);
64}
65
66inline void pack_be24(uint8_t out[3], const uint32_t value)
67{
68 out[0] = static_cast<uint8_t>((value >> 16) & 0xFF);
69 out[1] = static_cast<uint8_t>((value >> 8) & 0xFF);
70 out[2] = static_cast<uint8_t>(value & 0xFF);
71}
72
73inline uint32_t unpack_le24(const uint8_t in[3])
74{
75 return static_cast<uint32_t>(in[0]) | (static_cast<uint32_t>(in[1]) << 8) | (static_cast<uint32_t>(in[2]) << 16);
76}
77
78} // namespace detail
79
85 uint8_t file_type{};
86 uint8_t comm_mode{};
87 uint16_t access_rights{};
88 uint32_t file_size{};
89};
90
96 uint8_t aid[3]{}; // BE
97 uint8_t _pad{};
98 inline constexpr uint32_t aid24() const noexcept
99 {
100 // Big-endian
101 return ((uint32_t)aid[0] << 16) | ((uint32_t)aid[1] << 8) | aid[2];
102 }
103 inline constexpr const uint8_t* data() const noexcept
104 {
105 return aid;
106 }
107 inline explicit operator uint32_t() const noexcept
108 {
109 return aid24();
110 }
111};
112inline bool operator==(const desfire_aid_t& a, const desfire_aid_t& b) noexcept
113{
114 return a.aid[0] == b.aid[0] && a.aid[1] == b.aid[1] && a.aid[2] == b.aid[2];
115}
116inline bool operator!=(const desfire_aid_t& a, const desfire_aid_t& b) noexcept
117{
118 return !(a == b);
119}
120inline bool operator<(const desfire_aid_t& a, const desfire_aid_t& b) noexcept
121{
122 return a.aid24() < b.aid24();
123}
124
129enum class AuthMode : uint8_t {
130 Auto,
131 DES,
132 AES,
133};
134
155
161 uint8_t old_file_no{};
162 uint8_t new_file_no{};
163 uint16_t new_file_id{};
164};
165
171 uint8_t ti[4]{};
172 uint16_t cmd_ctr{};
173 uint8_t ses_enc_key[16]{};
174 uint8_t ses_mac_key[16]{};
175};
184std::vector<uint8_t> make_native_wrap_command(const uint8_t ins, const uint8_t* data = nullptr,
185 const uint16_t data_len = 0);
186
188inline uint8_t status_code(const uint8_t* rx, const uint16_t rx_len)
189{
190 return (rx && rx_len >= 2 && rx[rx_len - 2] == 0x91) ? rx[rx_len - 1] : 0xFF;
191}
192
194inline bool is_successful(const uint8_t* rx, const uint16_t rx_len)
195{
196 return status_code(rx, rx_len) == 0x00;
197}
198
200inline bool is_more(const uint8_t* rx, const uint16_t rx_len)
201{
202 return status_code(rx, rx_len) == 0xAF;
203}
204
206inline bool is_duplicate(const uint8_t* rx, const uint16_t rx_len)
207{
208 return status_code(rx, rx_len) == 0xDE;
209}
210
216public:
217 explicit DESFireFileSystem(m5::nfc::NFCLayerA& layer);
218 explicit DESFireFileSystem(m5::nfc::isodep::IsoDEP& isoDEP) : FileSystem{isoDEP}
219 {
220 }
221
222 m5::stl::expected<void, uint8_t> createApplication(const uint8_t aid[3], const uint8_t key_settings1,
223 const uint8_t key_settings2, const uint16_t iso_fid = 0,
224 const uint8_t* df_name = nullptr, const uint8_t df_name_len = 0);
225 inline bool selectApplication(const desfire_aid_t& aid)
226 {
227 return selectApplication(aid.data());
228 }
229 bool selectApplication(const uint8_t aid[3]);
230 bool selectApplication(const uint32_t aid24 = 0u);
231 bool deleteApplication(const uint8_t aid[3]);
232
233 bool getApplicationIDs(std::vector<desfire_aid_t>& out);
234 // NOTE: getFreeMemory is intended to be used before authentication (no secure messaging).
235 bool getFreeMemory(uint32_t& out);
236 bool getKeySettings(uint8_t& key_settings, uint8_t& key_count);
237 bool getFileIDs(std::vector<uint8_t>& out);
238 bool getISOFileIDs(std::vector<uint8_t>& out);
239 bool getFileSettings(FileSettings& out, const uint8_t file_no);
240 bool getFileSettingsEV2(FileSettings& out, const uint8_t file_no, Ev2Context& ctx);
241 bool getFileSettingsEV2Full(FileSettings& out, const uint8_t file_no, Ev2Context& ctx);
242
243 bool changeFileSettings(const uint8_t file_no, const uint8_t file_option, const uint16_t access_rights);
244 bool changeFileSettingsEV2(const uint8_t file_no, const uint8_t file_option, const uint16_t access_rights,
245 Ev2Context& ctx);
246 bool changeFileSettingsEV2Full(const uint8_t file_no, const uint8_t file_option, const uint16_t access_rights,
247 Ev2Context& ctx);
248
249 bool formatPICC(const uint8_t* picc_master_key, const AuthMode mode = AuthMode::Auto);
250
251 bool createStdDataFile(const uint8_t file_no, const uint16_t iso_fid, const uint8_t comm_mode,
252 const uint16_t access_rights, const uint32_t file_size);
253
254 // DESFire Light: requires AppMasterKey authentication and CommMode.Full.
255 bool setConfigurationFileRenaming(const FileRename& first, const FileRename* second = nullptr);
256 bool setConfigurationFileRenamingEV2Full(const FileRename& first, const FileRename* second, Ev2Context& ctx);
257
265 bool deleteTransactionMACFileEV2Full(const uint8_t file_no, Ev2Context& ctx);
266
277 bool createTransactionMACFileEV2Full(const uint8_t file_no, const uint8_t comm_mode, const uint16_t access_rights,
278 const uint8_t tmac_key[16], const uint8_t tmac_key_ver, Ev2Context& ctx);
279 bool setConfigurationAppNameEV2Full(const uint8_t* df_name, uint8_t df_name_len, uint16_t iso_fid, Ev2Context& ctx);
280
289 bool readData(std::vector<uint8_t>& out, const uint8_t file_no, const uint32_t offset, const uint32_t length);
290 bool readDataLight(std::vector<uint8_t>& out, const uint8_t file_no, const uint32_t offset, const uint32_t length);
291 bool readDataLightEV2Full(std::vector<uint8_t>& out, const uint8_t file_no, const uint32_t offset,
292 const uint32_t length, Ev2Context& ctx);
293 bool readDataLightEV2(std::vector<uint8_t>& out, const uint8_t file_no, const uint32_t offset,
294 const uint32_t length, Ev2Context& ctx);
295 bool writeData(const uint8_t file_no, const uint32_t offset, const uint8_t* data, const uint32_t data_len);
296 bool writeDataLight(const uint8_t file_no, const uint32_t offset, const uint8_t* data, const uint32_t data_len);
297 bool writeDataLightEV2(const uint8_t file_no, const uint32_t offset, const uint8_t* data, const uint32_t data_len,
298 Ev2Context& ctx);
299 bool writeDataLightEV2Full(const uint8_t file_no, const uint32_t offset, const uint8_t* data,
300 const uint32_t data_len, Ev2Context& ctx);
301
302 bool authenticateDES(const uint8_t key_no, const uint8_t key[16]);
303 bool authenticateISO(const uint8_t key_no, const uint8_t key[16]);
304 bool authenticateAES(const uint8_t key_no, const uint8_t key[16]);
305 bool authenticateEV2First(const uint8_t key_no, const uint8_t key[16], Ev2Context& ctx);
306
307protected:
308 bool transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len);
309};
310
311} // namespace desfire
312} // namespace mifare
313} // namespace a
314} // namespace nfc
315} // namespace m5
316#endif
ISO/IEC 7816-4 file system.
Definition file_system.hpp:81
Common interface layer for each chip of the NFC-A reader.
Definition nfc_layer_a.hpp:43
File system for MIFARE DESFire.
Definition desfire_file_system.hpp:215
bool createTransactionMACFileEV2Full(const uint8_t file_no, const uint8_t comm_mode, const uint16_t access_rights, const uint8_t tmac_key[16], const uint8_t tmac_key_ver, Ev2Context &ctx)
Create TransactionMAC file.
Definition desfire_file_system.cpp:1101
bool readData(std::vector< uint8_t > &out, const uint8_t file_no, const uint32_t offset, const uint32_t length)
Read data from DESFire file.
Definition desfire_file_system.cpp:567
bool deleteTransactionMACFileEV2Full(const uint8_t file_no, Ev2Context &ctx)
Delete TransactionMAC file (required for ISOReadBinary to work)
Definition desfire_file_system.cpp:1092
ISO Data Exchange Protocol.
Definition isoDEP.hpp:190
bool is_more(const uint8_t *rx, const uint16_t rx_len)
Is the received data still waiting for a response?
Definition desfire_file_system.hpp:200
constexpr file_no_t MAXIMUM_FILE_NO
Maximum file number.
Definition desfire_file_system.hpp:39
uint8_t file_no_t
Alias for file number.
Definition desfire_file_system.hpp:37
bool is_duplicate(const uint8_t *rx, const uint16_t rx_len)
Is duplicate error? (e.g. app/file already exists)
Definition desfire_file_system.hpp:206
constexpr uint8_t MAXIMUM_FILES
Files max.
Definition desfire_file_system.hpp:42
constexpr file_no_t MINIMUM_FILE_NO
Minimum file number.
Definition desfire_file_system.hpp:38
AuthMode
Authentication mode.
Definition desfire_file_system.hpp:129
bool is_successful(const uint8_t *rx, const uint16_t rx_len)
Is the status of the received data successful?
Definition desfire_file_system.hpp:194
uint8_t status_code(const uint8_t *rx, const uint16_t rx_len)
DESFire status code (0x91xx)
Definition desfire_file_system.hpp:188
File system base using isoDEP.
MIFARE definitions.
constexpr uint8_t DESFIRE_CC_FILE_NO
AN11004 default CC file number.
Definition mifare.hpp:196
constexpr uint8_t DESFIRE_NDEF_FILE_NO
AN11004 default NDEF file number.
Definition mifare.hpp:197
constexpr uint8_t DESFIRE_NDEF_AID[]
DESFire NDEF AID (3 bytes)
Definition mifare.hpp:198
NFC-A definitions.
NFC-B definitions.
Top level namespace of M5stack.
For MIFARE.
NFC related definitions.
NDEF related.
bool operator==(const PICC &a, const PICC &b)
Equal?
Definition nfca.hpp:523
bool operator!=(const PICC &a, const PICC &b)
Not equal?
Definition nfca.hpp:529
Session context for EV2 secure messaging.
Definition desfire_file_system.hpp:170
uint8_t ses_mac_key[16]
Session MAC key.
Definition desfire_file_system.hpp:174
uint16_t cmd_ctr
Command Counter.
Definition desfire_file_system.hpp:172
uint8_t ses_enc_key[16]
Session ENC key.
Definition desfire_file_system.hpp:173
uint8_t ti[4]
Transaction Identifier.
Definition desfire_file_system.hpp:171
File renaming parameters for DESFire Light SetConfiguration.
Definition desfire_file_system.hpp:160
uint16_t new_file_id
New ISO File ID (LSB first in command)
Definition desfire_file_system.hpp:163
uint8_t new_file_no
New file number.
Definition desfire_file_system.hpp:162
uint8_t old_file_no
Current file number.
Definition desfire_file_system.hpp:161
DESFire file settings (minimal fields for StdDataFile)
Definition desfire_file_system.hpp:84
Options for formatting DESFire as Type4 NDEF.
Definition desfire_file_system.hpp:139
uint8_t key_settings1
AN11004: Create/Delete requires auth, Get* requires auth.
Definition desfire_file_system.hpp:149
uint8_t aid[3]
NDEF Tag Application AID.
Definition desfire_file_system.hpp:141
const uint8_t * app_master_key
DES/3DES master key (App), or nullptr to skip auth.
Definition desfire_file_system.hpp:152
uint8_t comm_mode
Plain communication.
Definition desfire_file_system.hpp:147
uint16_t ndef_file_size
NDEF file size (bytes)
Definition desfire_file_system.hpp:146
const uint8_t * picc_master_key
DES/3DES master key (PICC), or nullptr to skip auth.
Definition desfire_file_system.hpp:151
AuthMode auth_mode
Authentication mode.
Definition desfire_file_system.hpp:153
uint16_t cc_file_size
CC file size (bytes)
Definition desfire_file_system.hpp:145
uint16_t access_rights
DESFire access rights.
Definition desfire_file_system.hpp:148
uint8_t key_settings2
ISO FID support(bit5) + NumKeys=1 + DES/3DES.
Definition desfire_file_system.hpp:150
m5::nfc::ndef::type4::CapabilityContainer cc
CC contents.
Definition desfire_file_system.hpp:140
uint8_t ndef_file_no
NDEF file number (DESFire)
Definition desfire_file_system.hpp:144
uint8_t cc_file_no
CC file number (DESFire)
Definition desfire_file_system.hpp:143
24bit Application ID
Definition desfire_file_system.hpp:95
Capability container for Type4.
Definition ndef.hpp:455