@ukeyfe/react-native-nfc-litecard 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,45 +1,47 @@
1
1
  # @ukeyfe/react-native-nfc-litecard
2
2
 
3
- [English](./README.en.md) | 中文
3
+ English | [中文](./README.zh.md)
4
4
 
5
- 基于 **MIFARE Ultralight AES** (MF0AES(H)20) React Native NFC 读写库,用于 LiteCard 助记词存储。
5
+ React Native NFC read/write library for **MIFARE Ultralight AES** (MF0AES(H)20), designed for LiteCard mnemonic storage.
6
6
 
7
- > **设计原则**:库只返回状态码 (`code`) 和数据 (`data`),**不提供用户提示文案**。调用方根据 `ResultCode` 自行处理本地化提示。
7
+ > **Design principle**: The library only returns status codes (`code`) and data (`data`). It does **not** provide user-facing messages. The caller should map `NfcStatusCode` to their own localised strings.
8
8
 
9
- ## 功能概览
9
+ ## Features
10
10
 
11
- | 功能 | 方法 | 说明 |
12
- |------|------|------|
13
- | 检测卡片 | `checkCard()` | 判断卡片是空卡还是已有数据 |
14
- | 读取助记词 | `readMnemonic()` | 密码认证后读取 BIP-39 助记词 |
15
- | 读取昵称 | `readUserNickname()` | 读取卡片上的用户昵称 |
16
- | 读取重试次数 | `readMnemonicRetryCount()` | 读取 PIN 重试计数器 |
17
- | 重置重试次数 | `resetRetryCountTo10()` | 重置 PIN 重试计数器为默认值 10 |
18
- | 初始化卡片 | `initializeCard()` | 向空卡写入助记词并设置密码保护 |
19
- | 更新卡片 | `updateCard()` | 更新助记词和密码(需要旧密码) |
20
- | 修改密码 | `updatePassword()` | 仅修改密码(需要旧密码) |
21
- | 写入昵称 | `writeUserNickname()` | 写入用户昵称到卡片 |
22
- | 重置卡片 | `resetCard()` | 清空数据,密码重置为 "000000" |
11
+ | Feature | Method | Description |
12
+ |---------|--------|-------------|
13
+ | Check card | `checkCard()` | Detect whether the card is empty or contains data |
14
+ | Read mnemonic | `readMnemonic()` | Read BIP-39 mnemonic (password required) |
15
+ | Read nickname | `readUserNickname()` | Read user nickname from card |
16
+ | Read retry count | `readMnemonicRetryCount()` | Read PIN retry counter |
17
+ | Reset retry count | `resetRetryCountTo10()` | Reset PIN retry counter to default (10) |
18
+ | Initialize card | `initializeCard()` | Authenticate with default password, write mnemonic + set new password |
19
+ | Update card | `updateCard()` | Update mnemonic & password (old password required) |
20
+ | Change password | `updatePassword()` | Change password only (old password required) |
21
+ | Write nickname | `writeUserNickname()` | Write user nickname to card |
22
+ | Reset card | `resetCard()` | Wipe mnemonic data, set a new password, keep protection enabled |
23
+ | Card version | `getCardVersion()` | Read card product version info (no auth required) |
24
+ | Originality check | `readOriginality()` | Read ECC originality signature for NXP authenticity verification |
23
25
 
24
- ## 安装
26
+ ## Installation
25
27
 
26
28
  ```bash
27
29
  npm install @ukeyfe/react-native-nfc-litecard
28
30
  ```
29
31
 
30
- ### 前置依赖
32
+ ### Peer Dependencies
31
33
 
32
- 本库需要以下 peer dependencies,请确保项目中已安装:
34
+ This library requires the following peer dependencies:
33
35
 
34
36
  ```bash
35
37
  npm install react-native react-native-nfc-manager
36
38
  ```
37
39
 
38
- ## 快速上手
40
+ ## Quick Start
39
41
 
40
42
  ```typescript
41
43
  import {
42
- ResultCode,
44
+ NfcStatusCode,
43
45
  checkCard,
44
46
  readMnemonic,
45
47
  initializeCard,
@@ -50,259 +52,293 @@ import {
50
52
  resetCard,
51
53
  readMnemonicRetryCount,
52
54
  resetRetryCountTo10,
55
+ getCardVersion,
56
+ readOriginality,
53
57
  } from '@ukeyfe/react-native-nfc-litecard';
54
58
  ```
55
59
 
56
- ## API 文档
60
+ ## API Reference
57
61
 
58
62
  ### `checkCard(password?, onCardIdentified?)`
59
63
 
60
- 检测卡片状态(空卡 / 有数据)。
64
+ Detect card status (empty / has data).
61
65
 
62
- **不传密码(快速探测):**
66
+ **Without password (quick probe):**
63
67
  ```typescript
64
68
  const result = await checkCard();
65
- if (result.code === ResultCode.CHECK_EMPTY) {
66
- // 空卡,可以初始化
67
- } else if (result.code === ResultCode.CHECK_HAS_DATA) {
68
- // 有数据(或卡开了读保护无法确定)
69
+ if (result.code === NfcStatusCode.CHECK_EMPTY) {
70
+ // Empty card – ready to initialize
71
+ } else if (result.code === NfcStatusCode.CHECK_HAS_DATA) {
72
+ // Has data (or read-protected, cannot determine)
69
73
  }
70
74
  ```
