boltcard/docs/DETERMINISTIC.md
2023-10-20 23:14:22 +09:00

101 lines
No EOL
5.4 KiB
Markdown

## Abstract
The NXP NTAG424DNA allows applications to configure five application keys, named `K0`, `K1`, `K2`, `K3`, and `K4`. In the Bolt card configuration:
* `K0` is the `App Master Key`, it is the only key permitted to change the application keys.
* `K1` serves as the `encryption key` for the `PICCData`, represented by the `p=` parameter.
* `K2` is the `authentication key` used for calculating the SUN MAC of the `PICCData`, represented by the `c=` parameter.
* `K3` and `K4` are not used but should be configured as recommended in the [NTag424 application notes](https://www.nxp.com/docs/en/application-note/AN12196.pdf).
A simplistic approach to issuing Bolt cards would involve randomly generating the five different keys and storing them in a database.
When a validation request is made, the verifier would attempt to decrypt the `p=` parameter using all existing encryption keys until finding a match. Once decrypted, the `p=` parameter would reveal the card's uid, which can then be used to retrieve the remaining keys.
The primary drawback of this method is its lack of scalability. If many cards have been issued, identifying the correct encryption key could become computationally expensive.
In this document, we propose a solution to this issue.
## Key generation
Assuming the `LNUrl Withdraw Service` generates a random key named (the `IssuerKey`) and has a `batch` of Bolt Cards to configure, it will set the following parameters:
* `K0 = PRF(IssuerKey, '2d003f76' || batchId || UID)`
* `K1 = PRF(IssuerKey, '2d003f77' || batchId)`
* `K2 = PRF(IssuerKey, '2d003f78' || batchId || UID)`
* `K3 = PRF(IssuerKey, '2d003f79' || batchId || UID)`
* `K4 = PRF(IssuerKey, '2d003f7a' || batchId || UID)`
`batchId`: 4 bytes identifying the batch of card. (Can be set to `00000000` if uneeded)
The Pseudo Random Function `PRF(key, message)` applied during the key generation is the CMAC algorithm described in NIST Special Publication 800-38B.
## How the to implement a Reset feature
If a `LNUrl Withdraw Service` offers a factory reset feature for a user's bolt card, here is the recommended procedure:
1. Read the NDEF lnurlw URL, extract `p=` and `c=`.
2. For each existing `batchId`:
1. Derive `K1`, decrypts `p=` to get the `PICCData`.
2. If `PICCData[0] != 0xc7`, go to the next `batchId`.
3. Take `UID=PICCData[1..8]`, derive `K2`
4. Calculate the SUN MAC with `K2`, if different from `c=`, go to next `batchId`
3. From the `UID`, the `IssuerKey` and the `batchId` with correct SUN MAC, recover `K0`, `K3`, and `K4`.
5. Execute `AuthenticateEV2First` with `K0`
6. Erase the NDEF data file using `WriteData` or `ISOUpdateBinary`
7. Restore the NDEF file settings to default values with `ChangeFileSettings`.
8. Use `ChangeKey` with the recovered application keys to reset `K4` through `K0` to `00000000000000000000000000000000`.
Rational: Attempting to call `AuthenticateEV2First` without validating the `p=` and `c=` parameters could render the NTag inoperable after a few attempts.
## How to implement a verification
If a `LNUrl Withdraw Service` needs to verify a payment request, follow these steps:
1. Read the NDEF lnurlw URL, extract `p=` and `c=`.
2. For each existing `batchId`:
1. Derive `K1`, decrypts `p=` to get the `PICCData`.
2. If `PICCData[0] != 0xc7`, go to the next `batchId`.
3. Take `UID=PICCData[1..8]`, derive `K2`
4. Calculate the SUN MAC with `K2`, if different from `c=`, go to next `batchId`
3. If no correct SUN MAC has been found, returns an error.
3. Confirm that the last-seen counter for `ID=PRF(IssuerKey, '2d003f7b' || batchId || UID)[0..7]` is lower than what is stored in `counter=PICCData[8..11]`.
4. Update the last-seen counter.
The specific method for calculating `ID` is not crucial; the recommendation is to avoid using `UID` directly. This approach offers both privacy and security benefits.
Mainly, since the `UID` is used to derive keys, it is better to not store it outside the NTag.
## Security consideration
Since `K1` is shared among multiple Bolt Cards, the security of this scheme is based on the following assumptions:
* `K1` cannot be extracted from a legitimate NTag424.
* Bolt Card setup occurs in a trusted environment.
While NXP gives assurance keys can't be extracted, a non genuine NTag424 could potentially expose these keys.
Furthermore, because blank NTag424 uses the well-known initial application keys `00000000000000000000000000000000`, communication between the PCD and the PICC could be intercepted. If the Bolt Card setup doesn't occurs in a trusted environment, `K1` could be exposed during the calls to `ChangeKey`.
However, if `K1` is compromised, the attacker still cannot produce a valid checksum and can only recover the `UID` for tracking purposes.
Note that verifying the signature returned by `Read_Sig` can only prove NXP issued a card with a specific `UID`. It cannot prove that the current communication channel is established with an authentic NTag424. This is because the signature returned by `Read_Sig` covers only the `UID` and can therefore be replayed by a non-genuine NTag424.
## Test vectors
Input:
```
UID: 04a39493cc8680
Batch: 01000000
Issuer Key: 00000000000000000000000000000001
```
Expected:
```
K0: 60ef62b99ed8dc351ef7382b7d9e60f0
K1: aa104a0bef8f751add9f06c5f000837a
K2: 2ed57c172cf9b2ef8d8bfa6c9175d117
K3: b943783b3265f0c9091f716eab470b06
K4: 9fdd4ad2e7f2c0030eb84e695b257434
ID: 3cd713f36fc177
```