M5Unit-NFC 0.1.0 git rev:93745b5
Loading...
Searching...
No Matches
apdu.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_APDU_APDU_HPP
11#define M5_UNIT_UNIFIED_NFC_NFC_APDU_APDU_HPP
12#include <cstdint>
13#include <string>
14#include <vector>
15
16namespace m5 {
17namespace nfc {
22namespace apdu {
23
27constexpr uint16_t RESPONSE_OK{0x9000};
29constexpr uint16_t SUCCESSFULLY_1{0x6100};
31constexpr uint16_t SUCCESSFULLY_2{0x9F00};
32
33constexpr uint8_t RESPONSE_BYTES_STILL_AVAILABLE{0x61};
34constexpr uint8_t WRONG_LENGTH_LE{0x6C};
36
42inline bool is_response_OK(const uint16_t sw12)
43{
44 return sw12 == RESPONSE_OK || ((sw12 & 0xFF00) == SUCCESSFULLY_1) || ((sw12 & 0xFF00) == SUCCESSFULLY_2);
45}
46
52inline bool is_response_OK(const uint8_t sw[2])
53{
54 return is_response_OK((uint16_t)((sw[0] << 8) | sw[1]));
55}
62inline bool is_response_OK(const uint8_t sw1, const uint8_t sw2)
63{
64 return is_response_OK((uint16_t)((sw1 << 8) | sw2));
65}
66
71enum class INS : uint8_t {
72 // ISO/IEC 7816-4
73 SELECT_FILE = 0xA4,
74 CREATE_FILE = 0xE0,
75
76 READ_BINARY = 0xB0,
77 WRITE_BINARY = 0xD0,
78 UPDATE_BINARY = 0xD6,
79 ERASE_BINARY = 0x0E,
80
81 READ_RECORD = 0xB2,
82 WRITE_RECORD = 0xD2,
83 APPEND_RECORD = 0xE2,
84 UPDATE_RECORD = 0xDC,
85 UPDATE_RECORRD = UPDATE_RECORD,
86
87 GET_RESPONSE = 0xC0,
88 GET_DATA = 0xCA,
89 PUT_DATA = 0xDA,
90
91 VERIFY = 0x20,
92
93 INTERNAL_AUTHENTICATE = 0x88,
94 EXTERNAL_AUTHENTICATE = 0x82,
95
96 GET_CHALLENGE = 0x84,
97 GET_CHALLEMGE = GET_CHALLENGE,
98
99 // Not ISO/IEC 7816-4
100 LOCK_DF = 0x50,
101 UNLOCK_DF = 0x52,
102 UNLOCK_KEY = 0x54,
103 CHANGE_KEY = 0x32,
104 ERASE_ALL_RECORDS = 0x06,
105 GET_VERSION = 0x60,
106
107 // DESFire
108 DF_CREATE_APPLICATION = 0xCA,
109 DF_DELETE_APPLICATION = 0xDA,
110 DF_SELECT_APPLICATION = 0x5A,
111 DF_GET_APPLICATION_IDS = 0x6A,
112 DF_CREATE_STD_DATA_FILE = 0xCD,
113 DF_GET_FREE_MEMORY = 0x6E,
114 DF_GET_FILE_IDS = 0x6F,
115 DF_GET_ISO_FILE_IDS = 0x61,
116 DF_GET_KEY_SETTINGS = 0x45,
117 DF_SET_CONFIGURATION = 0x5C,
118 DF_CHANGE_FILE_SETTINGS = 0x5F,
119 DF_AUTHENTICATE = 0x0A,
120 DF_AUTHENTICATE_ISO = 0x1A,
121 DF_AUTHENTICATE_AES = 0xAA,
122 DF_AUTHENTICATE_EV2 = 0x71,
123 DF_FORMAT_PICC = 0xFC,
124 DF_READ_DATA = 0xBD,
125 DF_WRITE_DATA = 0x3D,
126 DF_GET_FILE_SETTINGS = 0xF5,
127 DF_DELETE_TRANSACTION_MAC_FILE = 0xDF,
128 DF_CREATE_TRANSACTION_MAC_FILE = 0xCE,
129};
131
137enum class SelectBy : uint8_t {
138 FileId = 0x00,
139 ChildDf = 0x01,
140 EfUnderCurrentDf = 0x02,
141 ParentDf = 0x03,
142 DfName = 0x04,
143 PathFromMf = 0x08,
144 PathFromCurrentDf = 0x09,
145};
146
152enum class SelectOccurrence : uint8_t {
153 FirstOrOnly = 0x00,
154 Last = 0x01,
155 Next = 0x02,
156 Previous = 0x03,
157};
158
163enum class SelectResponse : uint8_t {
164 FCI = 0x00,
165 FCP = 0x04,
166 FMD = 0x08,
167 None = 0x0C,
168};
169
170constexpr uint16_t master_file_id{0x3F00};
171
177inline bool need_select_file_le(const uint8_t param2)
178{
179 return (param2 & 0x0C) != 0x0C;
180}
181
186struct TLV {
187 uint32_t tag{};
188 uint32_t len{};
189 const uint8_t* v{};
190 uint8_t tag_len{};
191
196 inline bool is_constructed() const
197 {
198 return (tag & 0x20) != 0;
199 }
204 inline bool is_primitive() const
205 {
206 return !is_constructed();
207 }
208};
209
216std::vector<TLV> parse_tlv(const uint8_t* ptr, const uint32_t len);
222void dump_tlv(const std::vector<TLV>& tlvs, const uint8_t depth = 0);
223
235std::vector<uint8_t> make_apdu_command(const uint8_t cla, const uint8_t ins, const uint8_t param1 = 0x00,
236 const uint8_t param2 = 0x00, const uint8_t* data = nullptr,
237 const uint16_t data_len = 0, const uint16_t rx_len = 0);
238
247inline std::vector<uint8_t> make_apdu_case1(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2)
248{
249 return make_apdu_command(cla, ins, p1, p2, nullptr, 0, 0);
250}
251
261inline std::vector<uint8_t> make_apdu_case2(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2,
262 const uint16_t le)
263{
264 return make_apdu_command(cla, ins, p1, p2, nullptr, 0, le);
265}
266
277inline std::vector<uint8_t> make_apdu_case3(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2,
278 const uint8_t* data, const uint16_t data_len)
279{
280 return make_apdu_command(cla, ins, p1, p2, data, data_len, 0);
281}
282
294inline std::vector<uint8_t> make_apdu_case4(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2,
295 const uint8_t* data, const uint16_t data_len, const uint16_t le)
296{
297 return make_apdu_command(cla, ins, p1, p2, data, data_len, le);
298}
299
300} // namespace apdu
301} // namespace nfc
302} // namespace m5
303#endif
std::vector< uint8_t > make_apdu_command(const uint8_t cla, const uint8_t ins, const uint8_t param1, const uint8_t param2, const uint8_t *data, const uint16_t data_len, const uint16_t rx_len)
Make APDU command.
Definition apdu.cpp:22
SelectBy
Select control for SELECT_FILE.
Definition apdu.hpp:137
@ EfUnderCurrentDf
Select EF under current DF (FID in data)
@ FileId
Select MF/DF/EF by file ID.
@ DfName
Select by DF name (AID)
@ ChildDf
Select child DF (FID in data)
@ PathFromMf
Select by path from MF.
@ PathFromCurrentDf
Select by path from current DF.
@ ParentDf
Select parent DF.
constexpr uint16_t RESPONSE_OK
Command successfully executed (OK)
Definition apdu.hpp:27
constexpr uint16_t SUCCESSFULLY_2
Command successfully executed; xx bytes of data are available and can be requested using GET RESPONSE...
Definition apdu.hpp:31
std::vector< uint8_t > make_apdu_case1(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2)
Make APDU case1 command [CLA | INS | P1 | P2].
Definition apdu.hpp:247
SelectResponse
Response for SELECT_FILE.
Definition apdu.hpp:163
constexpr uint8_t WRONG_LENGTH_LE
Wrong length Le.
Definition apdu.hpp:34
std::vector< uint8_t > make_apdu_case2(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint16_t le)
Make APDU case2 command [CLA | INS | P1 | P2 | Le].
Definition apdu.hpp:261
INS
APDU instruction code.
Definition apdu.hpp:71
bool need_select_file_le(const uint8_t param2)
Check whether SELECT FILE expects Le.
Definition apdu.hpp:177
constexpr uint8_t RESPONSE_BYTES_STILL_AVAILABLE
Response bytes still available.
Definition apdu.hpp:33
constexpr uint16_t SUCCESSFULLY_1
Command successfully executed; xx bytes of data are available and can be requested using GET RESPONSE...
Definition apdu.hpp:29
SelectOccurrence
Select occurrence for SELECT_FILE.
Definition apdu.hpp:152
@ Next
Select the next match.
@ FirstOrOnly
Select the first (or only) match.
@ Last
Select the last match.
@ Previous
Select the previous match.
constexpr uint16_t master_file_id
Master file ID.
Definition apdu.hpp:170
bool is_response_OK(const uint16_t sw12)
Is response successfully?
Definition apdu.hpp:42
std::vector< uint8_t > make_apdu_case4(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *data, const uint16_t data_len, const uint16_t le)
Make APDU case4 command [CLA | INS | P1 | P2 | Lc | C-Data | Le].
Definition apdu.hpp:294
std::vector< uint8_t > make_apdu_case3(const uint8_t cla, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *data, const uint16_t data_len)
Make APDU case3 command [CLA | INS | P1 | P2 | Lc | C-Data].
Definition apdu.hpp:277
For APDU.
Top level namespace of M5Stack.
NFC related definitions.
NFC-V definitions.
File Control Parameters.
Definition file_system.hpp:26
TLV element.
Definition apdu.hpp:186
bool is_constructed() const
Is constructed TLV?
Definition apdu.hpp:196
bool is_primitive() const
Is primitive TLV?
Definition apdu.hpp:204
uint32_t len
L (length)
Definition apdu.hpp:188
uint8_t tag_len
Tag length.
Definition apdu.hpp:190
uint32_t tag
T (Tag)
Definition apdu.hpp:187