Files
otp-import/README.md
Amal Graafstra 602bbc13f7 Add --reset and post-import --set-password; fix algorithm nibble parsing
Add two admin operations on the OATH protocol layer: --reset (RESET
0x04/0xDEAD) and --set-password, which sets an access password after a
successful import only if the applet has none. Fix _parse_select to mask
the SELECT ALGORITHM tag to its low nibble (the applet reports the full
type|algo byte, e.g. 0x21), which previously broke validate on a locked
applet. Add a clean top-level OathError handler.
2026-07-08 11:38:50 -07:00

73 lines
2.8 KiB
Markdown

# otp-import
Import TOTP credentials from an exported spreadsheet into a VivoKey Apex OTP
(ykneo-oath) applet over PC/SC.
The importer reads the curated columns of an export spreadsheet
(`otp-keys-export.xlsx`: Issuer, Account, Secret, Type, Algorithm, Digits,
Period) and writes each credential to the applet using the standard YKOATH
`PUT` command. It authenticates first if the applet is password-protected, asks
before overwriting credentials that already exist, and can optionally profile
per-credential on-chip memory consumption via the `javacard-memory` applet.
The protocol layer is verified against the applet sources
(`com.vivokey.otp.YkneoOath` / `OathObj`) and `doc/Protocol.txt`. See
[docs/design.md](docs/design.md) for the full design and protocol notes.
## Security
This tool handles live TOTP secrets. **Keep your secrets out of this
repository.** The spreadsheet, any CSV, and QR screenshots are excluded by
`.gitignore`; keep the actual data in a private location (e.g. a synced
personal folder) and point the importer at it with `--input`.
## Requirements
- Python 3.9+
- `pyscard`, `cryptography`, `openpyxl`
- A PC/SC reader with the Apex (or a JavaCard carrying the applet) presented
## Usage
```
# 1. Validate the data and preview the APDUs (no card needed)
python apex_otp_import.py --input /path/to/otp-keys-export.xlsx --dry-run
# 2. Read-only: list what is already on the applet
python apex_otp_import.py --input /path/to/otp-keys-export.xlsx --list
# 3. Import (asks before overwriting existing credentials)
python apex_otp_import.py --input /path/to/otp-keys-export.xlsx
# Non-interactive conflict handling
python apex_otp_import.py --input ... --overwrite-all
python apex_otp_import.py --input ... --skip-existing
# Target a specific reader, supply a password, and profile memory
python apex_otp_import.py --input ... --reader VivoKey --password '...' --profile-memory
# Import, then set an access password (only if the applet has none yet)
python apex_otp_import.py --input ... --set-password 'yourpassword'
# Reset: wipe all credentials and any password (standalone; no input needed)
python apex_otp_import.py --reset
```
Authenticating to a password-protected applet uses the standard YKOATH scheme
(PBKDF2-HMAC-SHA1 of the password with the device id as salt, then mutual
challenge-response). `--set-password` only sets a password on an applet that has
none; it does not change or remove an existing one. `--reset` clears everything.
The input is validated before any reader is touched. Duplicate credential names,
invalid Base32, over-long names/keys, and unsupported algorithms halt the run
with a report so they can be fixed in the source data.
## Tests
Hardware-free unit tests cover the protocol encoding, password derivation,
input validation, and response reassembly:
```
python test_oath.py
```