v1.9.21: SCP80 docs as parent section, GP+JavaCard AID labels, UX fixes

Docs:
- SCP80 tab is now a parent section (3) with subsections 3.1/3.2/3.3
- Renumbered sections: Response parser→4, Card reader→5, Server→6, Version compat→7
- Applied to help.html, help-ru.html, README.md, README_RUS.md

C-APDU/RAM form labels (GP + JavaCard terminology):
- AID → Application / Instance AID
- ELF AID → Load File AID / Package AID
- Module AID → Executable Module AID / Applet Class AID

SCP80/RAM explorer labels (GP + JavaCard terminology):
- ISD → ISD (Issuer Security Domain)
- Applications → Applications / Applet Instances
- Executable Load Files → Executable Load Files (ELFs) / Packages
- AID → Application/Instance AID or Load File AID/Package AID (context-dependent)
- Module AIDs → Executable Module AIDs / Applet Class AIDs

UX fixes:
- Delete All button now matches Delete button style (red)
- Explorer results cleared when switching away from Explore Card operation
- KIc/KID dropdowns (index + algorithm) now update when selecting saved card
- Added LANG_RU translations for new labels
This commit is contained in:
2026-08-31 22:32:32 +03:00
parent 2c0889a8a3
commit 57c414de07
7 changed files with 681 additions and 385 deletions
+141 -146
View File
@@ -31,15 +31,19 @@ npm run build
## Interface
Five tabs, each with a form and a "Generate" button.
Four top-level tabs: **C-APDU**, **SCP80**, **Response parser**, **Card reader**. The C-APDU and SCP80 tabs each have sub-tabs.
---
## SIM RFM Tab
## C-APDU tab
Builds command APDUs (C-APDUs). Five sub-tabs cover different card generations and command sets.
### SIM RFM
CLA = `A0` (GSM 11.11 / ISO 7816-4).
### Commands
#### Commands
| Command | INS | Description |
|---|---|---|
@@ -54,56 +58,48 @@ CLA = `A0` (GSM 11.11 / ISO 7816-4).
| VERIFY PIN | 20 | Verify PIN1 or PIN2 |
| CHANGE PIN | 24 | Change PIN1 or PIN2 |
### SELECT methods
#### SELECT methods
| Method | P1 | P2 | Input |
|---|---|---|---|
| По FID | 00 | 00 | 2-byte FID (4 hex) |
| По полному пути от MF | 08 | 00 | Full path hex from MF |
| По DF name / AID | 04 | 00 | AID (application ID) |
| ADF RFM цепочка | 00 | 00 | Comma-separated FIDs, each selected in turn |
| By FID | 00 | 00 | 2-byte FID (4 hex) |
| By full path from MF | 08 | 00 | Full path hex from MF |
| By DF name / AID | 04 | 00 | AID (application ID) |
| ADF RFM chain | 00 | 00 | Comma-separated FIDs, each selected in turn |
### Options
#### Options
- **Начать с SELECT** — checkbox to prepend a SELECT command before the operation. When unchecked, the operation is sent standalone with CLA.
- **Режим выборки (P2)** — for record commands: Absolute (04), Next (06), Previous (02).
- **Размер записи** — pad/truncate data to the specified byte count.
- **Переопределить P1/P2** — checkbox to enable manual override of P1/P2 bytes.
- **Start with SELECT** — checkbox to prepend a SELECT command before the operation. When unchecked, the operation is sent standalone with CLA.
- **Selection mode (P2)** — for record commands: Absolute (04), Next (06), Previous (02).
- **Record size** — pad/truncate data to the specified byte count.
- **Allow P1/P2 editing** — checkbox to enable manual override of P1/P2 bytes.
### Conversion sidebar
A conversion panel is embedded in the right-hand column, supporting IMSI, MSISDN, ICCID, SPN, PLMN, and Nibble swap conversions.
### References
#### References
- ISO/IEC 7816-4: Organization, security and commands for interchange
- ETSI TS 102 226: Remote APDU structure for UICC based applications
- GSM 11.11: SIM-ME Interface
---
## USIM RFM Tab
### USIM RFM
CLA = `00` (ETSI TS 102 221). Same commands as SIM, but SELECT uses P1=09, P2=0C (by FID from current directory).
### References
#### References
- ETSI TS 102 221: UICC-Terminal Interface; Physical and Logical Characteristics
- ETSI TS 102 226: Remote APDU structure for UICC based applications
---
## Expanded Script Tab
### Expanded Script
Builds Expanded Remote Application data format per ETSI TS 102 226 §5.2.1.
### Format
#### Format
Two encoding variants:
- **Definite (AA)**: `AA` + length + Command TLVs
- **Indefinite (AE)**: `AE` + `80` + Command TLVs + `00 00`
### Command TLVs
#### Command TLVs
| Type | Tag | Description |
|---|---|---|
@@ -112,7 +108,7 @@ Two encoding variants:
| Error Action | 82 | Proactive command on error |
| Script Chaining | 83 | Chaining data for multi-packet scripts |
### Immediate Action builder
#### Immediate Action builder
When the type is set to Immediate Action, the tool provides a structured builder for:
@@ -122,54 +118,17 @@ When the type is set to Immediate Action, the tool provides a structured builder
Error Action supports the same builder (DISPLAY TEXT, PLAY TONE).
### References
#### References
- ETSI TS 102 226 V13.0.0 §5.2.1: Expanded Remote Application data format
- ETSI TS 102 223: Card Application Toolkit (CAT) — proactive command structure
- ETSI TS 101 220: BER-TLV tag assignments
---
### RAM/GP
## RAM Tab
CLA = `80` (GlobalPlatform Card Specification v2.3.1). Remote Application Management commands for card content management.
CLA = `80` (GlobalPlatform Card Specification v2.3.1). Remote Application Management operations for card content management over SCP80.
All RAM operations are delivered as SCP80 secured packets (ETSI TS 102 225) via SMS-PP-DOWNLOAD ENVELOPE. The card must support SCP03 (AES or 3DES) for secure transport.
### Card Preset
Select a saved card configuration from the **Card preset** dropdown. Each preset stores:
| Field | Description |
|---|---|
| SPI1 / SPI2 | Security level and PoR settings |
| KIc / KID key | Encryption and MAC key hex |
| KIc / KID index | Key version number |
| TAR | Toolkit Application Reference (3 bytes) |
| Counter (CNTR) | 10-digit hex replay counter, auto-incremented after each successful SCP80 send |
Card presets are managed in the **SCP80 → Cards** subtab (see below). If no preset is selected, the RAM tab warns and refuses to execute.
### Operations
The RAM subtab offers two operations selected from the **Operation** dropdown:
| Operation | Description |
|---|---|
| **Explore Card (all GP data)** | Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 for memory info. Results appear in an explorer view with per-item **Delete** buttons. |
| **Install Package (.cap file)** | Sends a `.cap` file to the card via the server: INSTALL\[for load\] → LOAD ×N → INSTALL\[for install (+make selectable)\]. |
### Explorer View
After "Explore Card" runs, the explorer view displays:
- **ISD** — AID, lifecycle, privileges (no delete; the ISD cannot be removed)
- **Applications** — AID, lifecycle, privileges, associated ELF/SD. Each has a **Delete** button (GP `DELETE` by AID).
- **Executable Load Files** — AID, lifecycle, version, module AIDs. Each has **Delete** (ELF only) and **Delete All** (cascade: ELF + modules + installed Applications, P2=0x80) buttons.
Delete confirms via a browser prompt before sending the GP `DELETE` command via SCP80. The explorer auto-refreshes after a successful deletion.
### GP Commands Reference
#### GP Commands Reference
| Command | INS | P1 | Description |
|---|---|---|---|
@@ -187,7 +146,7 @@ Delete confirms via a browser prompt before sending the GP `DELETE` command via
| EXTERNAL AUTHENTICATE | 82 | 00 | SCP host authentication |
| INTERNAL AUTHENTICATE | 88 | 00 | Card challenge-response |
### INSTALL [for install] — Privilege Builder
#### INSTALL [for install] — Privilege Builder
Tag `C7` in the INSTALL data field. Built from 3 privilege bytes (GP spec Tables 11-7, 11-8, 11-9):
@@ -218,7 +177,7 @@ Tag `C7` in the INSTALL data field. Built from 3 privilege bytes (GP spec Tables
|---|---|
| b8 | Receipt Generation |
### INSTALL [for install] — SIM/UICC Toolkit Parameters
#### INSTALL [for install] — SIM/UICC Toolkit Parameters
Optional TLV objects appended to the INSTALL data field:
@@ -235,7 +194,7 @@ Optional TLV objects appended to the INSTALL data field:
| 16 | RC/DS/CC + MAC + Cipher |
| 19 | RC/DS/CC + MAC + Cipher + DS |
### GET STATUS P1 values
#### GET STATUS P1 values
| Value | Meaning |
|---|---|
@@ -244,7 +203,7 @@ Optional TLV objects appended to the INSTALL data field:
| 20 | Executable Load Files |
| 10 | ELF and their Executable Modules |
### GET STATUS P2 values
#### GET STATUS P2 values
| Value | Meaning |
|---|---|
@@ -253,7 +212,7 @@ Optional TLV objects appended to the INSTALL data field:
| 00 | First/all, old format (deprecated) |
| 02 | Next, old format (deprecated) |
### GET DATA tag values
#### GET DATA tag values
| Tag | Data Object |
|---|---|
@@ -271,14 +230,14 @@ Optional TLV objects appended to the INSTALL data field:
| 7F21 | Certificate (SD public key) |
| 5031 | Certificate info (EF.OD) |
### DELETE P1 values
#### DELETE P1 values
| Value | Meaning |
|---|---|
| 00 | By AID |
| 80 | Delete associated objects |
### STORE DATA P1 values
#### STORE DATA P1 values
| Value | Meaning |
|---|---|
@@ -287,7 +246,7 @@ Optional TLV objects appended to the INSTALL data field:
| 80 | Last block, encrypted |
| C0 | More blocks, encrypted |
### SET STATUS parameters
#### SET STATUS parameters
**P1 (Status Type)**:
| Value | Target |
@@ -302,18 +261,68 @@ Optional TLV objects appended to the INSTALL data field:
| 00 | Unlock (return to previous state) |
| 80 | Lock (LOCKED state) |
### References
#### References
- GlobalPlatform Card Specification v2.3.1 (GPC_Spec_v2.3.1): Commands, Privileges, TLV structures
- ETSI TS 102 226 V13.0.0 §8.2.1.3.2: SIM/UICC Toolkit parameters, MSL, TAR, Access Domain
### Conversion (SIM/USIM sidebars)
Value encoding conversions embedded in the SIM RFM and USIM RFM tabs.
#### IMSI → EF.IMSI
Per TS 31.102 §4.2.3. Encodes a 15-digit IMSI into the 9-byte EF.IMSI format:
- Byte 0: number of subsequent bytes (8)
- Odd/even indicator nibble in the last byte
- BCD digits, swapped nibble pairs per identity
Input: 15 decimal digits. Output: 18 hex characters.
#### MSISDN → BCD
Strips leading `+`, pads odd length with `f`, swaps nibble pairs.
#### ICCID → hex
Swaps nibble pairs of the ICCID string.
#### Provider Name → SPN
Per 3GPP TS 31.102 §4.2.5 (EF_SPN). Three encoding paths:
1. **GSM 7-bit packed** (all chars in GSM 7-bit default alphabet): prefix `01`, DCS byte (spare bits), packed septets, 0xFF padding to 16 bytes.
2. **UCS2 non-BMP** (emoji / chars > U+FFFF): prefix `00`, DCS `80`, UTF-16BE, 0xFF padding to 16 bytes.
3. **UCS2 BMP non-GSM7** (Cyrillic, etc.): prefix `00`, DCS `81`, base byte, per-char offsets, 0xFF padding to 16 bytes.
GSM 7-bit alphabet per 3GPP TS 23.038. Full extension table supported.
#### PLMN → EF_PLMNsel / PLMNwAcT
Per TS 31.102 §4.2.3. 3-byte BCD encoding for PLMN, plus optional 2-byte Access Technology selector.
#### Nibble swap
Swaps nibble pairs of an even-length hex string.
#### References
- 3GPP TS 31.102: Characteristics of the USIM Application
- 3GPP TS 23.038: Alphabets and language information
- ETSI TS 102 225: Secured packet structure for (U)SIM toolkit
- pySim: enc_imsi() implementation
---
## SCP80 Tab — Secured Packet
## SCP80 tab
The **SCP80** top-level tab groups SCP80-related views, switched by two pills: **Secured Packet** (this section) and **Cards**. Assembles secured packets per ETSI TS 102 225.
The **SCP80** top-level tab groups SCP80-related views, switched by three pills: **Secured Packet**, **Cards**, and **RAM**. Assembles secured packets per ETSI TS 102 225.
### Packet structure
### Secured Packet
Builds SCP80 secured packets per ETSI TS 102 225.
#### Packet structure
| Field | Size | Description |
|---|---|---|
@@ -330,7 +339,7 @@ The **SCP80** top-level tab groups SCP80-related views, switched by two pills: *
| RC/CC/DS | 8 | Cryptographic Checksum / MAC |
| Secured Data | variable | Padded APDU (encrypted if required) |
### SPI1 (Security Level)
#### SPI1 (Security Level)
SPI1 bit layout (TS 102 225 §5.1.1): `b8b6` padding, `b5b4` counter, `b3` ciphering, `b2b1` RC/CC/DS.
@@ -350,7 +359,7 @@ SPI1 bit layout (TS 102 225 §5.1.1): `b8b6` padding, `b5b4` counter, `b3`
> **AES requires `b5 b4 = 10` (higher) or `11` (+1)** per TS 102 225 §5.1.2 and §5.1.3.1.
> The 3DES values `00/01/02/06` (no counter) remain valid for 3DES only.
### SPI2 (PoR settings)
#### SPI2 (PoR settings)
| Value | Mode | Security | Cipher |
|---|---|---|---|
@@ -363,7 +372,7 @@ SPI1 bit layout (TS 102 225 §5.1.1): `b8b6` padding, `b5b4` counter, `b3`
| 02 | PoR on error | None | No |
| 06 | PoR on error | RC | No |
### Crypto
#### Crypto
- **3DES-CBC** encryption (zero ICV), supporting 8, 16, and 24 byte keys — deprecated since Rel-18, still supported for backwards compatibility
- **AES-CBC** encryption (zero ICV, zero-padded to 16), supporting 16, 24, and 32 byte keys (TS 102 225 §5.1.2, KIc `x2`)
@@ -371,14 +380,7 @@ SPI1 bit layout (TS 102 225 §5.1.1): `b8b6` padding, `b5b4` counter, `b3`
- **AES-CMAC** (NIST SP 800-38B, truncated to 8 octets) for the AES cryptographic checksum (TS 102 225 §5.1.3.1, KID `x2`)
- Padding byte configurable (`00` per TS 102 225 default, or `FF`)
### References
- ETSI TS 102 225 V18.1.0: Secured packet structure for UICC based applications
- ETSI TS 102 226: Remote APDU structure for UICC based applications
- ISO 9797-1: MAC algorithms
- NIST SP 800-38B: CMAC
### PoR (Proof of Reception)
#### PoR (Proof of Reception)
PoR confirms the card received and executed the secured packet. Two modes:
@@ -389,9 +391,24 @@ PoR confirms the card received and executed the secured packet. Two modes:
Delivery PoR (SPI2 `01`) is simpler — the card returns the PoR directly in the ENVELOPE response. Submit PoR (SPI2 `21`) is used when the card cannot respond inline (e.g. during ELF operations where the ENVELOPE response space is limited).
### Cards Subtab
#### References
The **Cards** pill in the SCP80 tab manages saved card configurations (presets). Each preset stores the cryptographic keys, SPI settings, TAR, and replay counter needed for SCP80 operations.
- ETSI TS 102 225 V18.1.0: Secured packet structure for UICC based applications
- ETSI TS 102 226: Remote APDU structure for UICC based applications
- ISO 9797-1: MAC algorithms
- NIST SP 800-38B: CMAC
### Cards
Stores saved card configurations (presets). Each preset stores the cryptographic keys, SPI settings, TAR, and replay counter needed for SCP80 operations.
| Field | Description |
|---|---|
| SPI1 / SPI2 | Security level and PoR settings |
| KIc / KID key | Encryption and MAC key hex |
| KIc / KID index | Key version number |
| TAR | Toolkit Application Reference (3 bytes) |
| Counter (CNTR) | 10-digit hex replay counter, auto-incremented after each successful SCP80 send |
**Add a card:** fill in the name, SPI1/SPI2, KIc/KID keys and indices, TAR, and click **Add**. The card appears in the list and becomes available in the RAM tab's **Card preset** dropdown.
@@ -401,57 +418,41 @@ The **Cards** pill in the SCP80 tab manages saved card configurations (presets).
**Counter:** the 10-digit hex counter (CNTR) is auto-incremented after each successful SCP80 send (both manual Secured Packet sends and RAM operations). The updated counter is saved back to the preset automatically.
---
### RAM
## Conversion (SIM/USIM sidebars)
All RAM operations are delivered as SCP80 secured packets (ETSI TS 102 225) via SMS-PP-DOWNLOAD ENVELOPE. The card must support SCP03 (AES or 3DES) for secure transport.
Value encoding conversions embedded in the SIM RFM and USIM RFM tabs.
Select a saved card configuration from the **Card preset** dropdown. If no preset is selected, the RAM tab warns and refuses to execute.
### IMSI → EF.IMSI
The RAM subtab offers two operations selected from the **Operation** dropdown:
Per TS 31.102 §4.2.3. Encodes a 15-digit IMSI into the 9-byte EF.IMSI format:
- Byte 0: number of subsequent bytes (8)
- Odd/even indicator nibble in the last byte
- BCD digits, swapped nibble pairs per identity
| Operation | Description |
|---|---|
| **Explore Card (all GP data)** | Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 for memory info. Results appear in an explorer view with per-item **Delete** buttons. |
| **Install Package (.cap file)** | Sends a `.cap` file to the card via the server: INSTALL\[for load\] → LOAD ×N → INSTALL\[for install (+make selectable)\]. |
Input: 15 decimal digits. Output: 18 hex characters.
#### Explorer View
### MSISDN → BCD
After "Explore Card" runs, the explorer view displays:
Strips leading `+`, pads odd length with `f`, swaps nibble pairs.
- **ISD** — AID, lifecycle, privileges (no delete; the ISD cannot be removed)
- **Applications** — AID, lifecycle, privileges, associated ELF/SD. Each has a **Delete** button (GP `DELETE` by AID).
- **Executable Load Files** — AID, lifecycle, version, module AIDs. Each has **Delete** (ELF only) and **Delete All** (cascade: ELF + modules + installed Applications, P2=0x80) buttons.
### ICCID → hex
Swaps nibble pairs of the ICCID string.
### Provider Name → SPN
Per 3GPP TS 31.102 §4.2.5 (EF_SPN). Three encoding paths:
1. **GSM 7-bit packed** (all chars in GSM 7-bit default alphabet): prefix `01`, DCS byte (spare bits), packed septets, 0xFF padding to 16 bytes.
2. **UCS2 non-BMP** (emoji / chars > U+FFFF): prefix `00`, DCS `80`, UTF-16BE, 0xFF padding to 16 bytes.
3. **UCS2 BMP non-GSM7** (Cyrillic, etc.): prefix `00`, DCS `81`, base byte, per-char offsets, 0xFF padding to 16 bytes.
GSM 7-bit alphabet per 3GPP TS 23.038. Full extension table supported.
### PLMN → EF_PLMNsel / PLMNwAcT
Per TS 31.102 §4.2.3. 3-byte BCD encoding for PLMN, plus optional 2-byte Access Technology selector.
### Nibble swap
Swaps nibble pairs of an even-length hex string.
### References
- 3GPP TS 31.102: Characteristics of the USIM Application
- 3GPP TS 23.038: Alphabets and language information
- ETSI TS 102 225: Secured packet structure for (U)SIM toolkit
- pySim: enc_imsi() implementation
Delete confirms via a browser prompt before sending the GP `DELETE` command via SCP80. The explorer auto-refreshes after a successful deletion.
---
## Response parser tab
Decodes a raw command response: pick the command that was sent, enter the SW (e.g. `9000`) and the response data hex, then press **Decode**.
- **Command** — SIM/USIM group (SELECT, STATUS, READ/UPDATE, PIN ops, CAT commands like TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, ...) or RAM/GP group (INSTALL, LOAD, DELETE, GET/STORE DATA, auth, SCP commands).
- **SW decode** — status words resolved against generic, UICC (TS 102 221), and GlobalPlatform maps, with context auto-detected.
- **Privilege decode** — GET DATA / INSTALL response payloads decode the privilege bytes into human-readable flags.
- **Response data** — raw hex rendered and interpreted per command (e.g. SELECT FCP templates).
---
## Card Reader (pySim integration)
@@ -480,11 +481,9 @@ Custom files persist in `localStorage` across sessions. Export/import as JSON fo
### Proactive UICC Pill
The **Proactive UICC** sub-tab in the Card Reader provides real-time CAT session
interaction:
The **Proactive UICC** sub-tab in the Card Reader provides real-time CAT session interaction:
**Subscribed Events** — the card's SET UP EVENT LIST is displayed with per-event
**Send** buttons. Clicking opens a form specific to the event type:
**Subscribed Events** — the card's SET UP EVENT LIST is displayed with per-event **Send** buttons. Clicking opens a form specific to the event type:
- **No-data events** (User Activity, Idle Screen, etc.) — single-click confirmation
- **Location Status** — dropdown for Normal / Limited / No service
@@ -495,13 +494,9 @@ interaction:
technology selection, and 53-cause unified rejection cause code dropdown
covering EMM, GMM, 5GMM, and LU causes
**Proactive Command Log** — chronological list of proactive commands encountered
(seconds elapsed, type code, name, byte count). Covers SET UP MENU, SET UP EVENT
LIST, POLL INTERVAL, DISPLAY TEXT, SELECT ITEM, and PROVIDE LOCAL INFORMATION.
**Proactive Command Log** — chronological list of proactive commands encountered (seconds elapsed, type code, name, byte count). Covers SET UP MENU, SET UP EVENT LIST, POLL INTERVAL, DISPLAY TEXT, SELECT ITEM, and PROVIDE LOCAL INFORMATION.
**PLI Data Dictionary** — editable per-qualifier hex values for all 22 PROVIDE
LOCAL INFORMATION qualifiers (TS 102 223 + TS 131 111). 10 qualifiers have
inline decode/encode forms (▶ toggle):
**PLI Data Dictionary** — editable per-qualifier hex values for all 22 PROVIDE LOCAL INFORMATION qualifiers (TS 102 223 + TS 131 111). 10 qualifiers have inline decode/encode forms (toggle):
| Code | Decoded fields |
|------|--------------|
@@ -516,14 +511,14 @@ inline decode/encode forms (▶ toggle):
| 0A | Battery charge (%) |
| 0E | Multiple Access Technologies (comma-list) |
Values persist on the server until restart. Apply → hex updates; Save → POSTs to
server. The server will use these values to populate TERMINAL RESPONSE data for
future PLI proactive commands.
Values persist on the server until restart. Apply → hex updates; Save → POSTs to server. The server will use these values to populate TERMINAL RESPONSE data for future PLI proactive commands.
### Command Hints
Type a command name in the **pySim command line** input. Usage hints appear as a tooltip after 300ms. Command autocomplete suggestions appear above the input.
---
## PWA
OTAMan is a Progressive Web App and can be installed for offline use. Use the **INSTALL PWA** button in the header, or use the browser's install prompt.
+181 -146
View File
@@ -31,15 +31,19 @@ npm run build
## Интерфейс
Пять вкладок, каждая с формой и кнопкой «Generate APDU».
Четыре вкладки: **C-APDU**, **SCP80**, **Response parser**, **Card reader**. Вкладки C-APDU и SCP80 имеют подвкладки.
---
## Вкладка SIM RFM
## Вкладка C-APDU
Построение команд APDU (C-APDU). Пять подвкладок для разных поколений карт и наборов команд.
### SIM RFM
CLA = `A0` (GSM 11.11 / ISO 7816-4).
### Команды
#### Команды
| Команда | INS | Описание |
|---|---|---|
@@ -54,7 +58,7 @@ CLA = `A0` (GSM 11.11 / ISO 7816-4).
| VERIFY PIN | 20 | Проверка PIN1 или PIN2 |
| CHANGE PIN | 24 | Смена PIN1 или PIN2 |
### Методы SELECT
#### Методы SELECT
| Метод | P1 | P2 | Ввод |
|---|---|---|---|
@@ -63,46 +67,38 @@ CLA = `A0` (GSM 11.11 / ISO 7816-4).
| By DF name / AID | 04 | 00 | AID |
| ADF RFM chain | 00 | 00 | FID через запятую |
### Опции
#### Опции
- **Start with SELECT** — добавить SELECT перед командой.
- **Selection mode (P2)** — для record-команд: Absolute (04), Next (06), Previous (02).
- **Record size** — дополнить/обрезать данные до указанного размера.
- **Allow P1/P2 editing** — ручное редактирование P1/P2.
### Боковая панель конвертации
Поддерживает IMSI, MSISDN, ICCID, SPN, PLMN, Nibble swap.
### Ссылки
#### Ссылки
- ISO/IEC 7816-4: Organization, security and commands for interchange
- ETSI TS 102 226: Remote APDU structure for UICC based applications
- GSM 11.11: SIM-ME Interface
---
## Вкладка USIM RFM
### USIM RFM
CLA = `00` (ETSI TS 102 221). Те же команды, что и SIM, но SELECT использует P1=09, P2=0C.
### Ссылки
#### Ссылки
- ETSI TS 102 221: UICC-Terminal Interface
- ETSI TS 102 226: Remote APDU structure
---
## Вкладка Expanded Script
### Expanded Script
Построение Expanded Remote Application data format по ETSI TS 102 226 §5.2.1.
### Формат
#### Формат
- **Definite (AA)**: `AA` + длина + Command TLV
- **Indefinite (AE)**: `AE` + `80` + Command TLV + `00 00`
### Command TLV
#### Command TLV
| Тип | Тег | Описание |
|---|---|---|
@@ -111,60 +107,23 @@ CLA = `00` (ETSI TS 102 221). Те же команды, что и SIM, но SELE
| Error Action | 82 | Proactive-команда при ошибке |
| Script Chaining | 83 | Данные для многопакетных скриптов |
### Сборщик Immediate Action
#### Сборщик Immediate Action
- **Action indicator**: `81` / `82`
- **Proactive command**: REFRESH, DISPLAY TEXT, PLAY TONE
- **Custom hex**: ручной ввод
### Ссылки
#### Ссылки
- ETSI TS 102 226 §5.2.1
- ETSI TS 102 223: Card Application Toolkit
- ETSI TS 101 220: BER-TLV tag assignments
---
## Вкладка RAM
### RAM/GP
CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление содержимым карты через SCP80.
Все операции RAM отправляются как защищённые пакеты SCP80 (ETSI TS 102 225) через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES) для безопасной транспортировки.
### Выбор карты (Card Preset)
Выберите сохранённую конфигурацию карты из выпадающего списка **Card preset**. Каждый пресет хранит:
| Поле | Описание |
|---|---|
| SPI1 / SPI2 | Уровень безопасности и настройки PoR |
| Ключ KIc / KID | Hex ключи шифрования и MAC |
| Индекс KIc / KID | Номер версии ключа |
| TAR | Toolkit Application Reference (3 байта) |
| Счётчик (CNTR) | 10-значный hex счётчик повторов, автоматически увеличивается после каждой успешной отправки SCP80 |
Пресеты карт управляются во вкладке **SCP80 → Cards** (см. ниже). Если пресет не выбран, RAM-вкладка предупреждает и отказывается выполнять.
### Операции
В RAM-подвкладке доступны две операции через выпадающий список **Operation**:
| Операция | Описание |
|---|---|
| **Explore Card (all GP data)** | Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 для информации о памяти. Результаты отображаются в обзоре с кнопками **Delete** для каждого элемента. |
| **Install Package (.cap file)** | Отправка `.cap` файла на карту через сервер: INSTALL\[for load\] → LOAD ×N → INSTALL\[for install (+make selectable)\]. |
### Обзор карты (Explorer View)
После выполнения "Explore Card" отображается:
- **ISD** — AID, жизненный цикл, привилегии (без удаления; ISD нельзя удалить)
- **Приложения** — AID, жизненный цикл, привилегии, связанный ELF/SD. Каждое имеет кнопку **Delete** (GP `DELETE` по AID).
- **Executable Load Files** — AID, жизненный цикл, версии, AID модулей. Каждый имеет **Delete** (только ELF) и **Delete All** (каскадное: ELF + модули + установленные приложения, P2=0x80).
Удаление подтверждается через диалог браузера перед отправкой команды GP `DELETE` через SCP80. Обзор автоматически обновляется после успешного удаления.
### Справочник GP-команд
#### Справочник GP-команд
| Команда | INS | P1 | Описание |
|---|---|---|---|
@@ -182,7 +141,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| EXTERNAL AUTHENTICATE | 82 | 00 | Аутентификация SCP |
| INTERNAL AUTHENTICATE | 88 | 00 | Challenge-response |
### Привилегии (INSTALL)
#### Привилегии (INSTALL [for install])
Три байта привилегий по GP Spec Tables 11-7, 11-8, 11-9.
@@ -213,7 +172,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
|---|---|
| b8 | Receipt Generation |
### Параметры SIM/UICC Toolkit
#### Параметры SIM/UICC Toolkit
- **Tag `CA`** (SIM Toolkit): Priority, Timers, Text Length, Menu Entries, Positions, Channels, MSL, TAR, Access Domain
- **Tag `80`** (UICC Toolkit, внутри `EA`): те же поля без Access Domain
@@ -228,7 +187,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| 16 | RC/DS/CC + MAC + Cipher |
| 19 | RC/DS/CC + MAC + Cipher + DS |
### GET STATUS P1
#### GET STATUS P1
| Значение | Описание |
|---|---|
@@ -237,7 +196,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| 20 | Executable Load Files |
| 10 | ELF и модули |
### GET STATUS P2
#### GET STATUS P2
| Значение | Описание |
|---|---|
@@ -246,7 +205,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| 00 | Первые/все, старый формат (deprecated) |
| 02 | Следующие, старый формат (deprecated) |
### GET DATA теги
#### GET DATA теги
| Тег | Объект данных |
|---|---|
@@ -264,14 +223,14 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| 7F21 | Certificate (SD public key) |
| 5031 | Certificate info (EF.OD) |
### DELETE P1
#### DELETE P1
| Значение | Описание |
|---|---|
| 00 | Только AID |
| 80 | AID и связанные объекты |
### STORE DATA P1
#### STORE DATA P1
| Значение | Описание |
|---|---|
@@ -280,24 +239,64 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| 80 | Последний блок, с шифрованием |
| C0 | Ещё блоки, с шифрованием |
### SET STATUS
#### SET STATUS
**P1:** 80 = ISD, 40 = Приложение или SSD, 60 = SD и его приложения
**P2:** 00 = Разблокировать, 80 = Заблокировать (LOCKED)
### Ссылки
#### Ссылки
- GlobalPlatform Card Specification v2.3.1
- ETSI TS 102 226 §8.2.1.3.2: Параметры SIM/UICC Toolkit
### Конвертация (боковые панели SIM/USIM)
#### IMSI → EF.IMSI
15-значный IMSI → 9 байт EF.IMSI.
#### MSISDN → BCD
Удаление `+`, добавление `f`, обмен полубайтов.
#### ICCID → hex
Обмен полубайтов строки ICCID.
#### Provider Name → SPN
По 3GPP TS 31.102 §4.2.5. Три варианта кодирования:
1. GSM 7-bit packed
2. UCS2 non-BMP
3. UCS2 BMP non-GSM7
#### PLMN → EF_PLMNsel / PLMNwAcT
3-байтное BCD-кодирование + опциональный Access Technology.
#### Nibble swap
Обмен полубайтов hex-строки.
#### Ссылки
- 3GPP TS 31.102
- 3GPP TS 23.038
- ETSI TS 102 225
- pySim: enc_imsi()
---
## Вкладка Secured Packet
## Вкладка SCP80
Сборка защищённых пакетов по ETSI TS 102 225.
Вкладка **SCP80** группирует SCP80-виды, переключаемые тремя пиллами: **Secured Packet**, **Cards** и **RAM**. Сборка защищённых пакетов по ETSI TS 102 225.
### Структура пакета
### Secured Packet
Сборка защищённых пакетов SCP80 по ETSI TS 102 225.
#### Структура пакета
| Поле | Размер | Описание |
|---|---|---|
@@ -314,7 +313,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| RC/CC/DS | 8 | Контрольная сумма / MAC |
| Secured Data | переменная | APDU (с шифрованием при необходимости) |
### SPI1 (Уровень безопасности)
#### SPI1 (Уровень безопасности)
Битовое поле SPI1 (TS 102 225 §5.1.1): `b8b6` — паддинг, `b5b4` — счётчик, `b3` — шифрование, `b2b1` — RC/CC/DS.
@@ -334,7 +333,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
> **AES требует `b5 b4 = 10` (higher) или `11` (+1)** согласно TS 102 225 §5.1.2 и §5.1.3.1.
> Значения `00/01/02/06` (без счётчика) допустимы только для 3DES.
### SPI2 (PoR)
#### SPI2 (PoR)
| Значение | Режим |
|---|---|
@@ -347,7 +346,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
| 02 | PoR on error, no security |
| 06 | PoR on error, RC |
### Крипто
#### Крипто
- **3DES-CBC** шифрование, ключи 8/16/24 байт — устарело с Rel-18, но поддерживается для обратной совместимости
- **AES-CBC** шифрование (нулевой ICV, дополнение нулями до 16), ключи 16/24/32 байта (TS 102 225 §5.1.2, KIc `x2`)
@@ -355,26 +354,7 @@ CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление со
- **AES-CMAC** (NIST SP 800-38B, усечённый до 8 октетов) для AES (TS 102 225 §5.1.3.1, KID `x2`)
- Padding byte: `00` (по умолчанию) или `FF`
### Ссылки
- ETSI TS 102 225 V18.1.0
- ETSI TS 102 226
- ISO 9797-1
- NIST SP 800-38B (CMAC)
### Подвкладка Cards
Пилл **Cards** во вкладке SCP80 управляет сохранёнными конфигурациями карт (пресеты). Каждый пресет хранит криптографические ключи, настройки SPI, TAR и счётчик повторов для SCP80-операций.
**Добавить карту:** заполните имя, SPI1/SPI2, ключи KIc/KID и их индексы, TAR, нажмите **Add**. Карта появится в списке и станет доступна в выпаданом списке **Card preset** на RAM-вкладке.
**Редактировать карту:** выберите карту в списке, измените поля, нажмите **Save**.
**Удалить карту:** выберите карту, нажмите **Delete**. Удаляет пресет из `localStorage`.
**Счётчик:** 10-значный hex-счётчик (CNTR) автоматически увеличивается после каждой успешной отправки SCP80 (ручные отправки Secured Packet и RAM-операции). Обновлённый счётчик автоматически сохраняется обратно в пресет.
### PoR (Proof of Reception)
#### PoR (Proof of Reception)
PoR подтверждает, что карта получила и выполнила защищённый пакет. Два режима:
@@ -385,43 +365,127 @@ PoR подтверждает, что карта получила и выполн
Delivery PoR (SPI2 `01`) проще — карта возвращает PoR напрямую в ответе ENVELOPE. Submit PoR (SPI2 `21`) используется, когда карта не может ответить inline (ограничено пространство ответа ENVELOPE).
#### Ссылки
- ETSI TS 102 225 V18.1.0
- ETSI TS 102 226
- ISO 9797-1
- NIST SP 800-38B (CMAC)
### Cards
Пилл **Cards** управляет сохранёнными конфигурациями карт (пресеты). Каждый пресет хранит криптографические ключи, настройки TAR и счётчик повторов для SCP80-операций.
| Поле | Описание |
|---|---|
| SPI1 / SPI2 | Уровень безопасности и настройки PoR |
| Ключ KIc / KID | Hex ключи шифрования и MAC |
| Индекс KIc / KID | Номер версии ключа |
| TAR | Toolkit Application Reference (3 байта) |
| Счётчик (CNTR) | 10-значный hex счётчик повторов, автоматически увеличивается после каждой успешной отправки SCP80 |
**Добавить карту:** заполните имя, SPI1/SPI2, ключи KIc/KID и их индексы, TAR, нажмите **Add**. Карта появится в списке и станет доступна в выпаданом списке **Card preset** на RAM-вкладке.
**Редактировать карту:** выберите карту в списке, измените поля, нажмите **Save**.
**Удалить карту:** выберите карту, нажмите **Delete**. Удаляет пресет из `localStorage`.
**Счётчик:** 10-значный hex-счётчик (CNTR) автоматически увеличивается после каждой успешной отправки SCP80 (ручные отправки Secured Packet и RAM-операции). Обновлённый счётчик автоматически сохраняется обратно в пресет.
### RAM
Все операции RAM отправляются как защищённые пакеты SCP80 (ETSI TS 102 225) через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES) для безопасной транспортировки.
Выберите сохранённую конфигурацию карты из выпадающего списка **Card preset**. Если пресет не выбран, RAM-вкладка предупреждает и отказывается выполнять.
В RAM-подвкладке доступны две операции через выпадающий список **Operation**:
| Операция | Описание |
|---|---|
| **Explore Card (all GP data)** | Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 для информации о памяти. Результаты отображаются в обзоре с кнопками **Delete** для каждого элемента. |
| **Install Package (.cap file)** | Отправка `.cap` файла на карту через сервер: INSTALL\[for load\] → LOAD ×N → INSTALL\[for install (+make selectable)\]. |
#### Обзор карты (Explorer View)
После выполнения "Explore Card" отображается:
- **ISD** — AID, жизненный цикл, привилегии (без удаления; ISD нельзя удалить)
- **Приложения** — AID, жизненный цикл, привилегии, связанный ELF/SD. Каждое имеет кнопку **Delete** (GP `DELETE` по AID).
- **Executable Load Files** — AID, жизненный цикл, версии, AID модулей. Каждый имеет **Delete** (только ELF) и **Delete All** (каскадное: ELF + модули + установленные приложения, P2=0x80).
Удаление подтверждается через диалог браузера перед отправкой команды GP `DELETE` через SCP80. Обзор автоматически обновляется после успешного удаления.
---
## Конвертация (боковые панели SIM/USIM)
## Вкладка Response parser
### IMSI → EF.IMSI
Декодирование ответа команды: выберите отправленную команду, введите SW (например, `9000`) и данные ответа в hex, затем нажмите **Decode**.
15-значный IMSI → 9 байт EF.IMSI.
- **Команда** — группа SIM/USIM (SELECT, STATUS, READ/UPDATE, операции с PIN, CAT-команды TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, ...) или группа RAM/GP (INSTALL, LOAD, DELETE, GET/STORE DATA, аутентификация, команды SCP).
- **Декодирование SW** — статусные слова по картам generic, UICC (TS 102 221) и GlobalPlatform с автоопределением контекста.
- **Декодирование привилегий** — байты привилегий из ответов GET DATA / INSTALL в читаемые флаги.
- **Данные ответа** — hex с интерпретацией по команде (например, шаблоны FCP из SELECT).
### MSISDN → BCD
---
Удаление `+`, добавление `f`, обмен полубайтов.
## Card Reader (интеграция с pySim)
### ICCID → hex
Подключение к встроенному [`pysim-otaman-server`](pysim_otaman_server/) для работы с картой.
Обмен полубайтов строки ICCID.
> **Ограничение браузера:** если PWA раздаётся с публичного HTTPS-хоста, для доступа к локальному серверу (`http://127.0.0.1:8080`) нужны два условия: сервер должен отправлять `Access-Control-Allow-Private-Network: true` (pysim-otaman-server ≥ 1.6.1 делает это автоматически), и браузеру должно быть разрешено обращаться к локальной сети — в Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети → разрешить сайт (или подтвердить запрос). Без разрешения браузера запрос к `127.0.0.1` блокируется ещё до отправки preflight.
### Provider Name → SPN
### Файловый менеджер
По 3GPP TS 31.102 §4.2.5. Три варианта кодирования:
1. GSM 7-bit packed
2. UCS2 non-BMP
3. UCS2 BMP non-GSM7
Дерево файлов UICC. Отображаются имена, FID и AID (для ADF). Клик для чтения содержимого.
### PLMN → EF_PLMNsel / PLMNwAcT
- **Read** — чтение файла (автоопределение transparent/record)
- **Edit** — режим редактирования, измените hex-данные и нажмите **Save** для записи
- **Raw / Decoded** — переключение между hex-дампом и декодированным JSON
3-байтное BCD-кодирование + опциональный Access Technology.
### Пользовательские файлы
### Nibble swap
Файлы, отсутствующие в модели pysim, можно добавить вручную:
Обмен полубайтов hex-строки.
1. Перейдите на вкладку **Custom files**
2. Введите путь (например, `3F00/6F46`) и псевдоним (например, `EF.SPN`)
3. Нажмите **Add** — файл появится в дереве курсивом (непроверенный)
4. Кликните для проверки существования — при успехе работает как обычный файл
### Ссылки
Пользовательские файлы сохраняются в `localStorage`. Экспорт/импорт в JSON для обмена.
- 3GPP TS 31.102
- 3GPP TS 23.038
- ETSI TS 102 225
- pySim: enc_imsi()
### Proactive UICC
Подраздел **Proactive UICC** во вкладке Card Reader обеспечивает взаимодействие с CAT-сессией в реальном времени:
**Subscribed Events** — список событий SET UP EVENT LIST с кнопками **Send**. Клик открывает форму для конкретного типа события:
- **События без данных** (User Activity, Idle Screen и др.) — однократное уведомление
- **Location Status** — выпадающий список: Normal / Limited / No service
- **Access Technology Change** — 13 типов RAT
- **Network Rejection** — полная адаптивная форма: тип регистрации (LU / GPRS / EPS / 5GS), поля локации (MCC, MNC, LAC, RAC, TAC), доступные технологии, 53-позиционный выпадающий список причин отказа (EMM, GMM, 5GMM, LU)
**Proactive Command Log** — хронологический список проактивных команд. Каждая строка показывает время, код типа, имя и декодированный квалификатор.
**PLI Data Dictionary** — редактируемые hex-значения для всех 22 квалификаторов PROVIDE LOCAL INFORMATION (TS 102 223 + TS 131 111). 10 квалификаторов имеют встроенные формы декодирования/кодирования:
| Код | Декодированные поля |
|------|--------------|
| 00 | MCC, MNC, LAC/TAC |
| 01 | IMEI (15 цифр) |
| 03 | Дата, время, TZ |
| 04 | Язык (2-символьный код) |
| 05 | ME Status, Timing Advance |
| 06 | Access Technology (выпадающий список) |
| 08 | IMEISV (16 цифр) |
| 09 | Search Mode (Auto/Manual) |
| 0A | Battery charge (%) |
| 0E | Multiple Access Technologies (список через запятую) |
Значения сохраняются на сервере до перезапуска. Apply → hex обновляется; Save → POST на сервер.
### Подсказки команд
Введите имя команды в **pySim command line**. Подсказки по использованию появляются через 300 мс. Автодополнение команд — над полем ввода.
---
@@ -452,35 +516,6 @@ PWA проверяет версию сервера при подключении
---
## Card Reader (интеграция с pySim)
Подключение к встроенному [`pysim-otaman-server`](pysim_otaman_server/) для работы с картой.
> **Ограничение браузера:** если PWA раздаётся с публичного HTTPS-хоста, для доступа к локальному серверу (`http://127.0.0.1:8080`) нужны два условия: сервер должен отправлять `Access-Control-Allow-Private-Network: true` (pysim-otaman-server ≥ 1.6.1 делает это автоматически), и браузеру должно быть разрешено обращаться к локальной сети — в Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети → разрешить сайт (или подтвердить запрос). Без разрешения браузера запрос к `127.0.0.1` блокируется ещё до отправки preflight.
### Файловый менеджер
Дерево файлов UICC. Отображаются имена, FID и AID (для ADF). Клик для чтения содержимого.
- **Read** — чтение файла (автоопределение transparent/record)
- **Edit** — режим редактирования, измените hex-данные и нажмите **Save** для записи
- **Raw / Decoded** — переключение между hex-дампом и декодированным JSON
### Пользовательские файлы
Файлы, отсутствующие в модели pysim, можно добавить вручную:
1. Перейдите на вкладку **Custom files**
2. Введите путь (например, `3F00/6F46`) и псевдоним (например, `EF.SPN`)
3. Нажмите **Add** — файл появится в дереве курсивом (непроверенный)
4. Кликните для проверки существования — при успехе работает как обычный файл
Пользовательские файлы сохраняются в `localStorage`. Экспорт/импорт в JSON для обмена.
### Подсказки команд
Введите имя команды в **pySim command line**. Подсказки по использованию появляются через 300 мс. Автодополнение команд — над полем ввода.
## Сервер (pysim-otaman-server)
Встроенный Python-сервер оборачивает [pySim](https://osmocom.org/projects/pysim/wiki) и раздаёт как PWA (из `frontend/`), так и JSON API по `/api/*`.
@@ -531,4 +566,4 @@ pysim-otaman-server --http-port 8080
### Справочник API
Полный справочник endpoints: [docs/api.md](docs/api.md).
Полный справочник endpoints: [docs/api.md](docs/api.md).
+63 -34
View File
@@ -201,9 +201,12 @@
<section class="mb-10">
<h2 id="secured-packet" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">3. Вкладка SCP80 — Secured Packet</h2>
<p class="mb-3">Верхнеуровневая вкладка <strong>SCP80</strong> объединяет разделы, связанные с SCP80. Переключение — двумя переключателями: <strong>Secured Packet</strong> (этот раздел) и <strong>Cards</strong> (раздел 5). Собирает защищённые пакеты SCP80 по ETSI TS 102 225.</p>
<h3 id="packet-structure" class="text-lg font-medium mb-2">Структура пакета</h3>
<h2 id="scp80" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">3. Вкладка SCP80</h2>
<p class="mb-3">Верхнеуровневая вкладка <strong>SCP80</strong> объединяет разделы, связанные с SCP80. Переключение — тремя переключателями: <strong>Secured Packet</strong>, <strong>Cards</strong> и <strong>RAM</strong>. Собирает защищённые пакеты SCP80 по ETSI TS 102 225.</p>
<h3 id="secured-packet" class="text-lg font-medium mb-2">3.1 Secured Packet</h3>
<p class="mb-2">Собирает защищённые пакеты SCP80 по ETSI TS 102 225.</p>
<h4 id="packet-structure" class="font-medium mb-1">Структура пакета</h4>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Поле</th><th class="text-left py-1 px-2">Размер</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
<tbody>
@@ -221,7 +224,7 @@
<tr><td class="py-1 px-2 font-mono">Secured Data</td><td class="py-1 px-2">пер.</td><td class="py-1 px-2">APDU (с шифрованием при необходимости)</td></tr>
</tbody>
</table>
<h3 id="packet-crypto" class="text-lg font-medium mb-2">Крипто</h3>
<h4 id="packet-crypto" class="font-medium mb-1">Крипто</h4>
<ul class="list-disc list-inside text-sm space-y-1">
<li><strong>3DES-CBC</strong> шифрование (нулевой ICV), ключи 8/16/24 байта &mdash; устарело с Rel-18, но поддерживается для обратной совместимости</li>
<li><strong>AES-CBC</strong> шифрование (нулевой ICV, дополнение нулями до 16), ключи 16/24/32 байта (TS 102 225 &sect;5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
@@ -232,20 +235,46 @@
</ul>
<p class="text-sm mb-3">Кнопка &laquo;Verify vs pySim&raquo; сверяет собранный пакет с эталонной реализацией <code class="font-mono text-sm">OtaDialectSms.encode_cmd</code>. Кнопка &laquo;Send to Card&raquo; доставляет пакет через ENVELOPE SMS-PP-DOWNLOAD (при подключении к серверу).</p>
<h3 id="cards" class="text-lg font-medium mb-2">3.2 Cards</h3>
<p class="mb-2">Хранит предустановки карт локально в браузере (<code class="font-mono text-sm">localStorage</code>), чтобы представление Secured Packet могло автоматически подставлять ключи и параметры.</p>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Поле</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
<tbody>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Name</td><td class="py-1 px-2">Понятная метка</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">ICCID</td><td class="py-1 px-2">Опциональный идентификатор карты</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">KIc / KID</td><td class="py-1 px-2">Индикаторы ключа и алгоритма (например, 15 = индекс 1, 3DES-CBC2; x2 = AES)</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">SPI1 / SPI2</td><td class="py-1 px-2">Security Parameter Indicators</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">TAR</td><td class="py-1 px-2">Toolkit Application Reference</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Counter</td><td class="py-1 px-2">Счётчик повторов (5 байт)</td></tr>
<tr><td class="py-1 px-2">KIc key / KID key</td><td class="py-1 px-2">16/24/32 hex-символа (ключи 8/16/24 байта 3DES) или 32/48/64 hex-символа (ключи 16/24/32 байта AES)</td></tr>
</tbody>
</table>
<p class="text-sm mb-3"><strong>Export as JSON</strong> / <strong>Import JSON from clipboard</strong> для обмена предустановками. Выбранная предустановка автоматически заполняет форму Secured Packet.</p>
<h3 id="ram" class="text-lg font-medium mb-2">3.3 RAM</h3>
<p class="mb-2">Выполняет операции удалённого управления приложениями (Remote Application Management) как защищённые пакеты SCP80 через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES). Предустановка карты из подвкладки <strong>Cards</strong> обеспечивает SPI, ключи, TAR и счётчик.</p>
<h4 id="ram-operations" class="font-medium mb-1">Операции</h4>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Операция</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
<tbody>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Explore Card (all GP data)</td><td class="py-1 px-2">Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 для информации о памяти. Результаты отображаются в обзоре с кнопками <strong>Delete</strong> для каждого элемента.</td></tr>
<tr><td class="py-1 px-2">Install Package (.cap file)</td><td class="py-1 px-2">Отправка <code class="font-mono text-sm">.cap</code> файла на карту через сервер: INSTALL[for load] &rarr; LOAD &times;N &rarr; INSTALL[for install (+make selectable)].</td></tr>
</tbody>
</table>
<h4 id="ram-explorer" class="font-medium mb-1">Обзор карты (Explorer View)</h4>
<p class="text-sm mb-2">После выполнения &laquo;Explore Card&raquo; отображается:</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>ISD</strong> &mdash; AID, жизненный цикл, привилегии (без удаления; ISD нельзя удалить)</li>
<li><strong>Приложения</strong> &mdash; AID, жизненный цикл, привилегии, связанный ELF/SD. Каждое имеет кнопку <strong>Delete</strong> (GP <code class="font-mono text-sm">DELETE</code> по AID).</li>
<li><strong>Executable Load Files</strong> &mdash; AID, жизненный цикл, версии, AID модулей. Каждый имеет <strong>Delete</strong> (только ELF) и <strong>Delete All</strong> (каскадное: ELF + модули + установленные приложения, P2=<code class="font-mono text-sm">0x80</code>).</li>
</ul>
<p class="text-sm mb-3">Удаление подтверждается через диалог браузера перед отправкой команды GP <code class="font-mono text-sm">DELETE</code> через SCP80. Обзор автоматически обновляется после успешного удаления.</p>
<section class="mb-10">
<h2 id="response-parser" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">4. Вкладка Response parser</h2>
<p class="mb-3">Декодирование ответа команды: выберите отправленную команду, введите SW (например, <code class="font-mono text-sm">9000</code>) и данные ответа в hex, затем нажмите <strong>Decode</strong>.</p>
<ul class="list-disc list-inside text-sm space-y-1">
<li><strong>Команда</strong> — группа SIM/USIM (SELECT, STATUS, READ/UPDATE, операции с PIN, CAT-команды TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, &hellip;) или группа RAM/GP (INSTALL, LOAD, DELETE, GET/STORE DATA, аутентификация, команды SCP).</li>
<li><strong>Декодирование SW</strong> — статусные слова по картам generic, UICC (TS 102 221) и GlobalPlatform с автоопределением контекста.</li>
<li><strong>Декодирование привилегий</strong> — байты привилегий из ответов GET DATA / INSTALL в читаемые флаги.</li>
<li><strong>Данные ответа</strong> — hex с интерпретацией по команде (например, шаблоны FCP из SELECT).</li>
</ul>
<section class="mb-10">
<h2 id="cards" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">5. Вкладка SCP80 — Cards</h2>
<p class="mb-3">Второй переключатель вкладки <strong>SCP80</strong>. Хранит предустановки карт локально в браузере (<code class="font-mono text-sm">localStorage</code>), чтобы представление Secured Packet могло автоматически подставлять ключи и параметры.</p>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Поле</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
@@ -263,29 +292,29 @@
<section class="mb-10">
<h2 id="card-reader" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">6. Вкладка Card reader (pySim)</h2>
<h2 id="card-reader" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">5. Вкладка Card reader (pySim)</h2>
<p class="mb-3">Подключение к локальному <a href="https://github.com/anttro/otaman" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-otaman-server</a> для работы с картой. Подвкладки: <strong>File manager</strong>, <strong>Custom files</strong>, <strong>pySim command line</strong>, <strong>Raw APDU</strong> и <strong>Proactive UICC</strong>.</p>
<h3 id="file-manager" class="text-lg font-medium mb-2">6.1 File manager</h3>
<h3 id="file-manager" class="text-lg font-medium mb-2">5.1 File manager</h3>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>Read</strong> — чтение файла (автоопределение transparent/record)</li>
<li><strong>Edit</strong> — изменить hex-данные, <strong>Save</strong> для записи</li>
<li><strong>Raw / Decoded</strong> — переключение между hex-дампом и декодированным JSON</li>
</ul>
<h3 id="custom-files" class="text-lg font-medium mb-2">6.2 Custom files</h3>
<h3 id="custom-files" class="text-lg font-medium mb-2">5.2 Custom files</h3>
<p class="text-sm mb-3">Добавление файлов, не покрытых моделью pySim. Сохраняется в <code class="font-mono text-sm">localStorage</code>; экспорт/импорт JSON.</p>
<h3 id="pysim-cmdline" class="text-lg font-medium mb-2">6.3 pySim command line</h3>
<h3 id="pysim-cmdline" class="text-lg font-medium mb-2">5.3 pySim command line</h3>
<p class="text-sm mb-3">Выполнение любых команд pySim-shell с подсказками (300&nbsp;мс) и автодополнением.</p>
<h3 id="raw-apdu" class="text-lg font-medium mb-2">6.4 Raw APDU</h3>
<h3 id="raw-apdu" class="text-lg font-medium mb-2">5.4 Raw APDU</h3>
<p class="text-sm mb-3">Отправка произвольного APDU и просмотр ответа.</p>
<h3 id="proactive-uicc" class="text-lg font-medium mb-2">6.5 Proactive UICC</h3>
<h3 id="proactive-uicc" class="text-lg font-medium mb-2">5.5 Proactive UICC</h3>
<p class="text-sm mb-3">Работа с сессией Card Application Toolkit: подписанные события, журнал проактивных команд, словарь данных PROVIDE LOCAL INFORMATION и опрос STATUS.</p>
<h4 id="subscribed-events" class="font-medium mb-1">6.5.1 Подписанные события (SET UP EVENT LIST)</h4>
<h4 id="subscribed-events" class="font-medium mb-1">5.5.1 Подписанные события (SET UP EVENT LIST)</h4>
<p class="text-sm mb-2">События, которые отслеживает карта. У каждого события есть кнопка <strong>Send</strong>, открывающая форму, специфичную для типа события:</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>События без данных</strong> (User Activity, Idle Screen, Data Available, &hellip;) — уведомление в один клик</li>
@@ -295,10 +324,10 @@
</ul>
<p class="text-sm mb-3">Отправка события использует <code class="font-mono text-sm">ENVELOPE(Event Download)</code> по TS 102 223 / TS 131 111.</p>
<h4 id="proactive-log" class="font-medium mb-1">6.5.2 Журнал проактивных команд</h4>
<h4 id="proactive-log" class="font-medium mb-1">5.5.2 Журнал проактивных команд</h4>
<p class="text-sm mb-2">Хронологический список извлечённых проактивных команд. Каждая строка показывает время, код типа, имя и декодированный квалификатор (для команд, у которых он есть). Для команд с данными ответа показывается строка <code class="font-mono text-sm">Response:</code> с байтами TERMINAL RESPONSE (без служебных TLV); ответы PROVIDE LOCAL INFORMATION декодируются через словарь данных PLI.</p>
<h4 id="pli-dict" class="font-medium mb-1">6.5.3 Словарь данных PROVIDE LOCAL INFORMATION</h4>
<h4 id="pli-dict" class="font-medium mb-1">5.5.3 Словарь данных PROVIDE LOCAL INFORMATION</h4>
<p class="text-sm mb-2">Редактируемые hex-значения для всех 22 квалификаторов PLI (TS 102 223 &sect;8.6 + TS 131 111). У десяти квалификаторов есть встроенные формы декодирования/кодирования:</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>00</strong> Location Info (MCC, MNC, LAC/TAC, Cell ID)</li>
@@ -308,10 +337,10 @@
</ul>
<p class="text-sm mb-3">Значения хранятся на сервере до перезапуска. Когда карта выдаёт PLI, сервер вставляет значения словаря в TERMINAL RESPONSE.</p>
<h4 id="status-polling" class="font-medium mb-1">6.5.4 Опрос STATUS</h4>
<h4 id="status-polling" class="font-medium mb-1">5.5.4 Опрос STATUS</h4>
<p class="text-sm mb-3">Кнопка <strong>Send STATUS</strong> отправляет STATUS (F2) вручную. Переключатель <strong>Polling</strong> включает фоновый опрос: после настраиваемого интервала бездействия (аргумент сервера <code class="font-mono text-sm">--poll-interval</code>, 1&ndash;255&nbsp;с, по умолчанию 30&nbsp;с) сервер отправляет STATUS и обрабатывает любую ожидающую проактивную команду. При извлечении карты опрос останавливается, а состояние карты сбрасывается.</p>
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">6.6 Сценарии использования</h3>
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">5.6 Сценарии использования</h3>
<h4 id="scenario-a" class="font-medium mb-1">Сценарий A &mdash; Работа с файлами, не входящими в модель pySim (Custom files)</h4>
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
@@ -349,10 +378,10 @@
<section class="mb-10">
<h2 id="server" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">7. Установка сервера</h2>
<h2 id="server" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">6. Установка сервера</h2>
<p class="mb-3">Для работы с картой (вкладка Card reader, Proactive UICC, доставка OTA) нужен локальный <a href="https://github.com/anttro/otaman" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-otaman-server</a> — встроенный в OTAMan HTTP-сервер, оборачивающий pySim, работающий с ридером через PC/SC или serial и раздающий сам PWA (откройте <code class="font-mono text-sm">http://127.0.0.1:8080</code>).</p>
<h3 id="prerequisites" class="text-lg font-medium mb-2">7.1 Требования</h3>
<h3 id="prerequisites" class="text-lg font-medium mb-2">6.1 Требования</h3>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>Python 3.8+</strong> с <code class="font-mono text-sm">pip</code></li>
<li><strong>Git</strong></li>
@@ -360,20 +389,20 @@
<li><strong>Только Windows</strong> — используйте <strong>Python 3.10&ndash;3.13</strong> (рекомендуется 3.13): <code class="font-mono text-sm">pyscard</code> (обёртка драйвера PC/SC) поставляет готовые wheels для этих версий. На Python 3.9 / 3.14 pip собирает <code class="font-mono text-sm">pyscard</code> из исходников, для чего требуются Microsoft C++ Build Tools (&laquo;Desktop development with C++&raquo;). Мост SMPP (<code class="font-mono text-sm">smpp.twisted3</code>) на Windows намеренно не устанавливается, поэтому для Python 3.10&ndash;3.13 C++ Build Tools не нужны.</li>
</ul>
<h3 id="quickstart-linux" class="text-lg font-medium mb-2">7.2 Быстрый старт — Linux / macOS</h3>
<h3 id="quickstart-linux" class="text-lg font-medium mb-2">6.2 Быстрый старт — Linux / macOS</h3>
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/otaman.git
cd otaman
chmod +x setup.sh start.sh
./setup.sh # создаёт .venv, устанавливает pysim + сервер (однократно)
./start.sh # запускает сервер (PWA + API, автоопределение ридера)</pre>
<h3 id="quickstart-windows" class="text-lg font-medium mb-2">7.3 Быстрый старт — Windows</h3>
<h3 id="quickstart-windows" class="text-lg font-medium mb-2">6.3 Быстрый старт — Windows</h3>
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/otaman.git
cd otaman
setup.bat # создаёт .venv, устанавливает pysim + сервер (однократно)
start.bat # запускает сервер (PWA + API)</pre>
<h3 id="helper-scripts" class="text-lg font-medium mb-2">7.4 Вспомогательные скрипты</h3>
<h3 id="helper-scripts" class="text-lg font-medium mb-2">6.4 Вспомогательные скрипты</h3>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Скрипт</th><th class="text-left py-1 px-2">Назначение</th></tr></thead>
<tbody>
@@ -382,7 +411,7 @@ start.bat # запускает сервер (PWA + API)</pre>
</tbody>
</table>
<h3 id="reader-autodetect" class="text-lg font-medium mb-2">7.5 Автоопределение ридера (<code class="font-mono text-sm">start.sh</code>)</h3>
<h3 id="reader-autodetect" class="text-lg font-medium mb-2">6.5 Автоопределение ридера (<code class="font-mono text-sm">start.sh</code>)</h3>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>PC/SC (Linux)</strong> — если запущен демон <code class="font-mono text-sm">pcscd</code>, передаёт <code class="font-mono text-sm">-p 0</code></li>
<li><strong>Serial (Linux)</strong> — если существует <code class="font-mono text-sm">/dev/ttyUSB0</code>, передаёт <code class="font-mono text-sm">-d /dev/ttyUSB0</code></li>
@@ -390,7 +419,7 @@ start.bat # запускает сервер (PWA + API)</pre>
</ul>
<p class="text-sm mb-3">Если ридер не обнаружен, сервер запускается без аргументов и показывает &laquo;Reader: none&raquo;. Карту можно инициализировать позже кнопкой <strong>Equip</strong> на вкладке Card reader.</p>
<h3 id="manual-install" class="text-lg font-medium mb-2">7.6 Ручная установка</h3>
<h3 id="manual-install" class="text-lg font-medium mb-2">6.6 Ручная установка</h3>
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3"># Создать и активировать venv
python3 -m venv .venv
source .venv/bin/activate # Linux/macOS
@@ -409,7 +438,7 @@ pysim-otaman-server --http-port 8080</pre>
<section class="mb-10">
<h2 id="compatibility" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">8. Совместимость версий</h2>
<h2 id="compatibility" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">7. Совместимость версий</h2>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">PWA (OTAMan)</th><th class="text-left py-1 px-2">Сервер</th><th class="text-left py-1 px-2">Статус</th></tr></thead>
<tbody>
+60 -38
View File
@@ -201,9 +201,12 @@
<section class="mb-10">
<h2 id="secured-packet" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">3. SCP80 tab — Secured Packet</h2>
<p class="mb-3">The <strong>SCP80</strong> top-level tab groups the SCP80-related views. It is switched by two pills: <strong>Secured Packet</strong> (this section) and <strong>Cards</strong> (section 5). Assembles SCP80 secured packets per ETSI TS 102 225.</p>
<h3 id="packet-structure" class="text-lg font-medium mb-2">Packet structure</h3>
<h2 id="scp80" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">3. SCP80 tab</h2>
<p class="mb-3">The <strong>SCP80</strong> top-level tab groups the SCP80-related views. It is switched by three pills: <strong>Secured Packet</strong>, <strong>Cards</strong>, and <strong>RAM</strong>. Assembles SCP80 secured packets per ETSI TS 102 225.</p>
<h3 id="secured-packet" class="text-lg font-medium mb-2">3.1 Secured Packet</h3>
<p class="mb-2">Builds SCP80 secured packets per ETSI TS 102 225.</p>
<h4 id="packet-structure" class="font-medium mb-1">Packet structure</h4>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Field</th><th class="text-left py-1 px-2">Size</th><th class="text-left py-1 px-2">Description</th></tr></thead>
<tbody>
@@ -221,7 +224,7 @@
<tr><td class="py-1 px-2 font-mono">Secured Data</td><td class="py-1 px-2">var.</td><td class="py-1 px-2">Padded APDU (encrypted if required)</td></tr>
</tbody>
</table>
<h3 id="packet-crypto" class="text-lg font-medium mb-2">Crypto</h3>
<h4 id="packet-crypto" class="font-medium mb-1">Crypto</h4>
<ul class="list-disc list-inside text-sm space-y-1">
<li><strong>3DES-CBC</strong> encryption (zero ICV), 8/16/24-byte keys &mdash; deprecated since Rel-18, still supported for backwards compatibility</li>
<li><strong>AES-CBC</strong> encryption (zero ICV, zero-padded to 16), 16/24/32-byte keys (TS 102 225 &sect;5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
@@ -232,21 +235,8 @@
</ul>
<p class="text-sm mb-3">A &ldquo;Verify vs pySim&rdquo; button cross-checks the assembled packet against pySim&rsquo;s reference <code class="font-mono text-sm">OtaDialectSms.encode_cmd</code>. A &ldquo;Send to Card&rdquo; button delivers it via SMS-PP-DOWNLOAD ENVELOPE (when connected to the server).</p>
<section class="mb-10">
<h2 id="response-parser" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">4. Response parser tab</h2>
<p class="mb-3">Decodes a raw command response: pick the command that was sent, enter the SW (e.g. <code class="font-mono text-sm">9000</code>) and the response data hex, then press <strong>Decode</strong>.</p>
<ul class="list-disc list-inside text-sm space-y-1">
<li><strong>Command</strong> — SIM/USIM group (SELECT, STATUS, READ/UPDATE, PIN ops, CAT commands like TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, &hellip;) or RAM/GP group (INSTALL, LOAD, DELETE, GET/STORE DATA, auth, SCP commands).</li>
<li><strong>SW decode</strong> — status words resolved against generic, UICC (TS 102 221), and GlobalPlatform maps, with context auto-detected.</li>
<li><strong>Privilege decode</strong> — GET DATA / INSTALL response payloads decode the privilege bytes into human-readable flags.</li>
<li><strong>Response data</strong> — raw hex rendered and interpreted per command (e.g. SELECT FCP templates).</li>
</ul>
<section class="mb-10">
<h2 id="cards" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">5. SCP80 tab — Cards</h2>
<p class="mb-3">The second pill of the <strong>SCP80</strong> tab. Stores card presets locally in the browser (<code class="font-mono text-sm">localStorage</code>) so the Secured Packet view can auto-fill keys and parameters.</p>
<h3 id="cards" class="text-lg font-medium mb-2">3.2 Cards</h3>
<p class="mb-2">Stores card presets locally in the browser (<code class="font-mono text-sm">localStorage</code>) so the Secured Packet view can auto-fill keys and parameters.</p>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Field</th><th class="text-left py-1 px-2">Description</th></tr></thead>
<tbody>
@@ -261,31 +251,63 @@
</table>
<p class="text-sm mb-3"><strong>Export as JSON</strong> / <strong>Import JSON from clipboard</strong> share presets. The selected card preset auto-fills the Secured Packet form.</p>
<h3 id="ram" class="text-lg font-medium mb-2">3.3 RAM</h3>
<p class="mb-2">Delivers Remote Application Management operations as SCP80 secured packets via SMS-PP-DOWNLOAD ENVELOPE. The card must support SCP03 (AES or 3DES). A saved card preset from the <strong>Cards</strong> sub-tab provides the SPI, keys, TAR, and counter.</p>
<h4 id="ram-operations" class="font-medium mb-1">Operations</h4>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Operation</th><th class="text-left py-1 px-2">Description</th></tr></thead>
<tbody>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Explore Card (all GP data)</td><td class="py-1 px-2">Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 for memory info. Results appear in an explorer view with per-item <strong>Delete</strong> buttons.</td></tr>
<tr><td class="py-1 px-2">Install Package (.cap file)</td><td class="py-1 px-2">Sends a <code class="font-mono text-sm">.cap</code> file to the card via the server: INSTALL[for load] &rarr; LOAD &times;N &rarr; INSTALL[for install (+make selectable)].</td></tr>
</tbody>
</table>
<h4 id="ram-explorer" class="font-medium mb-1">Explorer View</h4>
<p class="text-sm mb-2">After &ldquo;Explore Card&rdquo; runs, the explorer displays:</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>ISD</strong> &mdash; AID, lifecycle, privileges (no delete; the ISD cannot be removed)</li>
<li><strong>Applications</strong> &mdash; AID, lifecycle, privileges, associated ELF/SD. Each has a <strong>Delete</strong> button (GP <code class="font-mono text-sm">DELETE</code> by AID).</li>
<li><strong>Executable Load Files</strong> &mdash; AID, lifecycle, version, module AIDs. Each has <strong>Delete</strong> (ELF only) and <strong>Delete All</strong> (cascade: ELF + modules + installed Applications, P2=<code class="font-mono text-sm">0x80</code>) buttons.</li>
</ul>
<p class="text-sm mb-3">Delete confirms via a browser prompt before sending the GP <code class="font-mono text-sm">DELETE</code> command via SCP80. The explorer auto-refreshes after a successful deletion.</p>
<section class="mb-10">
<h2 id="card-reader" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">6. Card reader (pySim) tab</h2>
<h2 id="response-parser" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">4. Response parser tab</h2>
<p class="mb-3">Decodes a raw command response: pick the command that was sent, enter the SW (e.g. <code class="font-mono text-sm">9000</code>) and the response data hex, then press <strong>Decode</strong>.</p>
<ul class="list-disc list-inside text-sm space-y-1">
<li><strong>Command</strong> — SIM/USIM group (SELECT, STATUS, READ/UPDATE, PIN ops, CAT commands like TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, &hellip;) or RAM/GP group (INSTALL, LOAD, DELETE, GET/STORE DATA, auth, SCP commands).</li>
<li><strong>SW decode</strong> — status words resolved against generic, UICC (TS 102 221), and GlobalPlatform maps, with context auto-detected.</li>
<li><strong>Privilege decode</strong> — GET DATA / INSTALL response payloads decode the privilege bytes into human-readable flags.</li>
<li><strong>Response data</strong> — raw hex rendered and interpreted per command (e.g. SELECT FCP templates).</li>
</ul>
<section class="mb-10">
<h2 id="card-reader" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">5. Card reader (pySim) tab</h2>
<p class="mb-3">Connects to a local <a href="https://github.com/anttro/otaman" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-otaman-server</a> for live card operations. Sub-tabs: <strong>File manager</strong>, <strong>Custom files</strong>, <strong>pySim command line</strong>, <strong>Raw APDU</strong>, and <strong>Proactive UICC</strong>.</p>
<h3 id="file-manager" class="text-lg font-medium mb-2">6.1 File manager</h3>
<h3 id="file-manager" class="text-lg font-medium mb-2">5.1 File manager</h3>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>Read</strong> — reads the selected file (auto-detects transparent vs record files)</li>
<li><strong>Edit</strong> — modify hex data, <strong>Save</strong> to write back</li>
<li><strong>Raw / Decoded</strong> — toggle between hex dump and pySim-decoded JSON</li>
</ul>
<h3 id="custom-files" class="text-lg font-medium mb-2">6.2 Custom files</h3>
<h3 id="custom-files" class="text-lg font-medium mb-2">5.2 Custom files</h3>
<p class="text-sm mb-3">Add files that pySim&rsquo;s model does not cover. Persists in <code class="font-mono text-sm">localStorage</code>; JSON export/import.</p>
<h3 id="pysim-cmdline" class="text-lg font-medium mb-2">6.3 pySim command line</h3>
<h3 id="pysim-cmdline" class="text-lg font-medium mb-2">5.3 pySim command line</h3>
<p class="text-sm mb-3">Execute any pySim-shell command with usage hints (300&nbsp;ms) and autocomplete.</p>
<h3 id="raw-apdu" class="text-lg font-medium mb-2">6.4 Raw APDU</h3>
<h3 id="raw-apdu" class="text-lg font-medium mb-2">5.4 Raw APDU</h3>
<p class="text-sm mb-3">Send an arbitrary APDU and view the raw response.</p>
<h3 id="proactive-uicc" class="text-lg font-medium mb-2">6.5 Proactive UICC</h3>
<h3 id="proactive-uicc" class="text-lg font-medium mb-2">5.5 Proactive UICC</h3>
<p class="text-sm mb-3">Interacts with the Card Application Toolkit session: subscribed events, the proactive command log, the PROVIDE LOCAL INFORMATION data dictionary, and STATUS polling.</p>
<h4 id="subscribed-events" class="font-medium mb-1">6.5.1 Subscribed events (SET UP EVENT LIST)</h4>
<h4 id="subscribed-events" class="font-medium mb-1">5.5.1 Subscribed events (SET UP EVENT LIST)</h4>
<p class="text-sm mb-2">The events the card monitors. Each event has a <strong>Send</strong> button that opens a form specific to the event type:</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>No-data events</strong> (User Activity, Idle Screen, Data Available, &hellip;) — one-click notification</li>
@@ -295,10 +317,10 @@
</ul>
<p class="text-sm mb-3">Sending an event uses <code class="font-mono text-sm">ENVELOPE(Event Download)</code> per TS 102 223 / TS 131 111.</p>
<h4 id="proactive-log" class="font-medium mb-1">6.5.2 Proactive command log</h4>
<h4 id="proactive-log" class="font-medium mb-1">5.5.2 Proactive command log</h4>
<p class="text-sm mb-2">Chronological list of fetched proactive commands. Each row shows the elapsed time, type code, name, and a decoded qualifier (for commands that have one). Commands with response data show a <code class="font-mono text-sm">Response:</code> line with the TERMINAL RESPONSE bytes (boilerplate TLVs stripped); PROVIDE LOCAL INFORMATION responses are decoded using the PLI data dictionary decoders.</p>
<h4 id="pli-dict" class="font-medium mb-1">6.5.3 PROVIDE LOCAL INFORMATION data dictionary</h4>
<h4 id="pli-dict" class="font-medium mb-1">5.5.3 PROVIDE LOCAL INFORMATION data dictionary</h4>
<p class="text-sm mb-2">Editable hex values for all 22 PLI qualifiers (TS 102 223 &sect;8.6 + TS 131 111). Ten qualifiers have inline decode/encode forms:</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>00</strong> Location Info (MCC, MNC, LAC/TAC, Cell ID)</li>
@@ -308,10 +330,10 @@
</ul>
<p class="text-sm mb-3">Values persist server-side until restart. When the card issues PLI, the server injects the dictionary values into the TERMINAL RESPONSE.</p>
<h4 id="status-polling" class="font-medium mb-1">6.5.4 STATUS polling</h4>
<h4 id="status-polling" class="font-medium mb-1">5.5.4 STATUS polling</h4>
<p class="text-sm mb-3">A <strong>Send STATUS</strong> button issues a manual STATUS (F2). A <strong>Polling</strong> toggle enables background polling: after a configurable idle interval (server CLI <code class="font-mono text-sm">--poll-interval</code>, 1&ndash;255&nbsp;s, default 30&nbsp;s) the server sends STATUS and handles any pending proactive command. Polling stops and card state resets if the card is removed.</p>
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">6.6 Usage scenarios</h3>
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">5.6 Usage scenarios</h3>
<h4 id="scenario-a" class="font-medium mb-1">Scenario A &mdash; Working with files not in pySim&rsquo;s model (Custom files)</h4>
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
@@ -349,10 +371,10 @@
<section class="mb-10">
<h2 id="server" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">7. Server installation</h2>
<h2 id="server" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">6. Server installation</h2>
<p class="mb-3">Live card operations (Card reader tab, Proactive UICC, OTA delivery) require the local <a href="https://github.com/anttro/otaman" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-otaman-server</a> — a small HTTP server bundled with OTAMan that wraps pySim, talks to the reader over PC/SC or serial, and also serves the PWA itself (open <code class="font-mono text-sm">http://127.0.0.1:8080</code>).</p>
<h3 id="prerequisites" class="text-lg font-medium mb-2">7.1 Prerequisites</h3>
<h3 id="prerequisites" class="text-lg font-medium mb-2">6.1 Prerequisites</h3>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>Python 3.8+</strong> with <code class="font-mono text-sm">pip</code></li>
<li><strong>Git</strong></li>
@@ -360,20 +382,20 @@
<li><strong>Windows only</strong> — use <strong>Python 3.10&ndash;3.13</strong> (3.13 recommended): <code class="font-mono text-sm">pyscard</code> (the PC/SC driver wrapper) ships precompiled wheels for these versions. On Python 3.9 / 3.14 pip builds <code class="font-mono text-sm">pyscard</code> from source, which requires Microsoft C++ Build Tools (&ldquo;Desktop development with C++&rdquo;). The SMPP bridge (<code class="font-mono text-sm">smpp.twisted3</code>) is intentionally not installed on Windows, so no C++ Build Tools are needed for Python 3.10&ndash;3.13.</li>
</ul>
<h3 id="quickstart-linux" class="text-lg font-medium mb-2">7.2 Quick start — Linux / macOS</h3>
<h3 id="quickstart-linux" class="text-lg font-medium mb-2">6.2 Quick start — Linux / macOS</h3>
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/otaman.git
cd otaman
chmod +x setup.sh start.sh
./setup.sh # creates .venv, installs pysim + server (run once)
./start.sh # starts the server (serves PWA + API, auto-detects reader)</pre>
<h3 id="quickstart-windows" class="text-lg font-medium mb-2">7.3 Quick start — Windows</h3>
<h3 id="quickstart-windows" class="text-lg font-medium mb-2">6.3 Quick start — Windows</h3>
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/otaman.git
cd otaman
setup.bat # creates .venv, installs pysim + server (run once)
start.bat # starts the server (serves PWA + API)</pre>
<h3 id="helper-scripts" class="text-lg font-medium mb-2">7.4 Helper scripts</h3>
<h3 id="helper-scripts" class="text-lg font-medium mb-2">6.4 Helper scripts</h3>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Script</th><th class="text-left py-1 px-2">Purpose</th></tr></thead>
<tbody>
@@ -382,7 +404,7 @@ start.bat # starts the server (serves PWA + API)</pre>
</tbody>
</table>
<h3 id="reader-autodetect" class="text-lg font-medium mb-2">7.5 Reader auto-detection (<code class="font-mono text-sm">start.sh</code>)</h3>
<h3 id="reader-autodetect" class="text-lg font-medium mb-2">6.5 Reader auto-detection (<code class="font-mono text-sm">start.sh</code>)</h3>
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>PC/SC (Linux)</strong> — if the <code class="font-mono text-sm">pcscd</code> daemon is running, passes <code class="font-mono text-sm">-p 0</code></li>
<li><strong>Serial (Linux)</strong> — if <code class="font-mono text-sm">/dev/ttyUSB0</code> exists, passes <code class="font-mono text-sm">-d /dev/ttyUSB0</code></li>
@@ -390,7 +412,7 @@ start.bat # starts the server (serves PWA + API)</pre>
</ul>
<p class="text-sm mb-3">If no reader is detected, the server starts without reader arguments and shows &ldquo;Reader: none&rdquo;. The card can be initialized later via the <strong>Equip</strong> button in the Card reader tab.</p>
<h3 id="manual-install" class="text-lg font-medium mb-2">7.6 Manual installation</h3>
<h3 id="manual-install" class="text-lg font-medium mb-2">6.6 Manual installation</h3>
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3"># Create and activate a venv
python3 -m venv .venv
source .venv/bin/activate # Linux/macOS
@@ -409,7 +431,7 @@ pysim-otaman-server --http-port 8080</pre>
<section class="mb-10">
<h2 id="compatibility" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">8. Version compatibility</h2>
<h2 id="compatibility" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">7. Version compatibility</h2>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">PWA (OTAMan)</th><th class="text-left py-1 px-2">Server</th><th class="text-left py-1 px-2">Status</th></tr></thead>
<tbody>
+232 -18
View File
@@ -18,7 +18,7 @@
<div class="max-w-7xl mx-auto px-6 py-2">
<div class="flex items-center justify-between mb-3">
<h1 class="text-2xl font-bold text-heading">OTAMan <span id="slogan" class="text-sm font-normal text-gray-500 dark:text-slate-400 ml-2" data-l10n="SIM OTA with a Human Face">SIM OTA with a Human Face</span> <span class="text-xs text-gray-400 dark:text-slate-500 ml-1">v1.9.19</span></h1>
<h1 class="text-2xl font-bold text-heading">OTAMan <span id="slogan" class="text-sm font-normal text-gray-500 dark:text-slate-400 ml-2" data-l10n="SIM OTA with a Human Face">SIM OTA with a Human Face</span> <span class="text-xs text-gray-400 dark:text-slate-500 ml-1">v1.9.21</span></h1>
<div class="flex items-center gap-4">
<button id="install-btn" class="px-2 py-1 text-xs rounded border border-gray-300 dark:border-slate-600 hover:bg-gray-200 dark:hover:bg-slate-700" style="display:none">INSTALL PWA [for offline use]</button>
<a href="https://github.com/anttro/otaman" target="_blank" class="text-xs text-gray-400 hover:text-gray-600 dark:text-slate-500 dark:hover:text-slate-300">github</a>
@@ -401,7 +401,7 @@
</select>
</div>
<div class="mb-3">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300">AID (hex)</label>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300">Application / Instance AID (hex)</label>
<input id="ram-aid" class="font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="A000000151000000">
</div>
<div id="ram-sdaid-row" class="mb-3">
@@ -409,11 +409,11 @@
<input id="ram-sdaid" class="font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="A000000151000000">
</div>
<div id="ram-elfaid-row" class="mb-3">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300">ELF AID (hex)</label>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300">Load File AID / Package AID (hex)</label>
<input id="ram-elfaid" class="font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="A000000151000000">
</div>
<div id="ram-modaid-row" class="mb-3">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300">Module AID (hex)</label>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300">Executable Module AID / Applet Class AID (hex)</label>
<input id="ram-modaid" class="font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="A000000151000000">
</div>
<div id="ram-priv-row" class="mb-3">
@@ -902,9 +902,114 @@
<div id="ram-cap-info" class="text-xs text-gray-500 mt-1 hidden"></div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300 mt-2" data-l10n="SD AID (empty = ISD)">SD AID (empty = ISD)</label>
<input id="ram-sd-aid" class="w-full font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="A000000003000000" maxlength="32">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300 mt-2" data-l10n="Install parameters (hex, optional)">Install parameters (hex, optional)</label>
<div id="rc-priv-row" class="mb-3 mt-2">
<div class="flex items-center gap-3 mb-2">
<label class="text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Privileges">Privileges</label>
<input id="rc-priv" readonly class="font-mono w-20 border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1 bg-gray-100 dark:bg-slate-800" value="00">
</div>
<div class="grid grid-cols-2 gap-x-4 gap-y-1 text-xs">
<div class="font-medium text-gray-700 dark:text-slate-300 mb-1" data-l10n="Byte 1">Byte 1</div>
<div class="font-medium text-gray-700 dark:text-slate-300 mb-1" data-l10n="Byte 2">Byte 2</div>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="80" onchange="updateRcPriv()"> Security Domain</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="80" onchange="updateRcPriv()"> Trusted Path</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="40" onchange="updateRcPriv()"> DAP Verification</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="40" onchange="updateRcPriv()"> Authorized Management</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="20" onchange="updateRcPriv()"> Delegated Management</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="20" onchange="updateRcPriv()"> Token Verification</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="10" onchange="updateRcPriv()"> Card Lock</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="10" onchange="updateRcPriv()"> Global Delete</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="08" onchange="updateRcPriv()"> Card Terminate</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="08" onchange="updateRcPriv()"> Global Lock</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="04" onchange="updateRcPriv()"> Card Reset</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="04" onchange="updateRcPriv()"> Global Registry</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="02" onchange="updateRcPriv()"> CVM Management</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b1" value="01" onchange="updateRcPriv()"> Mandated DAP Verification</label>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b2" value="02" onchange="updateRcPriv()"> Final Application</label>
<div></div>
<label class="flex items-center gap-1"><input type="checkbox" class="rc-priv-b3" value="80" onchange="updateRcPriv()"> Receipt Generation</label>
</div>
</div>
<div id="rc-toolkit-row" class="mb-3">
<div class="mb-2">
<label class="flex items-center gap-2 text-sm font-medium text-gray-700 dark:text-slate-300">
<input id="rc-toolkit-enable" type="checkbox" class="rounded border-gray-300 dark:border-slate-600 dark:bg-slate-800" onchange="updateRcToolkit()">
SIM/UICC Toolkit parameters
</label>
</div>
<div id="rc-toolkit-body" class="hidden">
<div class="mb-3">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Toolkit mode">Toolkit mode</label>
<select id="rc-tk-mode" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800">
<option value="ca">SIM Toolkit (Tag CA)</option>
<option value="ea">UICC Toolkit (Tag EA)</option>
</select>
</div>
<div class="grid grid-cols-2 gap-x-3 gap-y-2 text-sm">
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Priority">Priority</label>
<input id="rc-tk-priority" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Timers (max)">Timers (max)</label>
<input id="rc-tk-timers" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Menu text length">Menu text length</label>
<input id="rc-tk-textlen" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Menu items">Menu items</label>
<input id="rc-tk-menus" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="First menu position">First menu position</label>
<input id="rc-tk-firstpos" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="First menu ID (hex)">First menu ID (hex)</label>
<input id="rc-tk-firstid" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800" placeholder="00" maxlength="2" value="00">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Last menu position">Last menu position</label>
<input id="rc-tk-lastpos" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Last menu ID (hex)">Last menu ID (hex)</label>
<input id="rc-tk-lastid" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800" placeholder="00" maxlength="2" value="00">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Channels (max)">Channels (max)</label>
<input id="rc-tk-channels" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300">MSL (SPI1, hex)</label>
<select id="rc-tk-msl" class="w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
<option value="00">00 — no verification</option>
<option value="11">11 — RC/CC/DS</option>
<option value="12">12 — RC/DS/CC</option>
<option value="15">15 — RC/DS/CC + MAC</option>
<option value="16" selected>16 — RC/DS/CC + MAC + Cipher</option>
<option value="19">19 — RC/DS/CC + MAC + Cipher + DS</option>
</select>
</div>
<div>
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300">TAR (3 bytes)</label>
<input id="rc-tk-tar" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800" placeholder="B00001" maxlength="6" value="B00001">
</div>
<div id="rc-tk-ad-row">
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Access domain (hex)">Access domain (hex)</label>
<input id="rc-tk-ad" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800" placeholder="00" maxlength="2" value="00">
</div>
<div id="rc-tk-services-row">
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Max services">Max services</label>
<input id="rc-tk-services" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
</div>
</div>
</div>
</div>
<label class="block mb-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="Install parameters (hex, optional)">Install parameters (hex, optional)</label>
<input id="ram-install-params-hex" class="w-full font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="C9 TLV">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300 mt-2" data-l10n="STK parameters (hex, optional)">STK parameters (hex, optional)</label>
<label class="block mb-1 text-xs font-medium text-gray-500 dark:text-slate-400 mt-2" data-l10n="STK parameters (hex, optional)">STK parameters (hex, optional)</label>
<input id="ram-stk-params" class="w-full font-mono border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800" placeholder="CA TLV">
<label class="flex items-center gap-2 mt-2">
<input type="checkbox" id="ram-make-sel" checked> <span class="text-sm" data-l10n="Make selectable">Make selectable</span>
@@ -1373,6 +1478,97 @@ function updateRamTkMode() {
}
document.getElementById('ram-tk-mode').addEventListener('change', updateRamTkMode);
function updateRcPriv() {
let b1 = 0, b2 = 0, b3 = 0;
document.querySelectorAll('.rc-priv-b1:checked').forEach(cb => b1 |= parseInt(cb.value, 16));
document.querySelectorAll('.rc-priv-b2:checked').forEach(cb => b2 |= parseInt(cb.value, 16));
document.querySelectorAll('.rc-priv-b3:checked').forEach(cb => b3 |= parseInt(cb.value, 16));
let hex = b1.toString(16).padStart(2, '0').toUpperCase();
hex += b2.toString(16).padStart(2, '0').toUpperCase();
if (b3) hex += b3.toString(16).padStart(2, '0').toUpperCase();
document.getElementById('rc-priv').value = hex;
}
function updateRcToolkit() {
const checked = document.getElementById('rc-toolkit-enable').checked;
document.getElementById('rc-toolkit-body').classList.toggle('hidden', !checked);
updateRcTkMode();
updateStkParamsHex();
}
function updateRcTkMode() {
const isSim = document.getElementById('rc-tk-mode').value === 'ca';
document.getElementById('rc-tk-ad-row').style.display = isSim ? '' : 'none';
document.getElementById('rc-tk-services-row').style.display = isSim ? 'none' : '';
}
document.getElementById('rc-tk-mode').addEventListener('change', () => { updateRcTkMode(); updateStkParamsHex(); });
function buildRcToolkitParams() {
if (!document.getElementById('rc-toolkit-enable').checked) return '';
const tkMode = document.getElementById('rc-tk-mode').value;
const priority = parseInt(document.getElementById('rc-tk-priority').value) || 0;
const timers = parseInt(document.getElementById('rc-tk-timers').value) || 0;
const textLen = parseInt(document.getElementById('rc-tk-textlen').value) || 0;
const menus = parseInt(document.getElementById('rc-tk-menus').value) || 0;
const firstPos = parseInt(document.getElementById('rc-tk-firstpos').value) || 0;
const firstId = (document.getElementById('rc-tk-firstid').value || '00').replace(/[^0-9a-fA-F]/g, '').padStart(2, '0').slice(0, 2) || '00';
const lastPos = parseInt(document.getElementById('rc-tk-lastpos').value) || 0;
const lastId = (document.getElementById('rc-tk-lastid').value || '00').replace(/[^0-9a-fA-F]/g, '').padStart(2, '0').slice(0, 2) || '00';
const channels = parseInt(document.getElementById('rc-tk-channels').value) || 0;
const msl = document.getElementById('rc-tk-msl').value;
const tar = (document.getElementById('rc-tk-tar').value || '').replace(/[^0-9a-fA-F]/g, '');
const adRaw = (document.getElementById('rc-tk-ad').value || '').replace(/[^0-9a-fA-F]/g, '');
const ad = adRaw.padStart(2, '0').slice(0, 2);
const services = parseInt(document.getElementById('rc-tk-services').value) || 0;
if (tar && tar.length % 6 !== 0) return null;
if (parseInt(firstId, 16) > 0x7F || parseInt(lastId, 16) > 0x7F) return null;
let menuPairs = '';
for (let i = 1; i <= menus; i++) {
if (i === 1) menuPairs += firstPos.toString(16).padStart(2, '0') + firstId;
else if (i === menus) menuPairs += lastPos.toString(16).padStart(2, '0') + lastId;
else menuPairs += '0000';
}
const mslField = msl === '00' ? '00' : '0201' + msl;
let tkPayload = '';
if (tkMode === 'ca') {
tkPayload = (adRaw ? '01' + ad : '00') +
priority.toString(16).padStart(2, '0') +
timers.toString(16).padStart(2, '0') +
textLen.toString(16).padStart(2, '0') +
menus.toString(16).padStart(2, '0') +
menuPairs +
channels.toString(16).padStart(2, '0') +
mslField +
(tar ? (tar.length / 2).toString(16).padStart(2, '0') + tar : '00');
const caTlv = 'CA' + berLenStr(tkPayload.length / 2) + tkPayload;
return 'EF' + berLenStr(caTlv.length / 2) + caTlv;
} else {
tkPayload = priority.toString(16).padStart(2, '0') +
timers.toString(16).padStart(2, '0') +
textLen.toString(16).padStart(2, '0') +
menus.toString(16).padStart(2, '0') +
menuPairs +
channels.toString(16).padStart(2, '0') +
mslField +
(tar ? (tar.length / 2).toString(16).padStart(2, '0') + tar : '00') +
services.toString(16).padStart(2, '0');
const innerTlv = '80' + berLenStr(tkPayload.length / 2) + tkPayload;
return 'EA' + berLenStr(innerTlv.length / 2) + innerTlv;
}
}
function updateStkParamsHex() {
const tk = buildRcToolkitParams();
document.getElementById('ram-stk-params').value = tk || '';
}
function updateInstallParamsHex() {
document.getElementById('ram-install-params-hex').value = 'C900';
}
// ===== GSM 7-bit alphabet =====
const GSM7_ALPHABET = [
'\u0040','\u00a3','\u0024','\u00a5','\u00e8','\u00e9','\u00f9','\u00ec',
@@ -4251,6 +4447,10 @@ function ramApplyCard(idx) {
function ramOpChanged() {
const op = document.getElementById('ram-op').value;
document.getElementById('ram-install-params').classList.toggle('hidden', op !== 'install-cap');
if (op !== 'explore') {
document.getElementById('ram-explorer').classList.add('hidden');
document.getElementById('ram-explorer').innerHTML = '';
}
}
function ramShowProgress(text) {
@@ -4539,7 +4739,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs) {
}
if (isd && isd.length) {
html += '<div class="mb-4">';
html += '<div class="font-semibold text-sm mb-1" data-l10n="ISD">ISD</div>';
html += '<div class="font-semibold text-sm mb-1" data-l10n="ISD (Issuer Security Domain)">ISD (Issuer Security Domain)</div>';
isd.forEach(o => {
html += '<div class="mb-1 pl-2 border-l-2 border-blue-400">';
html += '<div>AID: ' + (o.aid || '?') + '</div>';
@@ -4552,10 +4752,10 @@ function ramRenderExploreHtml(mem, isd, apps, elfs) {
}
if (apps && apps.length) {
html += '<div class="mb-4">';
html += '<div class="font-semibold text-sm mb-1" data-l10n="Applications">Applications</div>';
html += '<div class="font-semibold text-sm mb-1" data-l10n="Applications / Applet Instances">Applications / Applet Instances</div>';
apps.forEach(o => {
html += '<div class="mb-1 pl-2 border-l-2 border-green-400">';
html += '<div>AID: ' + (o.aid || '?');
html += '<div>Application / Instance AID: ' + (o.aid || '?');
if (o.aid) {
html += ' <button onclick="ramDeleteFromExplorer(\'' + o.aid + '\', false)" class="ml-2 px-2 py-0.5 text-xs bg-red-100 text-red-700 rounded hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400" data-l10n="Delete">Delete</button>';
}
@@ -4563,7 +4763,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs) {
html += '<div>Lifecycle: ' + ramFmtLifecycle(o.lifecycle || '') + '</div>';
if (o.privileges) html += '<div>Privileges: ' + ramFmtPrivileges(o.privileges) + ' (' + o.privileges + ')</div>';
if (o.implicitSel) html += '<div>Implicit sel: ' + o.implicitSel + '</div>';
if (o.elfAid) html += '<div>ELF AID: ' + o.elfAid + '</div>';
if (o.elfAid) html += '<div>Load File AID / Package AID: ' + o.elfAid + '</div>';
if (o.sdAid) html += '<div>SD AID: ' + o.sdAid + '</div>';
html += '</div>';
});
@@ -4571,19 +4771,19 @@ function ramRenderExploreHtml(mem, isd, apps, elfs) {
}
if (elfs && elfs.length) {
html += '<div class="mb-4">';
html += '<div class="font-semibold text-sm mb-1" data-l10n="Executable Load Files">Executable Load Files</div>';
html += '<div class="font-semibold text-sm mb-1" data-l10n="Executable Load Files (ELFs) / Packages">Executable Load Files (ELFs) / Packages</div>';
elfs.forEach(o => {
html += '<div class="mb-1 pl-2 border-l-2 border-purple-400">';
html += '<div>AID: ' + (o.aid || '?');
html += '<div>Load File AID / Package AID: ' + (o.aid || '?');
if (o.aid) {
html += ' <button onclick="ramDeleteFromExplorer(\'' + o.aid + '\', false)" class="ml-2 px-2 py-0.5 text-xs bg-red-100 text-red-700 rounded hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400" data-l10n="Delete">Delete</button>';
html += ' <button onclick="ramDeleteFromExplorer(\'' + o.aid + '\', true)" class="ml-1 px-2 py-0.5 text-xs bg-red-200 text-red-800 rounded hover:bg-red-300 dark:bg-red-900/50 dark:text-red-300" data-l10n="Delete All">Delete All</button>';
html += ' <button onclick="ramDeleteFromExplorer(\'' + o.aid + '\', true)" class="ml-1 px-2 py-0.5 text-xs bg-red-100 text-red-700 rounded hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400" data-l10n="Delete All">Delete All</button>';
}
html += '</div>';
html += '<div>Lifecycle: ' + ramFmtLifecycle(o.lifecycle || '') + '</div>';
if (o.version) html += '<div>Version: ' + o.version + '</div>';
if (o.moduleAids && o.moduleAids.length) {
html += '<div>Module AIDs:</div>';
html += '<div>Executable Module AIDs / Applet Class AIDs:</div>';
o.moduleAids.forEach(m => { html += '<div class="pl-4">- ' + m + '</div>'; });
}
if (o.sdAid) html += '<div>SD AID: ' + o.sdAid + '</div>';
@@ -4757,6 +4957,7 @@ async function ramInstallCap(sp) {
const body = {
cap_hex: capHex,
sd_aid: (document.getElementById('ram-sd-aid').value || '').replace(/[^0-9a-fA-F]/g, ''),
privileges: (document.getElementById('rc-priv').value || '00').replace(/[^0-9a-fA-F]/g, ''),
install_params: (document.getElementById('ram-install-params-hex').value || '').replace(/[^0-9a-fA-F]/g, ''),
stk_params: (document.getElementById('ram-stk-params').value || '').replace(/[^0-9a-fA-F]/g, ''),
make_selectable: document.getElementById('ram-make-sel').checked,
@@ -5038,8 +5239,14 @@ function cardsApply(idx) {
if (!c) return;
document.getElementById('sp-spi1').value = c.spi1;
document.getElementById('sp-spi2-hex').value = c.spi2;
document.getElementById('sp-kic-hex').value = c.kic;
document.getElementById('sp-kid-hex').value = c.kid;
const kicByte = parseInt(c.kic, 16);
document.getElementById('sp-kic-idx').value = ((kicByte >> 4) & 0x0F).toString(16).toUpperCase();
document.getElementById('sp-kic-alg').value = (kicByte & 0x0F).toString(16).padStart(2, '0');
updateSpKic();
const kidByte = parseInt(c.kid, 16);
document.getElementById('sp-kid-idx').value = ((kidByte >> 4) & 0x0F).toString(16).toUpperCase();
document.getElementById('sp-kid-alg').value = (kidByte & 0x0F).toString(16).padStart(2, '0');
updateSpKid();
document.getElementById('sp-tar').value = c.tar || 'B00001';
document.getElementById('sp-cntr').value = c.cntr;
document.getElementById('sp-kic-key').value = c.kicKey;
@@ -6591,8 +6798,9 @@ const LANG_RU = {
'PIN value': 'Значение PIN',
'Old PIN': 'Старый PIN',
'New PIN': 'Новый PIN',
'ELF AID (hex)': 'ELF AID (hex)',
'Module AID (hex)': 'AID модуля (hex)',
'Application / Instance AID (hex)': 'AID приложения / экземпляра (hex)',
'Load File AID / Package AID (hex)': 'AID Load File / пакета (hex)',
'Executable Module AID / Applet Class AID (hex)': 'AID исполняемого модуля / класса апплета (hex)',
'Security level (P1)': 'Уровень безопасности (P1)',
'Target': 'Цель',
'Current EF (case 1)': 'Текущий EF (case 1)',
@@ -6663,6 +6871,12 @@ const LANG_RU = {
'Remove': 'Удалить',
'Delete': 'Удалить',
'Delete All': 'Удалить все',
'ISD (Issuer Security Domain)': 'ISD (домен безопасности эмитента)',
'Applications / Applet Instances': 'Приложения / экземпляры апплетов',
'Executable Load Files (ELFs) / Packages': 'Исполняемые файлы загрузки (ELF) / пакеты',
'Application / Instance AID:': 'AID приложения / экземпляра:',
'Load File AID / Package AID:': 'AID Load File / пакета:',
'Executable Module AIDs / Applet Class AIDs:': 'AID исполняемых модулей / классов апплетов:',
'No cards defined.': 'Карты не заданы.',
'Card presets': 'Выбор карты',
'— Select card —': '— Выберите карту —',
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'otaman-v31';
const CACHE = 'otaman-v33';
const URLS = [
'index.html',
'help.html',
+3 -2
View File
@@ -18,7 +18,7 @@ from osmocom.construct import GsmOrUcs2Adapter
from osmocom.tlv import BER_TLV_IE
VERSION = '1.9.19'
VERSION = '1.9.21'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
@@ -2138,6 +2138,7 @@ class PysimHandler(BaseHTTPRequestHandler):
install_params_hex = body.get('install_params', '').replace(' ', '')
stk_params_hex = body.get('stk_params', '').replace(' ', '')
make_selectable = body.get('make_selectable', True)
privileges_hex = body.get('privileges', '').replace(' ', '') or '00'
steps = []
include_cpi = body.get('includeCpi', True)
@@ -2228,7 +2229,7 @@ class PysimHandler(BaseHTTPRequestHandler):
# Step 3: INSTALL [for install]
sys.stderr.write('RAM-INSTALL: Step 3 — INSTALL [for install]\n')
instance_aid = module_aid
privileges = '00'
privileges = privileges_hex
inst_params = install_params_hex if install_params_hex else 'C900'
if stk_params_hex:
inst_params += stk_params_hex