mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-06-05 23:41:48 +00:00
Merge pull request #3326 from klks/master
Add native fmcos support to proxmark3
This commit is contained in:
@@ -397,6 +397,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||
${PM3_ROOT}/client/src/cmdhffido.c
|
||||
${PM3_ROOT}/client/src/cmdhffmcos.c
|
||||
${PM3_ROOT}/client/src/cmdhffudan.c
|
||||
${PM3_ROOT}/client/src/cmdhfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdhfgst.c
|
||||
|
||||
@@ -738,6 +738,7 @@ SRCS = mifare/aiddesfire.c \
|
||||
cmdhfemrtd.c \
|
||||
cmdhffelica.c \
|
||||
cmdhffido.c \
|
||||
cmdhffmcos.c \
|
||||
cmdhffudan.c \
|
||||
cmdhfgallagher.c \
|
||||
cmdhfgst.c \
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "cmdhfemrtd.h" // eMRTD
|
||||
#include "cmdhffelica.h" // ISO18092 / FeliCa
|
||||
#include "cmdhffido.h" // FIDO authenticators
|
||||
#include "cmdhffmcos.h" // FMCOS CPU cards
|
||||
#include "cmdhfsecc.h" // iClass SE Config Card
|
||||
#include "cmdhffudan.h" // Fudan cards
|
||||
#include "cmdhfgallagher.h" // Gallagher DESFire cards
|
||||
@@ -588,6 +589,7 @@ static command_t CommandTable[] = {
|
||||
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"fmcos", CmdHFFmcos, AlwaysAvailable, "{ FMCOS CPU cards... }"},
|
||||
{"fudan", CmdHFFudan, AlwaysAvailable, "{ Fudan RFIDs... }"},
|
||||
{"gallagher", CmdHFGallagher, AlwaysAvailable, "{ Gallagher DESFire RFIDs... }"},
|
||||
{"gst", CmdHFGST, AlwaysAvailable, "{ Google Smart Tap passes... }"},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Commands for FMCOS CPU smart cards (Fudan Microelectronics)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDHFFMCOS_H__
|
||||
#define CMDHFFMCOS_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdHFFmcos(const char *Cmd);
|
||||
|
||||
#endif // CMDHFFMCOS_H__
|
||||
+882
@@ -0,0 +1,882 @@
|
||||
# FMCOS CPU Smart Card Commands
|
||||
<a id="Top"></a>
|
||||
|
||||
FMCOS (Fudan Microelectronics CPU OS) is an ISO14443-A CPU card operating system used in
|
||||
Chinese transit and e-wallet cards (PBOC compliant). Common hardware: FM1208-09, FM1216.
|
||||
|
||||
All commands in this family are reachable via `hf fmcos <subcommand>`.
|
||||
|
||||
---
|
||||
|
||||
# Table of Contents
|
||||
|
||||
- [Card Information](#card-information)
|
||||
- [info](#info)
|
||||
- [select](#select)
|
||||
- [File Management](#file-management)
|
||||
- [erase](#erase)
|
||||
- [create dir](#create-dir)
|
||||
- [create file](#create-file)
|
||||
- [create keyfile](#create-keyfile)
|
||||
- [Data Access](#data-access)
|
||||
- [read binary](#read-binary)
|
||||
- [read record](#read-record)
|
||||
- [write binary](#write-binary)
|
||||
- [write record](#write-record)
|
||||
- [append](#append)
|
||||
- [key (write key)](#key-write-key)
|
||||
- [Authentication](#authentication)
|
||||
- [auth external](#auth-external)
|
||||
- [auth internal](#auth-internal)
|
||||
- [PIN Management](#pin-management)
|
||||
- [pin verify](#pin-verify)
|
||||
- [pin change](#pin-change)
|
||||
- [pin reset](#pin-reset)
|
||||
- [pin unblock](#pin-unblock)
|
||||
- [Financial Operations](#financial-operations)
|
||||
- [balance](#balance)
|
||||
- [credit](#credit)
|
||||
- [purchase](#purchase)
|
||||
- [overdraft](#overdraft)
|
||||
- [history](#history)
|
||||
- [Card Lifecycle](#card-lifecycle)
|
||||
- [block](#block)
|
||||
- [unblock](#unblock)
|
||||
- [File Access Reference](#file-access-reference)
|
||||
- [Key Types Reference](#key-types-reference)
|
||||
- [File Protection Modes](#file-protection-modes)
|
||||
- [Access Rights Byte](#access-rights-byte)
|
||||
- [Complete Wallet Session Walkthrough](#complete-wallet-session-walkthrough)
|
||||
|
||||
---
|
||||
|
||||
## Card Information
|
||||
|
||||
### info
|
||||
|
||||
Detect a FMCOS card and dump its file-system layout: MF, DFs, and EFs with their file
|
||||
identifiers, types, sizes, and access attributes.
|
||||
|
||||
```
|
||||
hf fmcos info
|
||||
```
|
||||
|
||||
### select
|
||||
|
||||
SELECT a file or application directory by 2-byte file ID (hex) or by DF name (ASCII string).
|
||||
After selection subsequent commands operate within that context.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00
|
||||
hf fmcos select --id 3f01
|
||||
hf fmcos select --name 77616C6C657454657374
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | 2-byte file ID (e.g. `3f00` for MF, `3f01` for an ADF) |
|
||||
| `--name <hex>` | DF name bytes as hex (up to 16 bytes, e.g. `77616C6C657454657374` = `walletTest`) |
|
||||
| `-k` / `--keep` | Keep the RF field on after the command |
|
||||
|
||||
---
|
||||
|
||||
## File Management
|
||||
|
||||
### erase
|
||||
|
||||
ERASE DF -- delete all EFs and sub-DFs from the currently selected DF, but keep the DF
|
||||
itself and its keyfile. Requires the MF or relevant DF to be selected first.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00
|
||||
hf fmcos erase
|
||||
```
|
||||
|
||||
### create dir
|
||||
|
||||
CREATE DF (directory / application directory).
|
||||
|
||||
```
|
||||
hf fmcos create dir --id 3f01 --space 1500 --cperm f0 --eperm f0 --appid 95 --name 77616C6C657454657374
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | 2-byte file ID for the new DF |
|
||||
| `--space <hex>` | Total byte space to reserve (hex, e.g. `1500` = 5376 bytes) |
|
||||
| `--cperm <hex>` | Create-permission byte (e.g. `f0` = always allowed) |
|
||||
| `--eperm <hex>` | Erase-permission byte |
|
||||
| `--appid <hex>` | 1-byte application SID / AID tag |
|
||||
| `--name <hex>` | Optional DF name bytes as hex (up to 16 bytes, enables select-by-name) |
|
||||
|
||||
### create file
|
||||
|
||||
CREATE EF (elementary file) in the currently selected DF.
|
||||
|
||||
```
|
||||
# Unprotected binary file
|
||||
hf fmcos create file --id 0002 --type bin --size 50 --rperm f0 --wperm f0 --access ff
|
||||
|
||||
# Variable-length record file with MAC-only line protection
|
||||
hf fmcos create file --id 0006 --type var --size 50 --rperm f0 --wperm f0 --access 7f --prot mac
|
||||
|
||||
# Loop (cyclic) file with MAC+encryption
|
||||
hf fmcos create file --id 000a --type loop --size 210 --rperm f0 --wperm f0 --access 7f --prot enc
|
||||
|
||||
# Wallet/passbook balance file (EDEP) linked to loop file 0x0018
|
||||
hf fmcos create file --id 0002 --type wallet --size 0208 --rperm f0 --wperm 00 --access 18
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | 2-byte file ID |
|
||||
| `--type <type>` | `bin` (0x28), `fix` (0x2A), `var` (0x2C), `loop` (0x2E), `wallet` (0x2F) |
|
||||
| `--size <hex>` | File size in bytes (hex, e.g. `0208` = 520) |
|
||||
| `--rperm <hex>` | Read/usage-rights byte; for wallet type this is the single usage rights byte |
|
||||
| `--wperm <hex>` | Write permission byte; ignored for wallet type (always sent as 0x00) |
|
||||
| `--access <hex>` | Access-rights byte; for wallet type this is the low byte of the linked loop EF's file ID |
|
||||
| `--prot <mode>` | Line-protection mode: `none` (default), `mac`, `enc` (MAC+encrypt) |
|
||||
|
||||
**File type encodings:**
|
||||
|
||||
| Name | Code | Description |
|
||||
|------|------|-------------|
|
||||
| `bin` | 0x28 | Binary transparent file |
|
||||
| `fix` | 0x2A | Fixed-length record file |
|
||||
| `var` | 0x2C | Variable-length record file |
|
||||
| `loop` | 0x2E | Cyclic (loop) file -- used for transaction logs |
|
||||
| `wallet` | 0x2F | E-purse wallet / passbook balance file |
|
||||
|
||||
### create keyfile
|
||||
|
||||
CREATE KEYFILE in the currently selected DF. A DF must have a keyfile before any keys
|
||||
can be written to it.
|
||||
|
||||
```
|
||||
hf fmcos create keyfile --id 0000 --space 200 --dfsid 95 --perm f0
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | 2-byte file ID for the keyfile (commonly `0000`) |
|
||||
| `--space <hex>` | Space to reserve for key storage (bytes, hex, e.g. `200` = 512) |
|
||||
| `--dfsid <hex>` | Parent DF SID (must match the DF's `--appid` value) |
|
||||
| `--perm <hex>` | Key access permission byte |
|
||||
|
||||
---
|
||||
|
||||
## Data Access
|
||||
|
||||
### read binary
|
||||
|
||||
READ BINARY from the currently selected transparent (bin) EF.
|
||||
|
||||
```
|
||||
# Plain read
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 10
|
||||
|
||||
# With MAC line-protection (verifies response MAC)
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 10 --prot mac --key 36363636363636363636363636363636
|
||||
|
||||
# With MAC+encryption (decrypts response)
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 10 --prot enc --key 36363636363636363636363636363636
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--p1 <hex>` | P1 byte (high byte of file offset) |
|
||||
| `--p2 <hex>` | P2 byte (low byte of file offset) |
|
||||
| `--len <hex>` | Number of bytes to read (Le) |
|
||||
| `--prot <mode>` | `none`, `mac`, or `enc` |
|
||||
| `--key <hex>` | Line-protection key (8 or 16 bytes, required when `--prot` is mac/enc) |
|
||||
|
||||
### read record
|
||||
|
||||
READ RECORD from the currently selected record or cyclic EF.
|
||||
|
||||
```
|
||||
# Read record 1 from var file 0x06 (plain)
|
||||
hf fmcos read record --rec 01 --fid 06 --len 10
|
||||
|
||||
# Read with MAC verification
|
||||
hf fmcos read record --rec 01 --fid 07 --len 10 --prot mac --key 36363636363636363636363636363636
|
||||
|
||||
# Read with decryption
|
||||
hf fmcos read record --rec 01 --fid 08 --len 10 --prot enc --key 36363636363636363636363636363636
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--rec <hex>` | Record number (P1); `00` = current record |
|
||||
| `--fid <hex>` | File ID in P2 (upper 5 bits); `00` = current file |
|
||||
| `--len <hex>` | Number of bytes to read |
|
||||
| `--prot <mode>` | `none`, `mac`, or `enc` |
|
||||
| `--key <hex>` | Line-protection key when prot is mac/enc |
|
||||
|
||||
### write binary
|
||||
|
||||
UPDATE BINARY -- write data to the currently selected transparent EF.
|
||||
|
||||
```
|
||||
# Plain write
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 11121314151617181910
|
||||
|
||||
# Write with MAC
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 21222324252627282920 \
|
||||
--prot mac --key 36363636363636363636363636363636
|
||||
|
||||
# Write with MAC+encryption (data is encrypted before sending)
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 31323334353637383930 \
|
||||
--prot enc --key 36363636363636363636363636363636
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--p1 <hex>` | P1 byte (high offset byte) |
|
||||
| `--p2 <hex>` | P2 byte (low offset byte) |
|
||||
| `--data <hex>` | Data bytes to write |
|
||||
| `--prot <mode>` | `none`, `mac`, or `enc` |
|
||||
| `--key <hex>` | Line-protection key |
|
||||
|
||||
### write record
|
||||
|
||||
UPDATE RECORD -- write a record into the currently selected EF.
|
||||
|
||||
```
|
||||
# Plain record write (P1=record number, P2=file-id<<3|04)
|
||||
hf fmcos write record --rec 01 --fid 06 --data 5152535455565758595a
|
||||
|
||||
# With MAC
|
||||
hf fmcos write record --rec 01 --fid 07 --data 6162636465666768696a \
|
||||
--prot mac --key 36363636363636363636363636363636
|
||||
|
||||
# With MAC+encryption
|
||||
hf fmcos write record --rec 01 --fid 08 --data 7172737475767778797a \
|
||||
--prot enc --key 36363636363636363636363636363636
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--rec <hex>` | Record number (P1) |
|
||||
| `--fid <hex>` | File ID for P2 encoding |
|
||||
| `--data <hex>` | Record data bytes |
|
||||
| `--prot <mode>` | `none`, `mac`, or `enc` |
|
||||
| `--key <hex>` | Line-protection key |
|
||||
|
||||
### append
|
||||
|
||||
APPEND RECORD -- append a new record to a cyclic (loop) EF.
|
||||
|
||||
```
|
||||
# Plain append
|
||||
hf fmcos append --fid 0a --data 9192939495969798999a
|
||||
|
||||
# With MAC
|
||||
hf fmcos append --fid 0b --data a1a2a3a4a5a6a7a8a9a0 \
|
||||
--prot mac --key 36363636363636363636363636363636
|
||||
|
||||
# With MAC+encryption
|
||||
hf fmcos append --fid 0c --data b1b2b3b4b5b6b7b8b9b0 \
|
||||
--prot enc --key 36363636363636363636363636363636
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--fid <hex>` | File ID of the loop EF |
|
||||
| `--data <hex>` | Record data bytes |
|
||||
| `--prot <mode>` | `none`, `mac`, or `enc` |
|
||||
| `--key <hex>` | Line-protection key |
|
||||
|
||||
### key (write key)
|
||||
|
||||
WRITE KEY -- write a key entry into the currently selected keyfile. Use `--op 01` to add
|
||||
a new key, `--op 02` to update an existing one.
|
||||
|
||||
**Group A keys** (DES/3DES data keys with version + algorithm fields):
|
||||
|
||||
```
|
||||
# Add InternalKey (0x34) at slot 0, always-free usage
|
||||
hf fmcos key --op 01 --id 00 --type internal \
|
||||
--usage f0 --change 02 --version 00 --algo 01 \
|
||||
--key 2b8a438742c851566f02d881b09d58c0
|
||||
|
||||
# Add CreditKey (0x3F) at slot 1
|
||||
hf fmcos key --op 01 --id 01 --type credit \
|
||||
--usage f0 --change 02 --version 00 --algo 01 \
|
||||
--key a9e6e145f5df09500a58eef8575d49db
|
||||
|
||||
# Add PurchaseKey (0x3E) at slot 1
|
||||
hf fmcos key --op 01 --id 01 --type purchase \
|
||||
--usage f0 --change 02 --version 00 --algo 01 \
|
||||
--key eb18ce6986c820970e876219052ce0cf
|
||||
```
|
||||
|
||||
**Group B keys** (PIN and external-auth keys with error counter):
|
||||
|
||||
```
|
||||
# Add PIN key (0x3A) at slot 0 -- pin value is 2-6 raw bytes
|
||||
hf fmcos key --op 01 --id 00 --type pin \
|
||||
--usage f0 --followup 01 --errcount 33 \
|
||||
--key 123456
|
||||
|
||||
# Add ExternalAuth key (0x39) at slot 0
|
||||
hf fmcos key --op 01 --id 00 --type extauth \
|
||||
--usage f0 --change 02 --followup 44 --errcount 33 \
|
||||
--key f49dc1ba1b4deb5264718bc559106c0d
|
||||
```
|
||||
|
||||
**Group C keys** (line-protection, unlock-PIN, change-PIN):
|
||||
|
||||
```
|
||||
# Add line-protection key (0x36) at slot 0
|
||||
hf fmcos key --op 01 --id 00 --type lineprotect \
|
||||
--usage f0 --change 02 --errcount ff \
|
||||
--key 8a021972bfec9d152ca9eb82d7d12c09
|
||||
|
||||
# Add unlock-PIN key (0x37)
|
||||
hf fmcos key --op 01 --id 00 --type unlockpin \
|
||||
--usage f0 --change 02 --errcount 33 \
|
||||
--key d8f60fa2d791f3a658d27c0545824300
|
||||
|
||||
# Add change-PIN key (0x38)
|
||||
hf fmcos key --op 01 --id 00 --type changepin \
|
||||
--usage f0 --change 02 --errcount 33 \
|
||||
--key fb487a6d1b7cbf1bf84c666b8338376e
|
||||
```
|
||||
|
||||
**Key types:**
|
||||
|
||||
| Name | Code | Group | Description |
|
||||
|------|------|-------|-------------|
|
||||
| `desenc` | 0x30 | A | DES encrypt key |
|
||||
| `desdec` | 0x31 | A | DES decrypt key |
|
||||
| `desmac` | 0x32 | A | DES MAC key |
|
||||
| `internal` | 0x34 | A | Internal-auth / TAC key |
|
||||
| `overdraft` | 0x3C | A | Overdraft-limit key |
|
||||
| `debit` | 0x3D | A | Debit (online transfer) key |
|
||||
| `purchase` | 0x3E | A | Purchase / debit key |
|
||||
| `credit` | 0x3F | A | Credit key |
|
||||
| `extauth` | 0x39 | B | External-authentication key |
|
||||
| `pin` | 0x3A | B | PIN code key |
|
||||
| `lineprotect` | 0x36 | C | Line-protection key |
|
||||
| `unlockpin` | 0x37 | C | Unlock-PIN key |
|
||||
| `changepin` | 0x38 | C | Change-PIN key |
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
### auth external
|
||||
|
||||
EXTERNAL AUTHENTICATE -- authenticate the reader to the card. The card issues a challenge,
|
||||
the reader encrypts it with the external-auth key, and sends the response back.
|
||||
|
||||
```
|
||||
hf fmcos auth external --id 00 --key f49dc1ba1b4deb5264718bc559106c0d
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | Key slot ID |
|
||||
| `--key <hex>` | External-auth key (8 or 16 bytes) |
|
||||
|
||||
### auth internal
|
||||
|
||||
INTERNAL AUTHENTICATE -- authenticate the card to the reader. The reader sends an 8-byte
|
||||
challenge (`--data`); the card responds with a DES-encrypted value that the reader verifies
|
||||
offline.
|
||||
|
||||
```
|
||||
hf fmcos auth internal --p1 00 --p2 00 --data 0102030405060708
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--p1 <hex>` | P1 byte (typically `00`) |
|
||||
| `--p2 <hex>` | P2 byte (typically `00`) |
|
||||
| `--data <hex>` | 8-byte challenge sent to the card |
|
||||
|
||||
---
|
||||
|
||||
## PIN Management
|
||||
|
||||
### pin verify
|
||||
|
||||
VERIFY PIN -- present the PIN code to the card to unlock PIN-gated operations.
|
||||
PIN is 2-6 raw bytes.
|
||||
|
||||
```
|
||||
hf fmcos pin verify --id 00 --pin 123456
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | PIN key slot ID |
|
||||
| `--pin <hex>` | PIN bytes (2-6 bytes) |
|
||||
|
||||
### pin change
|
||||
|
||||
CHANGE PIN -- change the PIN using the current (old) PIN for authorization.
|
||||
|
||||
```
|
||||
hf fmcos pin change --id 00 --old 123456 --new 13371337
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | PIN key slot ID |
|
||||
| `--old <hex>` | Current PIN (2-6 bytes) |
|
||||
| `--new <hex>` | New PIN (2-6 bytes) |
|
||||
|
||||
### pin reset
|
||||
|
||||
RESET PIN -- set a new PIN using the change-PIN key MAC for authorization (no old PIN needed).
|
||||
The command computes a MAC over the new PIN using the change-PIN key and sends it to the card.
|
||||
|
||||
```
|
||||
hf fmcos pin reset --id 00 --pin 13371337 \
|
||||
--key fb487a6d1b7cbf1bf84c666b8338376e
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | PIN key slot ID |
|
||||
| `--pin <hex>` | New PIN (2-6 bytes) |
|
||||
| `--key <hex>` | Change-PIN key (16 bytes); MAC = DES-MAC(new_pin, XOR_halves(key)) |
|
||||
|
||||
### pin unblock
|
||||
|
||||
UNBLOCK PIN -- clear the PIN blocked state and set a new PIN.
|
||||
The new PIN is encrypted with the unlock-PIN key and a GET CHALLENGE IV.
|
||||
|
||||
```
|
||||
hf fmcos pin unblock --id 00 --pin 123456 \
|
||||
--key d8f60fa2d791f3a658d27c054582430e
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | PIN key slot ID |
|
||||
| `--pin <hex>` | New PIN (2-6 bytes) |
|
||||
| `--key <hex>` | Unlock-PIN key (16 bytes) |
|
||||
|
||||
---
|
||||
|
||||
## Financial Operations
|
||||
|
||||
FMCOS implements a two-phase PBOC e-wallet protocol. Phase 1 initializes the transaction
|
||||
and returns card-computed data (old balance, serial number, random seed, MAC1). Phase 2
|
||||
commits the transaction with a terminal-computed MAC2 and receives a Transaction
|
||||
Authentication Code (TAC) from the card which the terminal verifies.
|
||||
|
||||
**Keys involved:**
|
||||
|
||||
| Key | Role |
|
||||
|-----|------|
|
||||
| Credit key (16 B) | Derive the session process key for credit operations |
|
||||
| Purchase key (16 B) | Derive the session process key for purchase/debit |
|
||||
| Overdraft key (16 B) | Derive the session process key for overdraft-limit updates |
|
||||
| Internal key / DTK (16 B) | Verify TAC: all financial commands use `tac_key = XOR(ikey[0:8], ikey[8:16])` → DES-CBC-MAC |
|
||||
|
||||
**Terminal ID:** 6 bytes identifying the terminal. Use any fixed value for testing (e.g. `666666666666`).
|
||||
|
||||
### balance
|
||||
|
||||
GET BALANCE -- read the current balance from the wallet or passbook balance file.
|
||||
|
||||
```
|
||||
hf fmcos balance --type wallet
|
||||
hf fmcos balance --type passbook
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--type <type>` | `wallet` (0x02) or `passbook` (0x01) |
|
||||
| `-k` / `--keep` | Keep field on |
|
||||
|
||||
**APDU:** `80 5C 00 <type> 04`
|
||||
**Response:** 4-byte big-endian balance.
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
[=] Balance (wallet): 1000 (0x000003E8)
|
||||
```
|
||||
|
||||
### credit
|
||||
|
||||
ADD CREDIT -- two-phase credit transaction.
|
||||
|
||||
**Phase 1** (`INS 50`, P1=00): send key ID, amount, terminal ID. Card returns old balance,
|
||||
transaction serial, key version, algo ID, random seed, and MAC1. The implementation:
|
||||
- Derives the process key: `encrypt(random[4] | serial[2], credit_key)` -> first 8 bytes
|
||||
- Verifies MAC1: `DES-CBC-MAC(old_bal[4] | amount[4] | type[1] | terminal[6], process_key)`
|
||||
|
||||
**Phase 2** (`INS 52`, P1=00): send date, time, MAC2. Card returns TAC. The implementation:
|
||||
- Computes MAC2: `DES-CBC-MAC(amount[4] | type[1] | terminal[6] | date[4] | time[3], process_key)`
|
||||
- Verifies TAC: `DES-CBC-MAC(new_bal[4] | serial[2] | MAC2_buf[18], tac_key)`
|
||||
|
||||
```
|
||||
hf fmcos credit --type wallet --id 01 --amount 1000 \
|
||||
--terminal 666666666666 \
|
||||
--key a9e6e145f5df09500a58eef8575d49db \
|
||||
--ikey 2b8a438742c851566f02d881b09d58c0
|
||||
|
||||
hf fmcos credit --type passbook --id 01 --amount 2000 \
|
||||
--terminal 666666666666 \
|
||||
--key a9e6e145f5df09500a58eef8575d49db \
|
||||
--ikey 2b8a438742c851566f02d881b09d58c0
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--type <type>` | `wallet` or `passbook` |
|
||||
| `--id <n>` | Credit key slot ID (1 byte decimal) |
|
||||
| `--amount <n>` | Credit amount (integer, units match card configuration) |
|
||||
| `--terminal <hex>` | Terminal ID (6 bytes) |
|
||||
| `--key <hex>` | Credit key (16 bytes) |
|
||||
| `--ikey <hex>` | Internal key (16 bytes) for TAC verification |
|
||||
| `-k` / `--keep` | Keep field on after command |
|
||||
|
||||
> **Note**: FMCOS resets the card's security status after each completed financial transaction.
|
||||
> Re-verify PIN before each credit or purchase operation (SW:6985 indicates the security status was cleared).
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
[=] MAC1 OK old balance 0
|
||||
[+] TAC OK new balance 1000
|
||||
[+] SW: 9000 - Success
|
||||
```
|
||||
|
||||
### purchase
|
||||
|
||||
PURCHASE -- two-phase debit transaction from wallet or passbook.
|
||||
|
||||
**Phase 1** (`INS 50`, P1=01): send key ID, amount, terminal. Card returns old balance,
|
||||
offline serial, overdraft limit, key version, algo, random seed (15 bytes total).
|
||||
- Derives process key: `encrypt(random[4] | offline_serial[2] | tx_serial[2], purchase_key)[:8]`
|
||||
- Computes MAC1: `DES-CBC-MAC(amount[4] | tx_type[1] | terminal[6] | date[4] | time[3], process_key)`
|
||||
|
||||
**Phase 2** (`INS 54`, P1=01, P2=00): send tx serial, date, time, MAC1. Card returns TAC[4]+MAC2[4].
|
||||
- Verifies TAC: `DES-CBC-MAC(amount[4] | tx_type[1] | terminal[6] | serial[4] | date[4] | time[3], tac_key)`
|
||||
|
||||
Transaction type byte: 0x05 for passbook purchase, 0x06 for wallet purchase.
|
||||
|
||||
```
|
||||
# Wallet purchase of 50 units
|
||||
hf fmcos purchase --type wallet --id 01 --amount 50 \
|
||||
--terminal 666666666666 \
|
||||
--key eb18ce6986c820970e876219052ce0cf \
|
||||
--ikey 2b8a438742c851566f02d881b09d58c0 \
|
||||
--serial 01020304
|
||||
|
||||
# Passbook purchase (no explicit serial -- defaults to 00000001)
|
||||
hf fmcos purchase --type passbook --id 01 --amount 50 \
|
||||
--terminal 666666666666 \
|
||||
--key eb18ce6986c820970e876219052ce0cf \
|
||||
--ikey 2b8a438742c851566f02d881b09d58c0
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--type <type>` | `wallet` or `passbook` |
|
||||
| `--id <n>` | Purchase key slot ID |
|
||||
| `--amount <n>` | Debit amount |
|
||||
| `--terminal <hex>` | Terminal ID (6 bytes) |
|
||||
| `--key <hex>` | Purchase key (16 bytes) |
|
||||
| `--ikey <hex>` | Internal key (16 bytes) for TAC verification |
|
||||
| `--serial <hex>` | 4-byte transaction serial (optional, default `00000001`) |
|
||||
| `-k` / `--keep` | Keep field on |
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
[=] Old balance: 1000
|
||||
[+] TAC OK new balance 950
|
||||
[+] SW: 9000 - Success
|
||||
```
|
||||
|
||||
### overdraft
|
||||
|
||||
UPDATE OVERDRAFT LIMIT -- two-phase overdraft-limit update on the passbook.
|
||||
|
||||
**Phase 1** (`INS 50`, P1=04, P2=01): send key ID and terminal. Card returns old balance,
|
||||
online serial, old limit, key version, algo, random seed, and MAC1 (19 bytes total).
|
||||
- Derives process key: `encrypt(random[4] | serial[2], overdraft_key)[:8]`
|
||||
- Verifies MAC1: `DES-CBC-MAC(old_bal[4] | old_limit[3] | 0x07[1] | terminal[6], process_key)`
|
||||
|
||||
**Phase 2** (`INS 58`, P1=00, P2=00): send new limit (3 bytes), date, time, MAC2.
|
||||
- Computes MAC2: `DES-CBC-MAC(new_limit[3] | 0x07[1] | terminal[6] | date[4] | time[3], process_key)`
|
||||
- Card returns TAC[4]. When `--ikey` is provided the TAC is verified:
|
||||
`DES-CBC-MAC(XOR(ikey[0:8], ikey[8:16]), tac_bal[4] | online_serial[2] | new_limit[3] | 0x07[1] | terminal[6] | date[4] | time[3])`
|
||||
where `tac_bal = old_balance + new_limit - old_od_limit`. The card stores
|
||||
`actual_funds + overdraft_limit` as its balance field, so when the limit changes the new
|
||||
stored balance shifts by the limit delta.
|
||||
|
||||
```
|
||||
hf fmcos overdraft --id 01 --limit 1000 \
|
||||
--terminal 666666666666 \
|
||||
--key 94f63c4fae5e4977d749928ad12bc128 \
|
||||
--ikey 659a500f0f1fce35b6884bdff966576a
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--id <hex>` | Overdraft key slot ID |
|
||||
| `--limit <n>` | New overdraft limit (24-bit integer, max 16777215) |
|
||||
| `--terminal <hex>` | Terminal ID (6 bytes) |
|
||||
| `--key <hex>` | Overdraft key (16 bytes) |
|
||||
| `--ikey <hex>` | Internal key DTK (16 bytes) for TAC verification (optional) |
|
||||
| `-k` / `--keep` | Keep field on |
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
[=] Old balance: 1000 old overdraft limit: 0
|
||||
[=] MAC1 OK
|
||||
[+] Overdraft limit updated to 1000
|
||||
[+] TAC OK aabbccdd
|
||||
[+] SW: 9000 - Success
|
||||
```
|
||||
|
||||
### history
|
||||
|
||||
READ TRANSACTION HISTORY -- decode all records in the loop (cyclic) EF used as a transaction
|
||||
log. The card appends a 23-byte record to the loop file after every financial operation.
|
||||
|
||||
```
|
||||
# Wallet transaction log (loop file SFI 0x18 in the example setup)
|
||||
hf fmcos history --fid 18
|
||||
|
||||
# Passbook transaction log, read up to 20 records
|
||||
hf fmcos history --fid 19 --count 20
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--fid <hex>` | Loop file SFI byte (1 byte, e.g. `18` for wallet loop, `19` for passbook loop) |
|
||||
| `--count <n>` | Max records to read (default 10; `0` = read all, up to 255) |
|
||||
| `-k` / `--keep` | Keep field on after command |
|
||||
| `-a` / `--apdu` | Show raw APDU traffic |
|
||||
|
||||
**Record layout (23 bytes):**
|
||||
|
||||
| Offset | Length | Field | Notes |
|
||||
|--------|--------|-------|-------|
|
||||
| 0 | 2 | Serial | Transaction serial number (big-endian) |
|
||||
| 2 | 3 | OD limit | Overdraft limit at time of transaction |
|
||||
| 5 | 4 | Amount | Transaction amount (big-endian) |
|
||||
| 9 | 1 | Type | Transaction type byte |
|
||||
| 10 | 6 | Terminal | Terminal ID |
|
||||
| 16 | 4 | Date | BCD date `YYYYMMDD` |
|
||||
| 20 | 3 | Time | BCD time `HHMMSS` |
|
||||
|
||||
**Transaction type codes:**
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| `0x04` | Passbook cash withdrawal |
|
||||
| `0x05` | Passbook purchase |
|
||||
| `0x06` | Wallet purchase |
|
||||
| `0x07` | Overdraft limit update |
|
||||
| `0x09` | Compound purchase |
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
# | Date | Time | Type | Amount | OD Limit | Serial | Terminal
|
||||
---+------------+----------+--------------+------------+----------+--------+-------------------
|
||||
1 | 2026-05-24 | 14:30:22 | WL purchase | 50 | 0 | 000002 | 66 66 66 66 66 66
|
||||
2 | 2026-05-24 | 14:28:05 | WL purchase | 1000 | 0 | 000001 | 66 66 66 66 66 66
|
||||
[+] 2 records
|
||||
```
|
||||
|
||||
> **Note**: Record 1 is always the most recently written entry. Reading stops automatically
|
||||
> when the card returns a non-9000 SW (record number exceeds log capacity).
|
||||
|
||||
---
|
||||
|
||||
## Card Lifecycle
|
||||
|
||||
### block
|
||||
|
||||
BLOCK the entire card (CARD BLOCK, `INS 16`) or the currently selected application
|
||||
(APP BLOCK, `INS 1E`). Uses the line-protection key to compute a packet MAC over the
|
||||
command header via GET CHALLENGE.
|
||||
|
||||
```
|
||||
# Block the card permanently
|
||||
hf fmcos block --card --key 8a021972bfec9d152ca9eb82d7d12c09
|
||||
|
||||
# Block application temporarily (default)
|
||||
hf fmcos block --app --key 8a021972bfec9d152ca9eb82d7d12c09
|
||||
|
||||
# Block application permanently
|
||||
hf fmcos block --app --perm --key 8a021972bfec9d152ca9eb82d7d12c09
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--card` | Block the whole card |
|
||||
| `--app` | Block the current application |
|
||||
| `--perm` | Permanent block (default is temporary for `--app`) |
|
||||
| `--key <hex>` | Line-protection key (8 or 16 bytes) |
|
||||
|
||||
### unblock
|
||||
|
||||
UNBLOCK the currently selected application (APP UNBLOCK, `INS 18`).
|
||||
Same MAC pattern as block.
|
||||
|
||||
```
|
||||
hf fmcos unblock --key 8a021972bfec9d152ca9eb82d7d12c09
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--key <hex>` | Line-protection key (8 or 16 bytes) |
|
||||
|
||||
---
|
||||
|
||||
## File Access Reference
|
||||
|
||||
### MF (Master File)
|
||||
|
||||
- Automatically selected on card reset.
|
||||
- Can be selected at any DF level using FID `3F00` or the MF name.
|
||||
- Default name assigned at creation: `1PAY.SYS.DDF01`.
|
||||
|
||||
### DF (Directory File)
|
||||
|
||||
- Selected by file identifier (FID) or directory name (DF name).
|
||||
|
||||
### Binary EF (type `0x28`)
|
||||
|
||||
- Read with READ BINARY when the read condition is satisfied.
|
||||
- Updated with UPDATE BINARY when the write condition is satisfied.
|
||||
|
||||
### Fixed-Length Record EF (type `0x2A`)
|
||||
|
||||
- Read a specific record with READ RECORD when the read condition is satisfied.
|
||||
- Update a specific record with UPDATE RECORD when the write condition is satisfied.
|
||||
- Append a record at the end with APPEND RECORD when the append condition is satisfied.
|
||||
|
||||
### Cyclic (Loop) EF (type `0x2E`)
|
||||
|
||||
- Read a specific record with READ RECORD when the read condition is satisfied.
|
||||
- Prepend a new record at the front with APPEND RECORD when the append condition is satisfied.
|
||||
- When the file is full, the oldest record is automatically overwritten.
|
||||
- The most recently written record always has record number 1; the prior record is number 2; and so on.
|
||||
|
||||
### Wallet/Purse EF (EDEP/EP, type `0x2F`)
|
||||
|
||||
- GET BALANCE reads the current balance.
|
||||
- Under key control: CREDIT FOR LOAD (圈存), DEBIT FOR PURCHASE / CASH WITHDRAW (消费/取现),
|
||||
DEBIT FOR UNLOAD (圈提), and UPDATE OVERDRAFT LIMIT (修改透支限额).
|
||||
|
||||
### Variable-Length Record EF (type `0x2C`)
|
||||
|
||||
- Read a specific record with READ RECORD when the read condition is satisfied.
|
||||
- Update an existing record with UPDATE RECORD; append a new record with APPEND RECORD.
|
||||
- **TLV format:** each record is `Tag (1 byte) | Length (1 byte) | Value (Length bytes)`.
|
||||
Tag `0x00` is used by FMCOS for the standard record wrapper.
|
||||
- UPDATE RECORD requires the new record's total TLV length to equal the original; otherwise the
|
||||
command fails (SW `6A83`).
|
||||
|
||||
### KEY File (type `0x3F`)
|
||||
|
||||
- Only one KEY file is allowed per DF/MF; it **must be created before any other file** in that directory.
|
||||
- Key data can **never be read out** from the card.
|
||||
- While a DF/MF has no KEY file (and no other files), any file can be created and accessed without
|
||||
access-rights restrictions. Once you leave and re-enter that directory, access rights are enforced.
|
||||
- Each key is stored as a variable-length record: `key_data + 8 header bytes`.
|
||||
- Triple-DES (16-byte) key record: **24 bytes** total.
|
||||
- Single-DES (8-byte) key record: **16 bytes** total.
|
||||
- WRITE KEY adds a new key (when the "add key" permission is satisfied) or updates key data
|
||||
(when that specific key's "change" permission is satisfied).
|
||||
- Key data can only be used when the key's "use" permission is satisfied.
|
||||
|
||||
### Key Independence
|
||||
|
||||
Each key is bound to exactly one function (encrypt, decrypt, MAC, etc.) and cannot be used
|
||||
for any other function — including keys that generate, derive, or transport other card keys.
|
||||
|
||||
### PIN Key
|
||||
|
||||
- VERIFY checks the PIN; PIN CHANGE / UNBLOCK changes and optionally unlocks it.
|
||||
- On a successful VERIFY, the security-status register is updated to the post-condition value
|
||||
stored in the PIN key record.
|
||||
- An error counter decrements on every failed VERIFY; when it reaches 0 the PIN key is locked.
|
||||
|
||||
### Unlock-PIN Key
|
||||
|
||||
- UNBLOCK verifies the unlock password and simultaneously unlocks a PIN key that was blocked
|
||||
by repeated wrong attempts, while also setting a new PIN.
|
||||
- Once the unlock-PIN key's own error counter reaches 0, it is permanently locked with no recovery.
|
||||
|
||||
### External Authentication Key
|
||||
|
||||
- EXTERNAL AUTHENTICATE can be executed when the key's use condition is satisfied.
|
||||
- WRITE KEY updates the key when the change condition is satisfied.
|
||||
- Once locked by exhausting its error counter, it **cannot be unlocked**.
|
||||
|
||||
---
|
||||
|
||||
## Key Types Reference
|
||||
|
||||
FMCOS keys are stored in a keyfile EF. Each key entry begins with a type byte that
|
||||
encodes both the functional role (high nibble = 0x3x) and the line-protection mode
|
||||
OR-ed in by `--prot` when writing the key itself.
|
||||
|
||||
| Type name | Byte | Role |
|
||||
|-----------|------|------|
|
||||
| `desenc` | 0x30 | 3DES ECB encryption |
|
||||
| `desdec` | 0x31 | 3DES ECB decryption |
|
||||
| `desmac` | 0x32 | DES MAC generation |
|
||||
| `internal` | 0x34 | Internal-authenticate / TAC key |
|
||||
| `lineprotect` | 0x36 | Line-protection key (MAC-only or MAC+enc mode) |
|
||||
| `unlockpin` | 0x37 | Authorize PIN unblock |
|
||||
| `changepin` | 0x38 | Authorize PIN reset |
|
||||
| `extauth` | 0x39 | External-authenticate key |
|
||||
| `pin` | 0x3A | PIN code key |
|
||||
| `overdraft` | 0x3C | Overdraft-limit session key |
|
||||
| `debit` | 0x3D | Online-transfer (debit) session key |
|
||||
| `purchase` | 0x3E | Purchase / offline-debit session key |
|
||||
| `credit` | 0x3F | Credit session key |
|
||||
|
||||
---
|
||||
|
||||
## File Protection Modes
|
||||
|
||||
When creating a file or writing with protection, the `--prot` flag selects the mode:
|
||||
|
||||
| Mode | Value | Description |
|
||||
|------|-------|-------------|
|
||||
| `none` | 0x00 | No line protection |
|
||||
| `mac` | 0x80 | MAC-only; command includes 4-byte packet MAC, response includes MAC |
|
||||
| `enc` | 0xC0 | MAC + encryption; data encrypted, 4-byte MAC appended |
|
||||
|
||||
MAC is computed by `fmcos_packet_mac`: DES(8-byte key) or 3DES-Retail-MAC(16-byte key)
|
||||
over `CLA|INS|P1|P2|Lc[|data]` with a GET CHALLENGE response as the CBC IV.
|
||||
|
||||
---
|
||||
|
||||
## Access Rights Byte
|
||||
|
||||
The access-rights byte passed to `create file` controls whether line protection is needed
|
||||
and which key slot guards read / write access.
|
||||
|
||||
```
|
||||
Bit 7 (MSB): 1 = protection NOT required, 0 = protection required
|
||||
Bit 6-5: reserved
|
||||
Bits 4-3: read key index (11=key0, 10=key1, 01=key2, 00=key3)
|
||||
Bits 2-1 (LSB): write key index (11=key0, 10=key1, 01=key2, 00=key3)
|
||||
```
|
||||
|
||||
Common values:
|
||||
|
||||
| Value | Meaning |
|
||||
|-------|---------|
|
||||
| `ff` | No protection required, key0 for both read/write |
|
||||
| `7f` | Protection required, key0 for both read/write |
|
||||
| `f0` | No protection required (permission byte for directories/keys) |
|
||||
@@ -0,0 +1,697 @@
|
||||
# FMCOS Wallet Walkthrough
|
||||
|
||||
When commands are chained in a session the RF field must stay on between them.
|
||||
Add `-k` (keep field on) to every command in a chain except the last one.
|
||||
|
||||
## Keys used throughout
|
||||
|
||||
|
||||
| Variable | Hex |
|
||||
|---|---|
|
||||
| `external_auth_key` | `f49dc1ba1b4deb52647186bc59106c0d` |
|
||||
| `internal_key` | `2b8a438742c851566f02d881b09d58c0` |
|
||||
| `line_protection_key` | `8a021972bfec9d152ca9eb82d7d12c09` |
|
||||
| `unlock_pin_key` | `d8f60fa2d791f3a658d27c05458243ed` |
|
||||
| `change_pin_key` | `fb487a6d1b7cbf1bf84c666b8338376e` |
|
||||
| `purchase_key` | `eb18ce6986c820970e876219052ce0cf` |
|
||||
| `credit_key` | `a9e6e145f5df09500a58eef8575d49db` |
|
||||
| `debit_key` | `97fb4eda4b5237035946ee62d325d909` |
|
||||
| `overdraw_limit_key` | `94f63c4fae5e4977d749928ad12bc128` |
|
||||
| `int_enc` | `c4608b786af1992343e91a076670ae7c` |
|
||||
| `int_dec` | `b8d4190c76856901fc686f36ab9b1ce0` |
|
||||
| `int_mac` | `46a3ea8b254ee2749cc681050fd0dbcc` |
|
||||
| PIN (`\x12\x34\x56`) | `123456` (3 bytes, raw BCD) |
|
||||
| New PIN (`\x13\x37\x13\x37`) | `13371337` (4 bytes, raw BCD) |
|
||||
| Terminal ID | `666666666666` (6 bytes) |
|
||||
|
||||
---
|
||||
|
||||
## 1. reset — select MF and erase DF
|
||||
|
||||
Select the Master File then erase the application directory from a previous run:
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos erase
|
||||
```
|
||||
|
||||
`hf fmcos erase` sends INS=0x0E to delete the currently-selected DF and all
|
||||
its children. Run it only when the card already has a DF selected (the MF
|
||||
itself cannot be erased this way).
|
||||
|
||||
---
|
||||
|
||||
## 2. setup — create directory, keyfile, keys, loop files, balance files
|
||||
|
||||
### 2a. Create the application directory (ADF)
|
||||
|
||||
> **Note**: `--space` and `--size` arguments are parsed as **hexadecimal**.
|
||||
> `--space 1500` = 0x1500 = 5376 bytes, `--size 0208` = 0x0208 = 520 bytes.
|
||||
|
||||
`77616C6C657454657374` is the hex encoding of ASCII `walletTest`.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos create dir --id 3F01 --space 1500 --cperm F0 --eperm F0 --appid 95 --name 77616C6C657454657374 -k
|
||||
```
|
||||
|
||||
### 2b. Select the new ADF by name
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
```
|
||||
|
||||
All subsequent setup commands assume this DF remains selected (field stays on).
|
||||
|
||||
### 2c. Create the keyfile
|
||||
|
||||
```
|
||||
hf fmcos create keyfile --id 0000 --space 200 --dfsid 95 --perm F0 -k
|
||||
```
|
||||
|
||||
### 2d. Write keys
|
||||
|
||||
- `--op 01` = P1, authorization operation code (0x01 = add/update)
|
||||
- `--id 00` = P2, key slot to write (0x00 = auto-assign next slot)
|
||||
- `--usage F0` = usage rights byte
|
||||
|
||||
All key writes continue in the same session so every command carries `-k`.
|
||||
|
||||
**Key 0 — DES Encrypt (int_enc)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type desenc --change F4 --version 05 --algo 98 --key c4608b786af1992343e91a076670ae7c -k
|
||||
```
|
||||
|
||||
**Key 1 — DES Decrypt (int_dec)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type desdec --change F4 --version 05 --algo 98 --key b8d4190c76856901fc686f36ab9b1ce0 -k
|
||||
```
|
||||
|
||||
**Key 2 — DES MAC (int_mac)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type desmac --change F4 --version 05 --algo 98 --key 46a3ea8b254ee2749cc681050fd0dbcc -k
|
||||
```
|
||||
|
||||
**Key 3 — Internal Key (internal_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type internal --change 02 --version 00 --algo 01 --key 2b8a438742c851566f02d881b09d58c0 -k
|
||||
```
|
||||
|
||||
**Key 4 — File Line Protection Key (line_protection_key)**
|
||||
|
||||
Group C type — uses `--change` and `--errcount`.
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type lineprotect --change 02 --errcount 33 --key 8a021972bfec9d152ca9eb82d7d12c09 -k
|
||||
```
|
||||
|
||||
**Key 5 — Unlock PIN Key (unlock_pin_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type unlockpin --change 02 --errcount 33 --key d8f60fa2d791f3a658d27c05458243ed -k
|
||||
```
|
||||
|
||||
**Key 6 — Change PIN Key (change_pin_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type changepin --change 02 --errcount 33 --key fb487a6d1b7cbf1bf84c666b8338376e -k
|
||||
```
|
||||
|
||||
**Key 7 — External Authentication Key (external_auth_key)**
|
||||
|
||||
Group B type with `--change` — uses `--change`, `--followup`, and `--errcount`.
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type extauth --change 02 --followup 44 --errcount 33 --key f49dc1ba1b4deb52647186bc59106c0d -k
|
||||
```
|
||||
|
||||
**Key 8 — Purchase Key (purchase_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type purchase --change 02 --version 00 --algo 01 --key eb18ce6986c820970e876219052ce0cf -k
|
||||
```
|
||||
|
||||
**Key 9 — Credit Key (credit_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type credit --change 02 --version 00 --algo 01 --key a9e6e145f5df09500a58eef8575d49db -k
|
||||
```
|
||||
|
||||
**Key 10 — Debit Key (debit_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type debit --change 02 --version 00 --algo 01 --key 97fb4eda4b5237035946ee62d325d909 -k
|
||||
```
|
||||
|
||||
**Key 11 — Overdraw Limit Key (overdraw_limit_key)**
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type overdraft --change 02 --version 00 --algo 01 --key 94f63c4fae5e4977d749928ad12bc128 -k
|
||||
```
|
||||
|
||||
**Key 12 — PIN Key (pin_code)**
|
||||
|
||||
The PIN `\x12\x34\x56` is 3 raw BCD bytes.
|
||||
Group B type — uses `--followup` and `--errcount`.
|
||||
```
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type pin --followup 01 --errcount 33 --key 123456 -k
|
||||
```
|
||||
|
||||
### 2e. Create loop files for transaction logging
|
||||
|
||||
Loop file 0x0018 (to be linked to the wallet balance file):
|
||||
```
|
||||
hf fmcos create file --id 0018 --type loop --size 0517 --rperm F0 --wperm EF --access FF -k
|
||||
```
|
||||
|
||||
Loop file 0x0019 (to be linked to the passbook balance file):
|
||||
```
|
||||
hf fmcos create file --id 0019 --type loop --size 0517 --rperm F0 --wperm EF --access FF -k
|
||||
```
|
||||
|
||||
### 2f. Create wallet and passbook balance files
|
||||
|
||||
Wallet balance file (EF 0x0002, linked to loop file 0x0018):
|
||||
```
|
||||
hf fmcos create file --id 0002 --type wallet --size 0208 --rperm F0 --wperm 00 --access 18 -k
|
||||
```
|
||||
|
||||
Passbook balance file (EF 0x0001, linked to loop file 0x0019):
|
||||
```
|
||||
hf fmcos create file --id 0001 --type wallet --size 0208 --rperm F0 --wperm 00 --access 19
|
||||
```
|
||||
|
||||
The last command drops the field to end the setup session.
|
||||
|
||||
---
|
||||
|
||||
## 3. verify_pin — verify the PIN
|
||||
|
||||
The PIN `\x12\x34\x56` is 3 raw BCD bytes.
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. get_balance — read wallet and passbook balances
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos balance --type wallet -k
|
||||
hf fmcos balance --type passbook
|
||||
```
|
||||
|
||||
The command prints the 4-byte big-endian balance in decimal and hex.
|
||||
|
||||
---
|
||||
|
||||
## 5. add_money — credit (load funds)
|
||||
|
||||
Credit key index is 9 (written ninth in step 2d, 0-based index = 9 = 0x09).
|
||||
|
||||
Credit 1000 units to the wallet, then 2000 to the passbook in one session:
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos credit --type wallet --id 09 --amount 1000 --terminal 666666666666 --key a9e6e145f5df09500a58eef8575d49db --ikey 2b8a438742c851566f02d881b09d58c0 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos credit --type passbook --id 09 --amount 2000 --terminal 666666666666 --key a9e6e145f5df09500a58eef8575d49db --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
```
|
||||
|
||||
> **Note**: FMCOS resets the card's internal security status after each completed
|
||||
> financial transaction (Phase 1 + Phase 2). PIN verification must be repeated
|
||||
> before each credit or purchase operation, even within the same RF session.
|
||||
|
||||
`--key` is the credit_key (16-byte 3DES key used to derive the process key).
|
||||
`--ikey` is the internal_key used for TAC verification.
|
||||
|
||||
---
|
||||
|
||||
## 6. spend_wallet / spend_passbook — purchase (deduct funds)
|
||||
|
||||
Purchase key index is 8 (0-based index = 8 = 0x08).
|
||||
|
||||
Purchase (deduct) 50 units from the wallet:
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos purchase --type wallet --id 08 --amount 50 --terminal 666666666666 --key eb18ce6986c820970e876219052ce0cf --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
```
|
||||
|
||||
Purchase 50 units from the passbook:
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos purchase --type passbook --id 08 --amount 50 --terminal 666666666666 --key eb18ce6986c820970e876219052ce0cf --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
```
|
||||
|
||||
`--serial` (optional) sets the 4-byte transaction serial number; defaults to
|
||||
`00000001` when omitted.
|
||||
|
||||
---
|
||||
|
||||
## 7. withdraw_money — cash withdrawal (NOT SUPPORTED)
|
||||
|
||||
Cash withdrawal uses INS=0x50 P1=0x02. There is currently no `hf fmcos`
|
||||
command for this operation.
|
||||
|
||||
---
|
||||
|
||||
## 8. pin_block — deliberately block the PIN
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 11223344 -k
|
||||
hf fmcos pin verify --id 00 --pin 11223344 -k
|
||||
hf fmcos pin verify --id 00 --pin 11223344 -k
|
||||
hf fmcos pin verify --id 00 --pin 11223344
|
||||
```
|
||||
|
||||
After the error counter reaches zero the card blocks the PIN and returns
|
||||
SW=`6983`.
|
||||
|
||||
---
|
||||
|
||||
## 9. pin_unblock — restore a blocked PIN
|
||||
|
||||
Unlock PIN key index is 5 (0-based index = 5 = 0x05).
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin unblock --id 00 --pin 123456 --key d8f60fa2d791f3a658d27c05458243ed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. online_debit — online transfer (NOT SUPPORTED)
|
||||
|
||||
Online debit uses INS=0x50 P1=0x05 (initialize) and INS=0x54 P1=0x03
|
||||
(commit). There is currently no `hf fmcos` command for this operation.
|
||||
|
||||
---
|
||||
|
||||
## 11. update_overdraft — set the overdraft limit
|
||||
|
||||
Overdraft key index is 11 (0-based index = 11 = 0x0B).
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos overdraft --id 0B --limit 1000 --terminal 666666666666 --key 94f63c4fae5e4977d749928ad12bc128 --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
```
|
||||
|
||||
`--limit` is a 24-bit unsigned integer (maximum 16777215).
|
||||
|
||||
`--ikey` is the internal key (DTK, 16 bytes). When provided the card's 4-byte TAC response is
|
||||
verified using DES-CBC-MAC with `tac_key = XOR(ikey[0:8], ikey[8:16])` over:
|
||||
`balance[4] | online_serial[2] | new_limit[3] | 0x07[1] | terminal[6] | date[4] | time[3]`
|
||||
|
||||
---
|
||||
|
||||
## 12. get_history — read transaction history
|
||||
|
||||
Read the most recent 10 records from the wallet loop file (SFI 0x18):
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos history --fid 18
|
||||
```
|
||||
|
||||
Read up to 20 records from the passbook loop file (SFI 0x19):
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos history --fid 19 --count 20
|
||||
```
|
||||
|
||||
Example output (after a credit of 1000 and a purchase of 50):
|
||||
|
||||
```
|
||||
# | Date | Time | Type | Amount | OD Limit | Serial | Terminal
|
||||
---+------------+----------+--------------+------------+----------+--------+-------------------
|
||||
1 | 2026-05-24 | 14:30:22 | WL purchase | 50 | 0 | 000002 | 66 66 66 66 66 66
|
||||
2 | 2026-05-24 | 14:28:05 | WL purchase | 1000 | 0 | 000001 | 66 66 66 66 66 66
|
||||
[+] 2 records
|
||||
```
|
||||
|
||||
The SFI bytes (`18`, `19`) match the loop file IDs created in step 2e. Loop file record 1 is
|
||||
always the most recently written entry.
|
||||
|
||||
---
|
||||
|
||||
## 13. pin_change — change PIN using old PIN authorization
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos pin change --id 00 --old 123456 --new 13371337 -k
|
||||
hf fmcos pin verify --id 00 --pin 13371337 -k
|
||||
hf fmcos pin change --id 00 --old 13371337 --new 123456 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. pin_reset — set new PIN using change-PIN key (no old PIN needed)
|
||||
|
||||
Change PIN key index is 6 (0-based index = 6 = 0x06).
|
||||
|
||||
```
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos pin reset --id 00 --pin 13371337 --key fb487a6d1b7cbf1bf84c666b8338376e -k
|
||||
hf fmcos pin verify --id 00 --pin 13371337 -k
|
||||
hf fmcos pin change --id 00 --old 13371337 --new 123456 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete session (sequential)
|
||||
|
||||
The following block shows a full session in order: reset, setup, load money,
|
||||
spend, and check balance. Each sub-section starts a new session (field
|
||||
activates) and ends when the last command drops the field.
|
||||
|
||||
> **Note**: `--space` and `--size` are hex — `--space 1500` = 5376 bytes, `--space 400` = 1024 bytes, `--size 0517` = 1303 bytes, `--size 0208` = 520 bytes.
|
||||
|
||||
```
|
||||
# ── 1. Reset ────────────────────────────────────────────────────────────────
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos erase
|
||||
|
||||
# ── 2. Create ADF ────────────────────────────────────────────────────────────
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos create dir --id 3F01 --space 1500 --cperm F0 --eperm F0 --appid 95 --name 77616C6C657454657374 -k
|
||||
|
||||
# ── 3. Select ADF ────────────────────────────────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
|
||||
# ── 4. Create keyfile ────────────────────────────────────────────────────────
|
||||
hf fmcos create keyfile --id 0000 --space 400 --dfsid 95 --perm F0 -k
|
||||
|
||||
# ── 5. Write 13 keys (indexes 0-12) ─────────────────────────────────────────
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type desenc --change F4 --version 05 --algo 98 --key c4608b786af1992343e91a076670ae7c -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type desdec --change F4 --version 05 --algo 98 --key b8d4190c76856901fc686f36ab9b1ce0 -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type desmac --change F4 --version 05 --algo 98 --key 46a3ea8b254ee2749cc681050fd0dbcc -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type internal --change 02 --version 00 --algo 01 --key 2b8a438742c851566f02d881b09d58c0 -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type lineprotect --change 02 --errcount 33 --key 8a021972bfec9d152ca9eb82d7d12c09 -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type unlockpin --change 02 --errcount 33 --key d8f60fa2d791f3a658d27c05458243ed -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type changepin --change 02 --errcount 33 --key fb487a6d1b7cbf1bf84c666b8338376e -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type extauth --change 02 --followup 44 --errcount 33 --key f49dc1ba1b4deb52647186bc59106c0d -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type purchase --change 02 --version 00 --algo 01 --key eb18ce6986c820970e876219052ce0cf -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type credit --change 02 --version 00 --algo 01 --key a9e6e145f5df09500a58eef8575d49db -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type debit --change 02 --version 00 --algo 01 --key 97fb4eda4b5237035946ee62d325d909 -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type overdraft --change 02 --version 00 --algo 01 --key 94f63c4fae5e4977d749928ad12bc128 -k
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type pin --followup 01 --errcount 33 --key 123456 -k
|
||||
|
||||
# ── 6. Create loop files ─────────────────────────────────────────────────────
|
||||
hf fmcos create file --id 0018 --type loop --size 0517 --rperm F0 --wperm EF --access FF -k
|
||||
hf fmcos create file --id 0019 --type loop --size 0517 --rperm F0 --wperm EF --access FF -k
|
||||
|
||||
# ── 7. Create balance files ──────────────────────────────────────────────────
|
||||
hf fmcos create file --id 0002 --type wallet --size 0208 --rperm F0 --wperm 00 --access 18 -k
|
||||
hf fmcos create file --id 0001 --type wallet --size 0208 --rperm F0 --wperm 00 --access 19
|
||||
|
||||
# ── 8. Verify PIN ────────────────────────────────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456
|
||||
|
||||
# ── 9. Credit wallet +1000, passbook +2000 ───────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos credit --type wallet --id 09 --amount 1000 --terminal 666666666666 --key a9e6e145f5df09500a58eef8575d49db --ikey 2b8a438742c851566f02d881b09d58c0 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos credit --type passbook --id 09 --amount 2000 --terminal 666666666666 --key a9e6e145f5df09500a58eef8575d49db --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
|
||||
# ── 10. Check balances ───────────────────────────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos balance --type wallet -k
|
||||
hf fmcos balance --type passbook
|
||||
|
||||
# ── 11. Purchase (spend) from wallet then passbook ───────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos purchase --type wallet --id 08 --amount 50 --terminal 666666666666 --key eb18ce6986c820970e876219052ce0cf --ikey 2b8a438742c851566f02d881b09d58c0 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos purchase --type passbook --id 08 --amount 50 --terminal 666666666666 --key eb18ce6986c820970e876219052ce0cf --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
|
||||
# ── 12. Check balances again ─────────────────────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos balance --type wallet -k
|
||||
hf fmcos balance --type passbook
|
||||
|
||||
# ── 13. Update overdraft limit to 1000 ──────────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos pin verify --id 00 --pin 123456 -k
|
||||
hf fmcos overdraft --id 0B --limit 1000 --terminal 666666666666 --key 94f63c4fae5e4977d749928ad12bc128 --ikey 2b8a438742c851566f02d881b09d58c0
|
||||
|
||||
# ── 14. Read transaction history ─────────────────────────────────────────────
|
||||
hf fmcos select --name 77616C6C657454657374 -k
|
||||
hf fmcos history --fid 18 -k
|
||||
hf fmcos history --fid 19
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File operations walkthrough
|
||||
|
||||
That script demos binary/variable/loop file creation with line protection (none, MAC, MAC+enc),
|
||||
plus application block/unblock. Two DFs are created on the same card:
|
||||
|
||||
- **blockTest** (DF 3FFF, appid 0x94) — block/unblock target
|
||||
- **fileTest** (DF 3F01, appid 0x95) — file read/write target
|
||||
|
||||
### Keys used
|
||||
|
||||
| Variable | Hex |
|
||||
|---|---|
|
||||
| `internal_key` | `659a500f0f1fce35b6884bdff966576a` |
|
||||
| `line_protection_key` | `980093b4d77ff65f7476bf9019a80892` |
|
||||
| `external_auth_key` | `7c3f149ed331b11211d2fb62e2df9637` |
|
||||
| `line_protection_key_1` | `49439874a1f623fc5e14818365d34699` |
|
||||
| `external_auth_key_1` | `da152a9a56def40a1386ca258788fea6` |
|
||||
| `internal_key_1` | `bb4a314981b20ce696d6c1e1cda5820c` |
|
||||
| `enc_external_auth_key` | `44ea0184094995a845b612522a8ab463` |
|
||||
|
||||
DF names as hex: `626c6f636b54657374` = `blockTest`, `66696c6554657374` = `fileTest`
|
||||
|
||||
---
|
||||
|
||||
### reset
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos erase
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### setup — create both DFs
|
||||
|
||||
#### blockTest DF (3FFF)
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos create dir --id 3FFF --space 500 --cperm F0 --eperm F0 --appid 94 --name 626c6f636b54657374 -k
|
||||
hf fmcos select --name 626c6f636b54657374 -k
|
||||
hf fmcos create keyfile --id 0001 --space 200 --dfsid 94 --perm F0 -k
|
||||
```
|
||||
|
||||
Keys written into blockTest (keyfile 0001):
|
||||
|
||||
```
|
||||
# Key 0 — lineprotect (line_protection_key_1)
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type lineprotect --change 02 --errcount 33 --key 49439874a1f623fc5e14818365d34699 -k
|
||||
|
||||
# Key 1 — extauth (external_auth_key_1)
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type extauth --change F0 --followup AA --errcount FF --key da152a9a56def40a1386ca258788fea6 -k
|
||||
|
||||
# Key 2 — internal (internal_key_1)
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type internal --change F0 --version 00 --algo 01 --key bb4a314981b20ce696d6c1e1cda5820c -k
|
||||
```
|
||||
|
||||
Seed binary file 0x0002 in blockTest:
|
||||
|
||||
```
|
||||
hf fmcos create file --id 0002 --type bin --size 50 --rperm F0 --wperm F0 --access FF -k
|
||||
hf fmcos select --id 0002 -k
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 62696e66696c655f626c6f636b5f74657374
|
||||
```
|
||||
|
||||
(`62696e66696c655f626c6f636b5f74657374` = ASCII `binfile_block_test`)
|
||||
|
||||
#### fileTest DF (3F01)
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f00 -k
|
||||
hf fmcos create dir --id 3F01 --space 1500 --cperm F0 --eperm F0 --appid 95 --name 66696c6554657374 -k
|
||||
hf fmcos select --name 66696c6554657374 -k
|
||||
hf fmcos create keyfile --id 0001 --space 200 --dfsid 95 --perm F0 -k
|
||||
```
|
||||
|
||||
Keys written into fileTest (keyfile 0001). Keys 2 and 3 are written with MAC+enc line protection
|
||||
(`--prot enc --authkey <external_auth_key>`):
|
||||
|
||||
```
|
||||
# Key 0 — extauth (external_auth_key), unprotected write
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type extauth --change F0 --followup AA --errcount FF --key 7c3f149ed331b11211d2fb62e2df9637 -k
|
||||
|
||||
# Key 1 — internal (internal_key), unprotected write
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type internal --change F0 --version 00 --algo 01 --key 659a500f0f1fce35b6884bdff966576a -k
|
||||
|
||||
# Key 2 — lineprotect (line_protection_key), written with enc protection
|
||||
hf fmcos key --op 01 --id 00 --usage F0 --type lineprotect --change F0 --errcount FF --key 980093b4d77ff65f7476bf9019a80892 --authkey 7c3f149ed331b11211d2fb62e2df9637 --prot enc -k
|
||||
|
||||
# Key 3 (slot 02) — extauth (enc_external_auth_key), written with enc protection
|
||||
hf fmcos key --op 01 --id 02 --usage F0 --type extauth --change F0 --followup AA --errcount FF --key 44ea0184094995a845b612522a8ab463 --authkey 7c3f149ed331b11211d2fb62e2df9637 --prot enc -k
|
||||
```
|
||||
|
||||
Files created in fileTest. Three trios: unprotected (`--access FF`), MAC (`--access 7F --prot mac`),
|
||||
MAC+enc (`--access 7F --prot enc`). `--access 7F` = protection required, use key 0.
|
||||
|
||||
```
|
||||
# Binary files
|
||||
hf fmcos create file --id 0002 --type bin --size 50 --rperm F0 --wperm F0 --access FF -k
|
||||
hf fmcos create file --id 0003 --type bin --size 50 --rperm F0 --wperm F0 --access 7F --prot mac -k
|
||||
hf fmcos create file --id 0004 --type bin --size 50 --rperm F0 --wperm F0 --access 7F --prot enc -k
|
||||
|
||||
# Variable-length record files
|
||||
hf fmcos create file --id 0006 --type var --size 50 --rperm F0 --wperm F0 --access FF -k
|
||||
hf fmcos create file --id 0007 --type var --size 50 --rperm F0 --wperm F0 --access 7F --prot mac -k
|
||||
hf fmcos create file --id 0008 --type var --size 50 --rperm F0 --wperm F0 --access 7F --prot enc -k
|
||||
|
||||
# Loop (cyclic) files --size 210 = 0x210 = 528 bytes
|
||||
# space = record_count*(record_len+1)+8; e.g. 5 records × (0x50+1) + 8 = 0x19D
|
||||
hf fmcos create file --id 000A --type loop --size 210 --rperm F0 --wperm F0 --access FF -k
|
||||
hf fmcos create file --id 000B --type loop --size 210 --rperm F0 --wperm F0 --access 7F --prot mac -k
|
||||
hf fmcos create file --id 000C --type loop --size 210 --rperm F0 --wperm F0 --access 7F --prot enc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### write_binary
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f01 -k
|
||||
hf fmcos select --id 0002 -k
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 111213141516171819101a1b1c1d1e1f -k
|
||||
|
||||
hf fmcos select --id 0003 -k
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 212223242526272829202a2b2c2d2e2f --prot mac --key 980093b4d77ff65f7476bf9019a80892 -k
|
||||
|
||||
hf fmcos select --id 0004 -k
|
||||
hf fmcos write binary --p1 00 --p2 00 --data 313233343536373839303a3b3c3d3e3f --prot enc --key 980093b4d77ff65f7476bf9019a80892
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### write_loop (APPEND RECORD)
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f01 -k
|
||||
hf fmcos select --id 000a -k
|
||||
hf fmcos append --fid 0a --data 919293949596979899909a9b9c9d9e9f -k
|
||||
|
||||
hf fmcos select --id 000b -k
|
||||
hf fmcos append --fid 0b --data a1a2a3a4a5a6a7a8a9a0aaabacadaeaf --prot mac --key 980093b4d77ff65f7476bf9019a80892 -k
|
||||
|
||||
hf fmcos select --id 000c -k
|
||||
hf fmcos append --fid 0c --data b1b2b3b4b5b6b7b8b9b0babbbcbdbebf --prot enc --key 980093b4d77ff65f7476bf9019a80892
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### write_record (UPDATE RECORD)
|
||||
|
||||
P2 encodes the SFI: `(file_id & 0x1F) << 3 | 4`. The CLI `--fid` takes the raw file ID byte
|
||||
(1–30) and encodes P2 automatically.
|
||||
|
||||
Variable-length files require `--tlv` so the data is wrapped as `00[len][data]`.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f01 -k
|
||||
hf fmcos select --id 0006 -k
|
||||
hf fmcos write record --rec 1 --fid 06 --data 515253545556575859505a5b5c5d5e5f --tlv -k
|
||||
|
||||
hf fmcos select --id 0007 -k
|
||||
hf fmcos write record --rec 1 --fid 07 --data 616263646566676869606a6b6c6d6e6f --tlv --prot mac --key 980093b4d77ff65f7476bf9019a80892 -k
|
||||
|
||||
hf fmcos select --id 0008 -k
|
||||
hf fmcos write record --rec 1 --fid 08 --data 717273747576777879707a7b7c7d7e7f --tlv --prot enc --key 980093b4d77ff65f7476bf9019a80892
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### read_binary
|
||||
|
||||
For MAC-protected reads the card appends a 4-byte MAC before the SW; the CLI strips it automatically.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f01 -k
|
||||
hf fmcos select --id 0002 -k
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 16 -k
|
||||
|
||||
hf fmcos select --id 0003 -k
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 16 --prot mac --key 980093b4d77ff65f7476bf9019a80892 -k
|
||||
|
||||
hf fmcos select --id 0004 -k
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 16 --prot enc --key 980093b4d77ff65f7476bf9019a80892
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### read_record
|
||||
|
||||
Variable-length files need `--tlv`; the CLI requests 2 extra bytes and strips the `00[len]` prefix before printing.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f01 -k
|
||||
hf fmcos read record --rec 01 --fid 06 --len 16 --tlv -k
|
||||
hf fmcos read record --rec 01 --fid 07 --len 16 --tlv --prot mac --key 980093b4d77ff65f7476bf9019a80892 -k
|
||||
hf fmcos read record --rec 01 --fid 08 --len 16 --tlv --prot enc --key 980093b4d77ff65f7476bf9019a80892
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### read_loop
|
||||
|
||||
Loop files use the same READ RECORD command; `--rec 01` reads the most recently appended record.
|
||||
|
||||
```
|
||||
hf fmcos select --id 3f01 -k
|
||||
hf fmcos read record --rec 01 --fid 0a --len 16 -k
|
||||
hf fmcos read record --rec 01 --fid 0b --len 16 --prot mac --key 980093b4d77ff65f7476bf9019a80892 -k
|
||||
hf fmcos read record --rec 01 --fid 0c --len 16 --prot enc --key 980093b4d77ff65f7476bf9019a80892
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### card_block / app_block
|
||||
|
||||
Permanent application block
|
||||
|
||||
```
|
||||
hf fmcos select --name 626c6f636b54657374 -k
|
||||
hf fmcos block --app --perm --key 49439874a1f623fc5e14818365d34699
|
||||
```
|
||||
|
||||
Temporary application block:
|
||||
|
||||
```
|
||||
hf fmcos select --name 626c6f636b54657374 -k
|
||||
hf fmcos block --app --key 49439874a1f623fc5e14818365d34699
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### app_unblock
|
||||
|
||||
After a block the app cannot be selected normally (SELECT returns an error SW), but the DF is still
|
||||
addressed. Send unblock while the field is still on from the failed select, then re-select:
|
||||
|
||||
```
|
||||
hf fmcos select --name 626c6f636b54657374 -k
|
||||
hf fmcos unblock --key 49439874a1f623fc5e14818365d34699 -k
|
||||
hf fmcos select --name 626c6f636b54657374 -k
|
||||
hf fmcos select --id 0002 -k
|
||||
hf fmcos read binary --p1 00 --p2 00 --len 16
|
||||
```
|
||||
Reference in New Issue
Block a user