|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +A Python GUI encryption/decryption tool (Tkinter) using AES-CBC with PBKDF2-HMAC-SHA256 key derivation. Supports text and file operations with drag-and-drop, progress tracking, and Chinese/English i18n. |
| 8 | + |
| 9 | +## Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Run the application |
| 13 | +python main.py |
| 14 | + |
| 15 | +# Install dependencies |
| 16 | +pip install -r requirements.txt |
| 17 | + |
| 18 | +# Build standalone executable with PyInstaller |
| 19 | +pyinstaller main.spec |
| 20 | +``` |
| 21 | + |
| 22 | +No test suite or linter is configured in this project. |
| 23 | + |
| 24 | +## Architecture |
| 25 | + |
| 26 | +### `main.py` — GUI layer (EncryptApp) |
| 27 | + |
| 28 | +Single-class Tkinter application inheriting from either `TkinterDnD.Tk` (if `tkinterdnd2` is installed) or `tk.Tk` (fallback). Key design points: |
| 29 | + |
| 30 | +- **i18n**: All UI strings live in the `TRANSLATIONS` dict at module level, keyed by semantic name (e.g. `"missing_pwd_msg"`) with `en`/`zh` values. `EncryptApp.tr(key)` resolves a key to the current language. Widgets are registered via `register_widget(widget, key, attr)` and batch-updated by `update_language()`. The language combobox triggers `update_language` on `<<ComboboxSelected>>`. |
| 31 | +- **Settings persistence**: `settings.json` is loaded on startup (`load_settings`) and written whenever paths, language, or iterations change (`save_settings`). Four keys: `enc_output_path`, `dec_output_path`, `language`, `iterations`. |
| 32 | +- **File operations run on daemon threads** (`_run_file_op` → `threading.Thread`). UI updates are posted back via `self.after(0, ...)`. Progress callbacks update `ttk.Progressbar` values as percentages. |
| 33 | +- **MAX_ITERATIONS** is 100,000,000, enforced in `check_iterations()`. |
| 34 | + |
| 35 | +### `crypto_manager.py` — Crypto logic (CryptoManager) |
| 36 | + |
| 37 | +Stateless crypto operations class (no constructor logic). Key constants: `SALT_SIZE=16`, `IV_SIZE=16`, `CHUNK_SIZE=64KB`, `ITERATIONS=10000` (overridable at runtime via the GUI — the app sets `crypto.ITERATIONS` from user input). |
| 38 | + |
| 39 | +- **`_derive_key(password, salt, key_length)`**: PBKDF2HMAC with SHA256. Iterations come from `self.ITERATIONS`. |
| 40 | +- **Text encrypt/decrypt**: Encodes text as UTF-8, applies PKCS7 padding, encrypts with AES-CBC. Output format: `base64(salt + iv + ciphertext)`. No authentication tag (no HMAC/GCM) — decryption failures surface as padding errors or garbage output. |
| 41 | +- **File encrypt/decrypt**: Streams data in 64KB chunks. Writes `[salt][iv][encrypted_stream]` to output. Uses PKCS7 padding — for encryption the padder accumulates chunks and finalizes at EOF; for decryption the unpadder strips padding at EOF. |
| 42 | +- Algorithm mapping: `{"AES-128": 16, "AES-192": 24, "AES-256": 32}` (key lengths in bytes). |
| 43 | + |
| 44 | +### `hook-tkinterdnd2.py` — PyInstaller hook |
| 45 | + |
| 46 | +Collects `tkinterdnd2` data files for PyInstaller bundling. Referenced by `main.spec` via `hookspath=['.']`. |
| 47 | + |
| 48 | +### `main.spec` — PyInstaller spec |
| 49 | + |
| 50 | +Builds a windowed (no console) single-directory bundle with `encryption.ico` as the icon. Entry point is `main.py`. |
| 51 | + |
| 52 | +### Android App (`android/`) |
| 53 | + |
| 54 | +Kotlin + Jetpack Compose native Android port (API 26+). Same crypto format as the Python version — ciphertext produced by either platform can be decrypted by the other. |
| 55 | + |
| 56 | +```bash |
| 57 | +# Run unit tests |
| 58 | +cd android && ./gradlew testDebugUnitTest |
| 59 | + |
| 60 | +# Build debug APK |
| 61 | +cd android && ./gradlew assembleDebug |
| 62 | +# Output: android/app/build/outputs/apk/debug/app-debug.apk |
| 63 | +``` |
| 64 | + |
| 65 | +**Architecture (MVVM + Clean Architecture):** |
| 66 | + |
| 67 | +- `core/crypto/CryptoManager.kt` — Pure Kotlin crypto engine using javax.crypto (JCA). Produces byte-identical output to `crypto_manager.py`. Uses `"AES/CBC/PKCS5Padding"` (JVM PKCS5 = PKCS7 for 16-byte blocks) and `PBKDF2WithHmacSHA256`. |
| 68 | +- `core/data/SettingsRepository.kt` — Jetpack DataStore persistence, replaces `settings.json`. |
| 69 | +- `core/di/AppModule.kt` — Hilt DI module providing singletons. |
| 70 | +- `ui/viewmodel/` — StateFlow-based ViewModels managing UI state via UDF pattern. Crypto operations run on `Dispatchers.IO`. |
| 71 | +- `ui/screens/` — Compose screens with responsive layout: three-column on wide (>=840dp), TabRow on narrow. |
| 72 | +- `ui/components/` — Reusable Composables: PasswordField, AlgorithmDropdown, IterationsField, ResultLog, FilePickerCard, OutputDirSelector. |
| 73 | + |
| 74 | +**i18n**: Android resource-based (`res/values/strings.xml` + `res/values-zh/strings.xml`), runtime switching via `AppCompatDelegate.setApplicationLocales()`. |
| 75 | + |
| 76 | +**CI/CD**: `.github/workflows/android-build.yml` — triggers on push to `main`/`master` when `android/**` changes. Runs unit tests → builds debug APK → uploads as artifact. Uses `gradle/actions/setup-gradle@v4` with Gradle 8.7. |
| 77 | + |
| 78 | +**Gradle wrapper**: For local builds, install Android Studio (auto-generates wrapper) or run `gradle wrapper` in the `android/` directory. CI uses `gradle-version` parameter and does not require the wrapper jar. |
| 79 | + |
| 80 | +**Cross-platform test vectors**: `test_vectors.json` (generated by Python) is consumed by `CryptoManagerTest.kt` to verify byte-level compatibility. |
| 81 | + |
| 82 | +## i18n Pattern |
| 83 | + |
| 84 | +To add a new translatable string: |
| 85 | +1. Add entries to `TRANSLATIONS` dict in `main.py`. |
| 86 | +2. For static labels: call `self.register_widget(widget, "key_name")` after creating the widget. |
| 87 | +3. For dynamic strings (message boxes, status labels): call `self.tr("key_name")` at the point of use. |
0 commit comments