1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
// SPDX-FileCopyrightText: 2026 Jannik Schürg
//
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! A transport-agnostic crate for communicating with NTAG 424 DNA NFC tags.
//!
//! An opinionated use case is provided through the [`high_level`] module.
//! This provides a convenient abstraction for tag provisioning
//! and SDM verification, without needing to work with low-level commands directly.
//!
//! # High level hardware overview
//!
//! The NTAG 424 DNA is a NFC chip that can generate cryptographically signed or encrypted
//! identifiers on the fly, readable by standard NFC readers. This allows to
//! uniquely identify a tag while verifying its authenticity,
//! which is useful for anti-counterfeiting and authentication where it
//! is important to not just have a tag with a unique identifier,
//! but also to be able to verify that the tag is genuine and not a clone.
//! The cryptography is based on AES-128 operations and has preventions against
//! side-channel and replay attacks.
//!
//! The chip utilizes a file system with configurable access
//! permissions through keys stored on chip. It stores three files:
//!
//! 1. The NFC _Capability Container_ (CC) file, which describes the tag's capabilities. This file
//! is mostly static.
//! 2. A 256 byte long file containing data using the _NFC Data Exchange Format_ (NDEF).
//! This file can have dynamically computed data inserted by the tag and is
//! read by standard NFC readers.
//! 3. A 128 byte long file, called _proprietary file_, containing raw data free for
//! an application to use.
//!
//! Furthermore, the tag stores a set of five application defined AES-128 keys[^1],
//! numbered 0 to 4, with the key 0 being
//! the _Application Master Key_. The master key is needed to change any of the keys and to configure the tag.
//!
//! For each file one can configure read and write permissions, either using
//! a key or allowing free, unauthenticated access.
//!
//! **Default access permissions out of the factory**:
//!
//! | File | Read Only | Write Only | Read / Write | Change file settings |
//! |-------------|---------|------------|------------|------------|
//! | CC | _Unauthenticated_ | Master Key | Master Key | Master Key |
//! | NDEF | _Unauthenticated_ | _Unauthenticated_ | _Unauthenticated_ | Master Key |
//! | Proprietary | Key 2 | Key 3 | Key 3 | Master Key |
//!
//! **Default keys out of the factory**: all keys are set to constant zero.
//!
//! ## _Secure Unique NFC_ (SUN) using _Secure Dynamic Messaging_ (SDM)
//!
//! The NDEF file can define placeholders that are dynamically filled by the tag when read.
//! This is called _Secure Dynamic Messaging_ (SDM) and is configured through the [file settings](`crate::AuthenticatedSession::change_file_settings`)
//! of the NDEF file.
//! Typically the NDEF encodes a URL with placeholders for the tag's unique identifier,
//! and counter, usually encrypted and signed using one of the application keys,
//! as well as a [MAC](https://en.wikipedia.org/wiki/Message_authentication_code).
//!
//! This allows the tag to provide a _Secure Unique NFC_ (SUN) identifier that can be
//! used for cases where a identifier fulfilling cryptographic properties is needed,
//! e.g. for anti-counterfeiting, authentication, or access control.
//!
//! By default the NDEF file is readable without authentication through standard NFC Type 4 commands
//! allowing many NFC readers to read the SUN identifier without special support for the tag's cryptographic features.
//! However, the NDEF file can also be configured to require authentication through one of the AES keys for reading.
//!
//! ### Example: what a reader sees
//!
//! The snippet below builds an NDEF file from a URL template and shows the
//! bytes written to the tag. Requires the `sdm` and `alloc` features.
//!
//! ```
//! # #[cfg(all(feature = "sdm", feature = "alloc"))]
//! # fn main() {
//! use ntag424::types::file_settings::CryptoMode;
//!
//! let (ndef, _sdm) = ntag424::sdm_url_config!(
//! "https://example.com/?p={picc}&m={mac}",
//! CryptoMode::Aes,
//! );
//!
//! // The first 7 bytes are the NDEF Type 4 wrapper (2-byte NLEN + short record
//! // header for a URI payload with the "https://" prefix code 0x04). The URI
//! // body follows, with `{picc}` filled with 32 ASCII zeros (placeholder for
//! // 16 bytes of encrypted PICCData, ASCII-doubled) and `{mac}` with 16 ASCII
//! // zeros (placeholder for the 8-byte truncated CMAC).
//! assert_eq!(&ndef[..7], &[0x00, 0x47, 0xD1, 0x01, 0x43, 0x55, 0x04]);
//! assert_eq!(
//! &ndef[7..],
//! b"example.com/?p=00000000000000000000000000000000&m=0000000000000000",
//! );
//! # }
//! # #[cfg(not(all(feature = "sdm", feature = "alloc")))] fn main() {}
//! ```
//!
//! When a standard NFC reader performs an unauthenticated read, the tag
//! returns the same bytes but with the placeholders replaced by freshly
//! computed values[^sdm-crypto], e.g.:
//!
//! ```text
//! https://example.com/?p=EF963FF7828658A599F3041510671E88&m=94EED9EE65337086
//! ```
//! # Provisioning
//!
//! <div class="warning">
//!
//! _All_ keys should be replaced before deployment and
//! the NDEF file should be locked down with appropriate permissions.
//! Check the provisioning example in the repository.
//!
//! </div>
//!
//! The implementation of the tag's initial setup should be carefully designed to match the
//! application's needs. The following list contains steps that should be considered for a secure setup of the tag.
//!
//! - Generate and store strong random keys for all five application keys. You may use [key diversification](`key_diversification`)
//! to derive keys from a single master key if needed. Access to those keys should be carefully
//! controlled.
//! - Review the [tag configuration](`crate::types::Configuration`).
//! - If SUN identifiers are needed, prepare the NDEF file:
//! - Write the NDEF file with the desired template, e.g. a URL with placeholders. Maybe
//! the [`sdm_url_config!`] macro can be used.
//! - Enable SDM via the [file settings](`crate::AuthenticatedSession::change_file_settings`) for the NDEF file,
//! also configure the file permissions and cryptographic settings in this step.
//! - Prepare the proprietary file if needed, write an initial content, and configure the file's
//! permissions.
//!
//! For a complete, runnable provisioning tool using a real PC/SC transport,
//! see `examples/provision/` in the repository. `examples/verification/` is
//! a companion that reads the provisioned config and verifies SDM-signed tag
//! taps against it.
//!
//! # Binary size
//!
//! Recommendations if binary size is a concern:
//!
//! 1. **Skip originality verification.** The [`Session::verify_originality`](`crate::Session::verify_originality`)
//! function pulls in `p224` + `crypto-bigint` + `sha2` (~150 KB pre-link).
//! If you do not need to verify originality,
//! simply do not call this function and the linker has a chance to remove the related code.
//!
//! 2. **Enable LTO.** Add to your `.cargo/config.toml` or `Cargo.toml`:
//! ```toml
//! [profile.release]
//! lto = true
//! opt-level = "s" # or "z" for smallest
//! codegen-units = 1
//! ```
//! These settings are what make dead-code elimination effective across crate boundaries.
//!
//! 3. **Disable the `alloc` feature** if you have no heap. The feature only gates `Vec`-returning
//! wrappers; all core protocol logic and the `*_into` in-place variants remain available.
//!
//! # Sources
//!
//! The following sources were used to implement this crate. Section numbers
//! cited throughout the docstrings (e.g. "§5.16", "§8.2.3.2") are anchors
//! into these PDFs, so you can jump straight to the relevant passage.
//!
//! - [NTAG 424 DNA datasheet](https://www.nxp.com/docs/en/data-sheet/NT4H2421Gx.pdf)
//! - [AN12196](https://www.nxp.com/docs/en/application-note/AN12196.pdf)
//! - [AN12321](https://www.nxp.com/docs/en/application-note/AN12321.pdf)
//! - [AN10922](https://www.nxp.com/docs/en/application-note/AN10922.pdf)
//! - tests on real hardware tags
//!
//! Integration tests use a mock transport that simulates the tag's responses, and are based on the above sources,
//! using either test vectors or collected responses from real hardware tags. Unit tests use the
//! same sources.
//!
//! _No tags were harmed during development of this crate._
//!
//! [^1]: There are also the NDA protected _originality keys_ used for originality verification.
//! [^sdm-crypto]: The `p=` value contains the encrypted tag identity and `m=` is the truncated CMAC.
//! A server can decrypt and verify these values; see [`sdm::Verifier`].
extern crate alloc;
/// Create SDM configuration from a URL template string.
///
/// The NDEF is computed at compile time.
/// Invalid templates fail during compilation.
///
/// Its intended usage is for
/// provisioning data that will be written to a tag at runtime.
///
/// See [`sdm_url_config`](`crate::sdm::sdm_url_config`) function for details.
///
/// This panics at compile time in case of an error, whereas the function
/// variant returns a `Result`.
///
/// Two forms are supported:
///
/// ```rust
/// # use ntag424::types::file_settings::CryptoMode;
/// let (ndef, sdm) = ntag424::sdm_url_config!(
/// "https://example.com/?[[p={picc}&m={mac}",
/// CryptoMode::Aes,
/// );
/// # let _ = (ndef, sdm);
/// ```
///
/// ```rust
/// # use ntag424::types::file_settings::CryptoMode;
/// # use ntag424::sdm::SdmUrlOptions;
/// let (ndef, sdm) = ntag424::sdm_url_config!(
/// "https://example.com/?u={uid}&m={mac}",
/// CryptoMode::Aes,
/// SdmUrlOptions::new(),
/// );
/// # let _ = (ndef, sdm);
/// ```
};
}
pub use ;
pub use SessionSuite;
pub use ;
pub use ;