71
75
 
72
- **传密码(认证后深度检查,适用于开了读保护的卡):**
76
+ **With password (authenticated deep check, for read-protected cards):**
73
77
  ```typescript
74
78
  const result = await checkCard('password');
75
- if (result.code === ResultCode.CHECK_EMPTY) {
76
- // 空卡,可以写入
77
- } else if (result.code === ResultCode.CHECK_HAS_DATA) {
78
- // 有合法助记词备份,类型: result.data?.type
79
- } else if (result.code === ResultCode.AUTH_WRONG_PASSWORD) {
80
- // 密码错误
79
+ if (result.code === NfcStatusCode.CHECK_EMPTY) {
80
+ // Empty card – ready to write
81
+ } else if (result.code === NfcStatusCode.CHECK_HAS_DATA) {
82
+ // Valid mnemonic backup exists, type: result.data?.type
83
+ } else if (result.code === NfcStatusCode.AUTH_WRONG_PASSWORD) {
84
+ // Wrong password
81
85
  }
82
86
  ```
83
87
 
84
- **参数:**
85
- | 参数 | 类型 | 必填 | 说明 |
86
- |------|------|------|------|
87
- | `password` | `string` | | 卡片保护密码。不传时直接尝试读取(适合未加密的卡);传入后先用密码进行 AES 认证再读取完整数据并校验 CRC16(适合开了读保护的卡,结果更准确) |
88
- | `onCardIdentified` | `() => void` | | NFC 连接建立后的回调,可用于 UI 提示"已识别到卡片" |
88
+ **Parameters:**
89
+ | Parameter | Type | Required | Description |
90
+ |-----------|------|----------|-------------|
91
+ | `password` | `string` | No | Card protection password. If omitted, the library reads directly (suited for unencrypted cards). If provided, AES authentication runs first, then full data is read and CRC16 is verified (suited for read-protected cards; more accurate). |
92
+ | `onCardIdentified` | `() => void` | No | Called after the NFC session is established; use for UI such as "card detected". |
89
93
 
90
- **返回值 (`NfcResult`):**
91
- | code | 含义 |
92
- |------|------|
93
- | `ResultCode.CHECK_EMPTY` (10104) | 空卡,没有助记词数据 |
94
- | `ResultCode.CHECK_HAS_DATA` (10105) | 卡上有数据。传密码时 `data.type` 包含助记词类型(如 "12 words (128-bit)" |
95
- | `ResultCode.AUTH_WRONG_PASSWORD` (40002) | 密码错误(仅传密码时可能返回) |
96
- | `ResultCode.NFC_CONNECT_FAILED` (40001) | NFC 连接失败,卡片未贴近或设备不支持 |
94
+ **Result codes:**
95
+ | Code | Meaning |
96
+ |------|---------|
97
+ | `NfcStatusCode.CHECK_EMPTY` (10104) | Empty card – no mnemonic data |
98
+ | `NfcStatusCode.CHECK_HAS_DATA` (10105) | Card has data. When a password is supplied, `data.type` contains the mnemonic type (e.g. `"12 words (128-bit)"`). |
99
+ | `NfcStatusCode.AUTH_WRONG_PASSWORD` (40002) | Wrong password (only possible when a password is provided) |
100
+ | `NfcStatusCode.NFC_CONNECT_FAILED` (40001) | NFC connection failed – card not tapped or device unsupported |
97
101
 
98
102
  ---
99
103
 
100
104
  ### `readMnemonic(password, onCardIdentified?)`
101
105
 
102
- 读取助记词(需要密码认证)。认证前会自动递减重试计数器,认证成功后重置为 10
106
+ Read the mnemonic (password authentication required). The retry counter is decremented before authentication and reset to 10 after a successful authentication.
103
107
 
104
108
  ```typescript
105
109
  const result = await readMnemonic('your-password');
106
110
  if (result.success) {
107
- console.log('助记词:', result.data?.mnemonic);
108
- console.log('类型:', result.data?.type); // "12 words (128-bit)"
109
- console.log('昵称:', result.data?.nickname);
110
- console.log('剩余重试:', result.data?.retryCount);
111
+ console.log('Mnemonic:', result.data?.mnemonic);
112
+ console.log('Type:', result.data?.type); // "12 words (128-bit)"
113
+ console.log('Nickname:', result.data?.nickname);
114
+ console.log('Retry count:', result.data?.retryCount);
111
115
  }
112
116
  ```
113
117
 
114
- **参数:**
115
- | 参数 | 类型 | 必填 | 说明 |
116
- |------|------|------|------|
117
- | `password` | `string` | | 卡片保护密码,用于 AES-128 认证 |
118
- | `onCardIdentified` | `() => void` | | 认证成功后、开始读取数据前的回调,可用于 UI 提示"正在读取" |
119
-
120
- **返回 `data` 字段:**
121
- | 字段 | 类型 | 说明 |
122
- |------|------|------|
123
- | `mnemonic` | `string` | BIP-39 助记词(如 "abandon abandon ... about" |
124
- | `type` | `string` | 助记词类型(如 "12 words (128-bit)""24 words (256-bit)" |
125
- | `entropyHex` | `string` | 熵数据的十六进制字符串 |
126
- | `rawBytes` | `string` | 卡上原始数据(类型+熵)的十六进制字符串 |
127
- | `nickname` | `string` | 用户昵称(如果卡上有设置) |
128
- | `retryCount` | `number` | 认证成功后重置的重试次数(正常为 10 |
118
+ **Parameters:**
119
+ | Parameter | Type | Required | Description |
120
+ |-----------|------|----------|-------------|
121
+ | `password` | `string` | Yes | Card protection password for AES-128 authentication |
122
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication and before reading data; use for UI such as "reading". |
123
+
124
+ **Returned `data` fields:**
125
+ | Field | Type | Description |
126
+ |-------|------|-------------|
127
+ | `mnemonic` | `string` | BIP-39 mnemonic (e.g. `"abandon abandon ... about"`) |
128
+ | `type` | `string` | Mnemonic type (e.g. `"12 words (128-bit)"`, `"24 words (256-bit)"`) |
129
+ | `entropyHex` | `string` | Entropy as a hexadecimal string |
130
+ | `rawBytes` | `string` | Hex string of raw on-card data (type + entropy) |
131
+ | `nickname` | `string` | User nickname if set on the card |
132
+ | `retryCount` | `number` | Retry count after successful authentication (normally 10) |
129
133
 
130
134
  ---
131
135
 
132
- ### `initializeCard(mnemonic, password, onCardIdentified?)`
136
+ ### `initializeCard(mnemonic, newPassword, defaultPassword, onCardIdentified?)`
133
137
 
134
- 初始化空卡:将助记词转为 BIP-39 熵写入卡片,设置 AES 密码保护,开启读写认证。
138
+ Initialize a card: authenticate with the factory-default password, write the mnemonic, and set a new password. The card must already have AES protection enabled (factory default).
135
139
 
136
140
  ```typescript
137
141
  const result = await initializeCard(
138
142
  'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
139
- 'your-password'
143
+ 'your-password',
144
+ '000000' // factory default password
140
145
  );
141
- if (result.code === ResultCode.INIT_SUCCESS) {
142
- console.log('初始化成功');
146
+ if (result.code === NfcStatusCode.INIT_SUCCESS) {
147
+ console.log('Initialization successful');
143
148
  }
144
149
  ```
145
150
 
146
- **参数:**
147
- | 参数 | 类型 | 必填 | 说明 |
148
- |------|------|------|------|
149
- | `mnemonic` | `string` | | BIP-39 助记词,支持 12/15/18/21/24 词。库会自动转为熵 + CRC16 写入卡片 |
150
- | `password` | `string` | | 要设置的保护密码,用于生成 AES-128 密钥并写入卡片 |
151
- | `onCardIdentified` | `() => void` | | NFC 连接建立后、开始写入前的回调,可用于 UI 提示"正在写入" |
151
+ **Parameters:**
152
+ | Parameter | Type | Required | Description |
153
+ |-----------|------|----------|-------------|
154
+ | `mnemonic` | `string` | Yes | BIP-39 mnemonic; supports 12/15/18/21/24 words. The library converts to entropy + CRC16 and writes to the card. |
155
+ | `newPassword` | `string` | Yes | New protection password; used to derive the AES-128 key written to the card. |
156
+ | `defaultPassword` | `string` | Yes | Current (factory-default) password on the card for authentication. |
157
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication and before writing begins; use for UI such as "writing". |
152
158
 
153
159
  ---
154
160
 
155
161
  ### `updateCard(oldPassword, newPassword, newMnemonic, onCardIdentified?, options?)`
156
162
 
157
- 更新卡片:用旧密码认证后,写入新助记词和新密码。认证前自动递减重试计数器。
163
+ Update the card: authenticate with the old password, then write the new mnemonic and new password. The retry counter is decremented automatically before authentication.
158
164
 
159
165
  ```typescript
160
166
  const result = await updateCard('old-password', 'new-password', 'new mnemonic words ...');
161
- if (result.code === ResultCode.WRITE_SUCCESS) {
162
- console.log('更新成功');
167
+ if (result.code === NfcStatusCode.WRITE_SUCCESS) {
168
+ console.log('Update successful');
163
169
  }
164
170
  ```
165
171
 
166
- **写入前检查是否已有备份:**
172
+ **Pre-check for existing backup:**
167
173
 
168
174
  ```typescript
169
175
  const result = await updateCard('old-password', 'new-password', 'mnemonic ...', undefined, {
170
176
  precheckExistingMnemonic: true,
171
177
  });
172
- if (result.code === ResultCode.PRECHECK_HAS_BACKUP) {
173
- console.log('卡上已有备份,未写入。类型:', result.data?.type);
174
- } else if (result.code === ResultCode.WRITE_SUCCESS) {
175
- console.log('写入成功');
178
+ if (result.code === NfcStatusCode.PRECHECK_HAS_BACKUP) {
179
+ // Card already has a valid mnemonic backup; write was skipped
180
+ console.log('Backup exists, type:', result.data?.type);
181
+ } else if (result.code === NfcStatusCode.WRITE_SUCCESS) {
182
+ console.log('Write successful');
176
183
  }
177
184
  ```
178
185
 
179
- **参数:**
180
- | 参数 | 类型 | 必填 | 说明 |
181
- |------|------|------|------|
182
- | `oldPassword` | `string` | | 当前卡片密码,用于 AES 认证 |
183
- | `newPassword` | `string` | | 新密码,写入后卡片将使用此密码保护 |
184
- | `newMnemonic` | `string` | | 新的 BIP-39 助记词(12/15/18/21/24 词) |
185
- | `onCardIdentified` | `() => void` | | 认证成功后的回调,可用于 UI 提示"正在写入" |
186
- | `options.precheckExistingMnemonic` | `boolean` | | 设为 `true` 时,认证后先读取卡片数据并校验 CRC16。如果已有合法助记词,返回 `PRECHECK_HAS_BACKUP` 不执行写入 |
186
+ **Parameters:**
187
+ | Parameter | Type | Required | Description |
188
+ |-----------|------|----------|-------------|
189
+ | `oldPassword` | `string` | Yes | Current card password for AES authentication |
190
+ | `newPassword` | `string` | Yes | New password; the card will be protected with this password after the write |
191
+ | `newMnemonic` | `string` | Yes | New BIP-39 mnemonic (12/15/18/21/24 words) |
192
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication; use for UI such as "writing". |
193
+ | `options.precheckExistingMnemonic` | `boolean` | No | When `true`, after authentication the library reads card data and verifies CRC16. If a valid mnemonic already exists, returns `PRECHECK_HAS_BACKUP` and does not write. |
187
194
 
188
195
  ---
189
196
 
190
197
  ### `updatePassword(oldPassword, newPassword, onCardIdentified?)`
191
198
 
192
- 仅修改密码,不更改卡上的助记词数据。认证前自动递减重试计数器。
199
+ Change the password only; mnemonic data on the card is unchanged. The retry counter is decremented automatically before authentication.
193
200
 
194
201
  ```typescript
195
202
  const result = await updatePassword('old-password', 'new-password');
196
- if (result.code === ResultCode.UPDATE_PASSWORD_SUCCESS) {
197
- console.log('密码修改成功');
203
+ if (result.code === NfcStatusCode.UPDATE_PASSWORD_SUCCESS) {
204
+ console.log('Password updated');
198
205
  }
199
206
  ```
200
207
 
201
- **参数:**
202
- | 参数 | 类型 | 必填 | 说明 |
203
- |------|------|------|------|
204
- | `oldPassword` | `string` | | 当前卡片密码,用于 AES 认证 |
205
- | `newPassword` | `string` | | 新密码,修改后卡片将使用此密码保护 |
206
- | `onCardIdentified` | `() => void` | | 认证成功后的回调 |
208
+ **Parameters:**
209
+ | Parameter | Type | Required | Description |
210
+ |-----------|------|----------|-------------|
211
+ | `oldPassword` | `string` | Yes | Current card password for AES authentication |
212
+ | `newPassword` | `string` | Yes | New password; the card will use this password after the change |
213
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication |
207
214
 
208
215
  ---
209
216
 
210
217
  ### `writeUserNickname(password, nickname, onCardIdentified?)`
211
218
 
212
- 写入用户昵称到卡片。昵称使用 UTF-8 编码,最长 12 字节(超出自动截断)。
219
+ Write a user nickname to the card. The nickname is UTF-8 encoded, max 12 bytes (longer input is truncated).
213
220
 
214
221
  ```typescript
215
222
  const result = await writeUserNickname('your-password', 'MyCard');
216
- if (result.code === ResultCode.WRITE_NICKNAME_SUCCESS) {
217
- console.log('昵称写入成功');
223
+ if (result.code === NfcStatusCode.WRITE_NICKNAME_SUCCESS) {
224
+ console.log('Nickname written');
218
225
  }
219
226
  ```
220
227
 
221
- **参数:**
222
- | 参数 | 类型 | 必填 | 说明 |
223
- |------|------|------|------|
224
- | `password` | `string` | | 卡片保护密码,用于 AES 认证 |
225
- | `nickname` | `string` | | 用户昵称,UTF-8 编码最长 12 字节。中文约 4 个字,英文 12 个字符 |
226
- | `onCardIdentified` | `() => void` | | 认证成功后的回调 |
228
+ **Parameters:**
229
+ | Parameter | Type | Required | Description |
230
+ |-----------|------|----------|-------------|
231
+ | `password` | `string` | Yes | Card protection password for AES authentication |
232
+ | `nickname` | `string` | Yes | User nickname; UTF-8 max 12 bytes (roughly 4 CJK characters or 12 Latin letters) |
233
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication |
227
234
 
228
235
  ---
229
236
 
230
237
  ### `readUserNickname(password?, onCardIdentified?)`
231
238
 
232
- 读取卡片上的用户昵称。
239
+ Read the user nickname from the card.
233
240
 
234
241
  ```typescript
235
242
  const result = await readUserNickname('your-password');
236
243
  if (result.success) {
237
- console.log('昵称:', result.data?.nickname);
244
+ console.log('Nickname:', result.data?.nickname);
238
245
  }
239
246
  ```
240
247
 
241
- **参数:**
242
- | 参数 | 类型 | 必填 | 说明 |
243
- |------|------|------|------|
244
- | `password` | `string` | | 卡片密码。如果卡开了读保护(PROT=1)则必须传入,否则可省略 |
245
- | `onCardIdentified` | `() => void` | | 认证成功后的回调 |
248
+ **Parameters:**
249
+ | Parameter | Type | Required | Description |
250
+ |-----------|------|----------|-------------|
251
+ | `password` | `string` | No | Card password. Required if read protection is enabled (`PROT=1`); otherwise optional. |
252
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication |
246
253
 
247
254
  ---
248
255
 
249
- ### `resetCard(password?, onCardIdentified?)`
256
+ ### `resetCard(password, newPassword, onCardIdentified?)`
250
257
 
251
- 重置卡片:清空所有用户数据(助记词、昵称),密码重置为 `"000000"`,关闭读写保护。
258
+ Reset the card: wipe mnemonic data, set a new password, and disable read/write protection. Nickname is preserved.
252
259
 
253
260
  ```typescript
254
- const result = await resetCard('your-password');
255
- if (result.code === ResultCode.RESET_SUCCESS) {
256
- console.log('重置成功');
261
+ const result = await resetCard('old-password', 'new-password');
262
+ if (result.code === NfcStatusCode.RESET_SUCCESS) {
263
+ console.log('Reset successful');
257
264
  }
258
265
  ```
259
266
 
260
- > ⚠️ 重置操作不可逆,卡上的助记词数据将被永久清除。
267
+ > ⚠️ This operation is irreversible; mnemonic data on the card is permanently erased.
261
268
 
262
- **参数:**
263
- | 参数 | 类型 | 必填 | 说明 |
264
- |------|------|------|------|
265
- | `password` | `string` | | 当前卡片密码。如果卡开了保护则必须传入,否则可省略。认证前自动递减重试计数器 |
266
- | `onCardIdentified` | `() => void` | | 认证成功后的回调 |
269
+ **Parameters:**
270
+ | Parameter | Type | Required | Description |
271
+ |-----------|------|----------|-------------|
272
+ | `password` | `string \| undefined` | No | Current card password. Required if the card is protected; pass `undefined` otherwise. The retry counter is decremented automatically before authentication. |
273
+ | `newPassword` | `string` | Yes | Password to set after reset. |
274
+ | `onCardIdentified` | `() => void` | No | Called after successful authentication |
267
275
 
268
276
  ---
269
277
 
270
278
  ### `readMnemonicRetryCount(onCardIdentified?)`
271
279
 
272
- 读取卡片上的 PIN 重试计数器值。不需要密码认证(计数器页不在保护区域内)。
280
+ Read the PIN retry counter on the card. No password authentication is required (the counter page is outside the protected area).
273
281
 
274
282
  ```typescript
275
283
  const result = await readMnemonicRetryCount();
276
284
  if (result.success) {
277
- console.log('剩余重试次数:', result.data?.retryCount);
285
+ console.log('Remaining retries:', result.data?.retryCount);
278
286
  }
279
287
  ```
280
288
 
281
- **参数:**
282
- | 参数 | 类型 | 必填 | 说明 |
283
- |------|------|------|------|
284
- | `onCardIdentified` | `() => void` | | NFC 连接建立后的回调 |
289
+ **Parameters:**
290
+ | Parameter | Type | Required | Description |
291
+ |-----------|------|----------|-------------|
292
+ | `onCardIdentified` | `() => void` | No | Called after the NFC session is established |
285
293
 
286
294
  ---
287
295
 
288
296
  ### `resetRetryCountTo10(onCardIdentified?)`
289
297
 
290
- PIN 重试计数器重置为默认值 10。不需要密码认证。
298
+ Reset the PIN retry counter to its default value (10). No password authentication is required.
291
299
 
292
300
  ```typescript
293
301
  const result = await resetRetryCountTo10();
294
302
  ```
295
303
 
296
- **参数:**
297
- | 参数 | 类型 | 必填 | 说明 |
298
- |------|------|------|------|
299
- | `onCardIdentified` | `() => void` | | NFC 连接建立后的回调 |
304
+ **Parameters:**
305
+ | Parameter | Type | Required | Description |
306
+ |-----------|------|----------|-------------|
307
+ | `onCardIdentified` | `() => void` | No | Called after the NFC session is established |
300
308
 
301
309
  ---
302
310
 
303
- ### NFC 锁管理
311
+ ### `getCardVersion(onCardIdentified?)`
304
312
 
305
- 用于 App 页面生命周期中的 NFC 会话管理:
313
+ Read card product version info. No authentication required.
314
+
315
+ ```typescript
316
+ const result = await getCardVersion();
317
+ if (result.success) {
318
+ console.log('Vendor:', result.data?.version?.vendorId); // 0x04 = NXP
319
+ console.log('Type:', result.data?.version?.productType); // 0x03 = Ultralight
320
+ console.log('Version:', result.data?.version?.majorVersion); // 0x04 = AES
321
+ }
322
+ ```
323
+
324
+ ---
325
+
326
+ ### `readOriginality(onCardIdentified?)`
327
+
328
+ Read the ECC originality signature to verify the card is a genuine NXP product. No authentication required.
329
+
330
+ ```typescript
331
+ const result = await readOriginality();
332
+ if (result.success) {
333
+ console.log('Signature:', result.data?.signature); // 96-char hex string
334
+ }
335
+ ```
336
+
337
+ ---
338
+
339
+ ### NFC Lock Management
340
+
341
+ For app-level NFC session lifecycle management:
306
342
 
307
343
  ```typescript
308
344
  import {
@@ -313,22 +349,22 @@ import {
313
349
  } from '@ukeyfe/react-native-nfc-litecard';
314
350
  ```
315
351
 
316
- | 方法 | 说明 |
317
- |------|------|
318
- | `isNfcOperationLocked()` | 检查 NFC 操作锁是否被持有 |
319
- | `releaseNfcOperationLock()` | 强制释放锁(页面关闭时使用) |
320
- | `markNfcOperationCancelledByCleanup()` | 标记当前操作被页面清理中断 |
321
- | `consumeNfcOperationCancelledByCleanup()` | 消费清理标记(返回是否被中断) |
352
+ | Method | Description |
353
+ |--------|-------------|
354
+ | `isNfcOperationLocked()` | Check if the NFC operation lock is held |
355
+ | `releaseNfcOperationLock()` | Force-release the lock (use on page unmount) |
356
+ | `markNfcOperationCancelledByCleanup()` | Mark current operation as interrupted by cleanup |
357
+ | `consumeNfcOperationCancelledByCleanup()` | Consume the cleanup flag (returns whether it was set) |
322
358
 
323
- ## NfcResult 返回结构
359
+ ## NfcResult Structure
324
360
 
325
- 所有 API 统一返回 `NfcResult`:
361
+ All APIs return a unified `NfcResult`:
326
362
 
327
363
  ```typescript
328
364
  interface NfcResult {
329
- code: number; // 状态码,与 ResultCode 常量比较
330
- success: boolean; // 操作是否成功
331
- data?: { // 可选数据,仅部分操作返回
365
+ code: number; // Status code – compare against NfcStatusCode
366
+ success: boolean; // Whether the operation succeeded
367
+ data?: { // Optional data, only present for some operations
332
368
  mnemonic?: string;
333
369
  type?: string;
334
370
  entropyHex?: string;
@@ -341,119 +377,122 @@ interface NfcResult {
341
377
  }
342
378
  ```
343
379
 
344
- ## 错误处理示例
380
+ ## Error Handling Example
345
381
 
346
382
  ```typescript
347
- import { ResultCode, readMnemonic } from '@ukeyfe/react-native-nfc-litecard';
383
+ import { NfcStatusCode, readMnemonic } from '@ukeyfe/react-native-nfc-litecard';
348
384
 
349
385
  const result = await readMnemonic('password');
350
386
 
351
387
  switch (result.code) {
352
- case ResultCode.READ_SUCCESS:
353
- console.log('读取成功:', result.data?.mnemonic);
388
+ case NfcStatusCode.READ_SUCCESS:
389
+ console.log('Read successful:', result.data?.mnemonic);
354
390
  break;
355
- case ResultCode.AUTH_WRONG_PASSWORD:
356
- alert('密码错误');
391
+ case NfcStatusCode.AUTH_WRONG_PASSWORD:
392
+ alert('Wrong password');
357
393
  break;
358
- case ResultCode.NFC_CONNECT_FAILED:
359
- alert('NFC 连接失败,请重新贴卡');
394
+ case NfcStatusCode.NFC_CONNECT_FAILED:
395
+ alert('NFC connection failed, please re-tap the card');
360
396
  break;
361
- case ResultCode.NFC_USER_CANCELED:
362
- // iOS 用户取消,静默处理
397
+ case NfcStatusCode.NFC_USER_CANCELED:
398
+ // iOS user cancelled – handle silently
363
399
  break;
364
- case ResultCode.READ_TIMEOUT:
365
- alert('读取超时,请将卡片移开后重新贴近');
400
+ case NfcStatusCode.READ_TIMEOUT:
401
+ alert('Read timeout – remove and re-tap the card');
366
402
  break;
367
- case ResultCode.RETRY_COUNT_EXHAUSTED:
368
- alert('重试次数已用完,卡片已锁定');
403
+ case NfcStatusCode.RETRY_COUNT_EXHAUSTED:
404
+ alert('Retry count exhausted – card is locked');
369
405
  break;
370
406
  default:
371
- alert('操作失败');
407
+ alert('Operation failed');
372
408
  }
373
409
  ```
374
410
 
375
- ## 返回码一览
376
-
377
- ### 成功码
378
-
379
- | 常量 | | 说明 |
380
- |------|------|------|
381
- | `READ_SUCCESS` | 10102 | 读取助记词成功 |
382
- | `READ_NICKNAME_SUCCESS` | 10103 | 读取昵称成功 |
383
- | `CHECK_EMPTY` | 10104 | 空卡 |
384
- | `CHECK_HAS_DATA` | 10105 | 卡片有数据 |
385
- | `READ_RETRY_COUNT_SUCCESS` | 10106 | 读取重试次数成功 |
386
- | `INIT_SUCCESS` | 10201 | 初始化成功 |
387
- | `WRITE_SUCCESS` | 10203 | 写入/更新成功 |
388
- | `UPDATE_PASSWORD_SUCCESS` | 10204 | 修改密码成功 |
389
- | `WRITE_NICKNAME_SUCCESS` | 10205 | 写入昵称成功 |
390
- | `RESET_SUCCESS` | 10206 | 重置卡片成功 |
391
- | `PRECHECK_HAS_BACKUP` | 10207 | 卡上已有合法备份,写入被跳过 |
392
-
393
- ### 错误码
394
-
395
- | 常量 | 值 | 说明 |
396
- |------|------|------|
397
- | `NFC_CONNECT_FAILED` | 40001 | NFC 连接失败 |
398
- | `AUTH_WRONG_PASSWORD` | 40002 | 密码错误 |
399
- | `AUTH_INVALID_RESPONSE` | 40003 | 认证响应无效 |
400
- | `AUTH_VERIFY_FAILED` | 40004 | 认证验证失败 |
401
- | `READ_FAILED` | 40005 | 读取失败 |
402
- | `WRITE_FAILED` | 40006 | 写入失败 |
403
- | `INVALID_MNEMONIC` | 40007 | 无效的助记词 |
404
- | `UNSUPPORTED_MNEMONIC_LENGTH` | 40008 | 不支持的助记词长度 |
405
- | `INVALID_CARD_DATA` | 40009 | 卡片数据无效 |
406
- | `UNKNOWN_ERROR` | 40010 | 未知错误 |
407
- | `NFC_USER_CANCELED` | 40011 | 用户取消 NFC 扫描 (iOS) |
408
- | `READ_TIMEOUT` | 40012 | 读取超时 |
409
- | `NFC_LOCK_TIMEOUT` | 40013 | NFC 锁超时 |
410
- | `CRC16_CHECK_FAILED` | 40014 | CRC16 校验失败 |
411
- | `RETRY_COUNT_EXHAUSTED` | 40015 | PIN 重试次数已用完,卡片锁定 |
412
-
413
- ## 存储格式
414
-
415
- 卡片使用 BIP-39 熵压缩存储助记词:
411
+ ## Result Codes
412
+
413
+ ### Success Codes
414
+
415
+ | Constant | Value | Description |
416
+ |----------|-------|-------------|
417
+ | `READ_SUCCESS` | 10102 | Mnemonic read successful |
418
+ | `READ_NICKNAME_SUCCESS` | 10103 | Nickname read successful |
419
+ | `CHECK_EMPTY` | 10104 | Empty card |
420
+ | `CHECK_HAS_DATA` | 10105 | Card has data |
421
+ | `READ_RETRY_COUNT_SUCCESS` | 10106 | Retry count read successful |
422
+ | `GET_VERSION_SUCCESS` | 10107 | Card version read successful |
423
+ | `READ_SIG_SUCCESS` | 10108 | Originality signature read successful |
424
+ | `INIT_SUCCESS` | 10201 | Initialization successful |
425
+ | `WRITE_SUCCESS` | 10203 | Write/update successful |
426
+ | `UPDATE_PASSWORD_SUCCESS` | 10204 | Password change successful |
427
+ | `WRITE_NICKNAME_SUCCESS` | 10205 | Nickname written |
428
+ | `RESET_SUCCESS` | 10206 | Card reset successful |
429
+ | `PRECHECK_HAS_BACKUP` | 10207 | Card already has a valid backup; write was skipped |
430
+
431
+ ### Error Codes
432
+
433
+ | Constant | Value | Description |
434
+ |----------|-------|-------------|
435
+ | `NFC_CONNECT_FAILED` | 40001 | NFC connection failed |
436
+ | `AUTH_WRONG_PASSWORD` | 40002 | Wrong password |
437
+ | `AUTH_INVALID_RESPONSE` | 40003 | Invalid authentication response |
438
+ | `AUTH_VERIFY_FAILED` | 40004 | Authentication verification failed |
439
+ | `READ_FAILED` | 40005 | Read failed |
440
+ | `WRITE_FAILED` | 40006 | Write failed |
441
+ | `INVALID_MNEMONIC` | 40007 | Invalid mnemonic |
442
+ | `UNSUPPORTED_MNEMONIC_LENGTH` | 40008 | Unsupported mnemonic length |
443
+ | `INVALID_CARD_DATA` | 40009 | Invalid card data |
444
+ | `UNKNOWN_ERROR` | 40010 | Unknown error |
445
+ | `NFC_USER_CANCELED` | 40011 | User cancelled NFC scan (iOS) |
446
+ | `READ_TIMEOUT` | 40012 | Read timeout |
447
+ | `NFC_LOCK_TIMEOUT` | 40013 | NFC lock timeout |
448
+ | `CRC16_CHECK_FAILED` | 40014 | CRC16 check failed |
449
+ | `RETRY_COUNT_EXHAUSTED` | 40015 | PIN retry count exhausted, card locked |
450
+
451
+ ## Storage Format
452
+
453
+ The card stores BIP-39 mnemonics using entropy compression:
416
454
 
417
455
  ```
418
- [类型 1字节] [熵数据 16-32字节] [CRC16 2字节]
456
+ [type 1B] [entropy 16-32B] [CRC16 2B]
419
457
  ```
420
458
 
421
- | 类型值 | 助记词长度 | 熵长度 |
422
- |--------|-----------|--------|
423
- | 0x01 | 12 | 16 字节 (128-bit) |
424
- | 0x02 | 15 | 20 字节 (160-bit) |
425
- | 0x03 | 18 | 24 字节 (192-bit) |
426
- | 0x04 | 21 | 28 字节 (224-bit) |
427
- | 0x05 | 24 | 32 字节 (256-bit) |
459
+ | Type | Mnemonic Length | Entropy Size |
460
+ |------|----------------|--------------|
461
+ | 0x01 | 12 words | 16 bytes (128-bit) |
462
+ | 0x02 | 15 words | 20 bytes (160-bit) |
463
+ | 0x03 | 18 words | 24 bytes (192-bit) |
464
+ | 0x04 | 21 words | 28 bytes (224-bit) |
465
+ | 0x05 | 24 words | 32 bytes (256-bit) |
428
466
 
429
- ## 安全机制
467
+ ## Security
430
468
 
431
- - **AES-128 硬件级双向认证**(3-pass mutual authentication
432
- - **SHA-256 密钥派生**:用户密码 → SHA-256 → 取前 16 字节作为 AES 密钥
433
- - **CRC16-Modbus 校验**:数据完整性验证
434
- - **PIN 重试计数器**:密码错误自动递减,成功后恢复为 10
435
- - **安全随机数**:认证使用 `crypto.getRandomValues()`(需 Hermes 0.72 `react-native-get-random-values` polyfill)
469
+ - **AES-128 hardware-level mutual authentication** (3-pass)
470
+ - **SHA-256 key derivation**: password → SHA-256 → first 16 bytes as AES key
471
+ - **CRC16-Modbus checksum**: data integrity verification
472
+ - **PIN retry counter**: auto-decrements on wrong password, resets to 10 on success
473
+ - **CMAC secure messaging**: all commands after authentication are protected with AES-CMAC (NIST 800-38B) to prevent tampering
474
+ - **Secure random**: authentication uses `crypto.getRandomValues()` (requires Hermes ≥ 0.72 or `react-native-get-random-values` polyfill)
436
475
 
437
- ## 项目结构
476
+ ## Project Structure
438
477
 
439
478
  ```
440
479
  src/
441
- ├── index.ts # 公共 API 导出
442
- ├── constants.ts # 共享常量(页地址、NFC 命令、助记词类型)
443
- ├── types.ts # 统一 ResultCode、NfcResult 接口、错误映射
444
- ├── crypto.ts # AES 加解密、密钥派生、安全随机数生成
445
- ├── utils.ts # CRC16hex 转换、数组工具
446
- ├── nfc-core.ts # NFC 锁、transceive、认证、重试计数器
447
- ├── reader.ts # 读卡 API
448
- └── writer.ts # 写卡 API
480
+ ├── index.ts # Public API exports
481
+ ├── constants.ts # Shared constants (page addresses, NFC commands, mnemonic types)
482
+ ├── types.ts # Unified NfcStatusCode, NfcResult interface, error mapping
483
+ ├── crypto.ts # AES encrypt/decrypt, key derivation, secure random
484
+ ├── utils.ts # CRC16, hex conversion, array utilities
485
+ ├── nfc-core.ts # NFC lock, transceive, authentication, retry counter
486
+ ├── reader.ts # Reader API
487
+ └── writer.ts # Writer API
449
488
  ```
450
489
 
451
- ## 平台支持
490
+ ## Platform Support
452
491
 
453
- | 平台 | 技术 | 说明 |
454
- |------|------|------|
455
- | iOS | MifareIOS | 需要 iPhone 7 及以上 |
456
- | Android | NfcA | 需要设备支持 NFC |
492
+ | Platform | Technology | Requirements |
493
+ |----------|-----------|--------------|
494
+ | iOS | MifareIOS | iPhone 7 or later |
495
+ | Android | NfcA | NFC-capable device |
457
496
 
458
497
  ## License
459
498