CipherGrid: A Mobile OCR-Assisted Multi-Cipher Encryption, Batch Processing, and Cryptanalysis Application
CipherGrid is an offline-first Ionic Vue application for learning, applying, and analyzing cryptographic transformations. It combines an explainable classical-cipher workspace, deterministic cryptanalysis, on-device OCR, batch file processing, reusable local recipes, QR exchange, encoding utilities, and a deliberately separate AES-256-GCM Secure Lab.
Classical ciphers are educational and are not secure for real secrets. Base64, hexadecimal, and binary are encodings, not encryption. SHA-256 is a one-way digest and cannot be decrypted.
- Feature overview
- History and saved data
- Technology stack
- Requirements
- Installation
- Available commands
- Application structure
- Android development
- OCR and offline behavior
- Testing and quality checks
- Continuous integration and releases
- Contributing
- Privacy and security boundaries
- Known limitations
- Troubleshooting
The registry-driven workspace supports encryption, decryption, validation, saved results, copy/share actions, QR handoff, and step-by-step explanations for:
- Caesar, including normalized shifts and all 26 brute-force candidates
- Vigenère with alphabetic keyword validation and repeated-key visualization
- Atbash
- Affine with modular-inverse validation and candidate ranking
- Rail Fence with zigzag visualization and rail-count comparison
- Columnar Transposition with stable duplicate-key ordering
- Playfair with a 5×5 I/J key square and visible filler handling
- Hill with invertible 2×2 and 3×3 matrices
- Plaintext Autokey with running-key explanation
Cipher implementations are pure TypeScript services. They do not depend on Vue components and return structured output, warnings, metadata, and explanation steps.
The Analyze workspace provides deterministic, explainable tools rather than presenting scoring as machine learning:
- Caesar and Affine candidate ranking
- English and Filipino local scoring profiles
- Rail Fence candidate comparison
- Letter frequencies, n-grams, text statistics, and Index of Coincidence
- Kasiski repeated-sequence examination
- Vigenère key-length estimates and per-column frequency analysis
- Editable candidate-key suggestions
- Cautious possible-family hints with uncertainty language
- Camera capture and gallery selection through Capacitor Camera
- Android ML Kit and iOS Vision through an
OcrServiceadapter - Lazy-loaded Tesseract worker fallback for browsers and PWAs
- OCR text correction and recognized-region selection
- Send-to-Encrypt, Decrypt, or Analyze actions
- Local processing by default; no cloud OCR service or API key is required
- Import
.txtand.csvfiles - Preview CSV mappings and use global or per-row cipher settings
- Validate rows independently and track pending, successful, warning, and failed counts
- Chunk processing, progress reporting, cancellation, correction, and retry
- Export new CSV or TXT results without overwriting the source file
- Build editable local Recipes with visible intermediate outputs
- AES-256-GCM through the Web Crypto API
- PBKDF2-HMAC-SHA-256 with 310,000 iterations
- Fresh random salt and IV for every encryption
- Versioned portable payloads and generic authentication-failure messages
- UTF-8-safe Base64, hexadecimal, and binary conversion
- SHA-256 with an explicit one-way warning
- Home, Workspace, Scan, Analyze, and Library primary destinations
- Interactive lessons with simple and technical views
- QR generation and compatible payload scanning where supported
- Opt-in IndexedDB history with individual and bulk deletion
- Preferences-backed settings and draft preservation
- Animated light/dark theme switch with reduced-motion support
- Responsive mobile-first UI, keyboard focus states, and safe-area handling
- Installable offline PWA with route-level feature loading
History is implemented and deliberately disabled by default. This prevents the app from retaining plaintext or ciphertext until the user explicitly opts in.
To enable it:
- Open the Settings gear in the app header, or choose History settings from Library.
- Enable Allow explicit Save actions to write local history.
- Choose a retention period.
- Press Save preferences.
- Return to Workspace and use Save on a generated result.
Saved cipher records are written to the local ciphergrid-local IndexedDB database and appear under Library → Saved results. Each record contains the algorithm, operation, input, output, and creation time. Users can delete individual records, clear all history, or clear all structured local records. AES passphrases are never stored.
| Area | Technology |
|---|---|
| UI | Ionic Vue 8, Vue 3 Composition API, TypeScript |
| Build | Vite 8, Vue TSC |
| State | Pinia |
| Routing | Ionic Vue Router |
| Native runtime | Capacitor 8 |
| Persistence | IndexedDB for records, Capacitor Preferences for settings |
| Modern crypto | Web Crypto API |
| Native OCR | @jcesarmobile/capacitor-ocr |
| Browser OCR | tesseract.js with locally copied English data |
| Tests | Vitest and jsdom |
| PWA | vite-plugin-pwa and Workbox |
For web development:
- Node.js 22 LTS
- npm, using the committed
package-lock.json - A modern browser with Web Crypto support
For Android development:
- Android Studio or Android command-line tools
- Android SDK 36
- Temurin Java 21
- A configured
ANDROID_HOMEor Android Studio-managed SDK
Capacitor 8 in this repository is built with Java 21. Do not copy Java 17 from older Capacitor workflows.
Clone the repository, install the locked dependencies, and start Vite:
git clone <repository-url>
cd CypherGrid
npm ci
npm run devOpen the local URL printed by Vite. The first launch shows onboarding; it can be reopened from the compass button in the Home header.
The npm postinstall script copies the packaged Tesseract English model from @tesseract.js-data/eng to public/tessdata. That generated model file is intentionally ignored by Git because it can be recreated from the locked dependency.
To create and preview a production build:
npm run build
npm run previewUse npm install <package> only when intentionally changing dependencies. Use npm ci for clean, reproducible installs and CI parity.
| Command | Purpose |
|---|---|
npm run dev |
Start the Vite development server |
npm run lint |
Run ESLint with zero warnings allowed |
npm run typecheck |
Run strict Vue and TypeScript checking |
npm run test -- --run |
Run the Vitest suite once |
npm run test |
Start Vitest in its default interactive mode |
npm run build |
Type-check and build the production PWA |
npm run preview |
Serve the built dist directory locally |
npm run format |
Apply ESLint auto-fixes where supported |
npx cap sync android |
Copy the current web build and update Android plugins |
npx cap open android |
Open the native project in Android Studio |
src/
components/
common/ shared shell and theme controls
models/ discriminated cipher and feature contracts
pages/ lazy-loaded feature screens
router/ Ionic Vue routes and onboarding guard
services/
analysis/ statistics and deterministic ranking
ciphers/ pure algorithms and registry
files/ CSV/TXT parsing and batch engine
ocr/ native and browser OCR adapters
qr/ versioned QR helpers
recipes/ visible workflow execution
secure/ Web Crypto AES-256-GCM
storage/ IndexedDB persistence
utilities/ encoding and hashing
stores/ Pinia settings and workspace drafts
tests/ Vitest suites
theme/ shared field-terminal design tokens
android/ generated and maintained Capacitor Android project
public/assets/ logo and application artwork
scripts/copy-ocr-data.mjs reproducible local OCR-data copy
.github/workflows/ verification and Android artifact workflow
Path aliases use TypeScript paths and the matching Vite alias. The project does not use the deprecated TypeScript baseUrl option.
Build the web application before synchronizing it into Android:
npm run build
npx cap sync android
npx cap open androidCommand-line debug build on macOS or Linux:
cd android
./gradlew test assembleDebugOn Windows PowerShell:
cd android
./gradlew.bat test assembleDebugThe debug APK is written to:
android/app/build/outputs/apk/debug/app-debug.apk
Run npm run build and npx cap sync android again whenever web assets or Capacitor plugins change.
Launcher icons, adaptive foregrounds, PWA artwork, and Android splash images are derived from public/assets/ciphergrid-logo.png. After changing the source logo, regenerate the platform artwork on Windows with:
./scripts/generate-brand-assets.ps1CI verifies compilation and packages the native OCR dependency, but it cannot prove camera behavior or OCR accuracy. Test on a physical Android device before a release:
- Deny camera permission and confirm the app shows a recoverable error.
- Grant permission and capture printed English, Filipino, and cipher-text samples.
- Repeat with punctuation, mixed case, rotation, low light, glare, and slight blur.
- Select the same samples from the gallery and compare recognized blocks.
- Disable networking, clear app storage, relaunch, and verify bundled-model OCR.
- Correct recognized text, select a subset, and send it to Encrypt, Decrypt, and Analyze.
On iOS, add the platform on macOS with npx cap add ios, then repeat the permission, orientation, and Apple Vision checks on a physical device.
- Android:
@jcesarmobile/capacitor-ocr0.3.0 packagescom.google.mlkit:text-recognition:16.0.1, including the Latin-script model in the application. - iOS: the same adapter uses Apple Vision.
- Web/PWA:
tesseract.jsis dynamically imported only when browser OCR begins. Its English model is copied locally and included in the service-worker cache. - UI components depend on the project
OcrServicecontract, not directly on the native plugin. - Images and recognized text are not uploaded by the standard OCR path.
- PWA offline availability begins after one successful load and service-worker installation.
Run the same web checks used by CI before opening a pull request:
npm run lint
npm run typecheck
npm run test -- --run
npm run buildIf Android-related code, dependencies, or generated web assets changed, also run:
npx cap sync android
cd android
./gradlew test assembleDebugThe unit tests cover published vectors, encryption/decryption round trips, invalid keys, empty input, punctuation, mixed case, Unicode behavior, padding conventions, AES authentication and randomness, cryptanalysis helpers, and batch mapping/failure isolation.
Reference vectors include:
- Caesar:
HELLO, shift3→KHOOR - Vigenère:
ATTACKATDAWN, keyLEMON→LXFOPVEFRNHR - Atbash:
HELLO→SVOOL - Affine:
AFFINECIPHER,a=5,b=8→IHHWVCSWFRCP - Rail Fence:
WEAREDISCOVEREDFLEEATONCE, rails3→WECRLTEERDSOEEFEAOCAIVDEN - Playfair: key
PLAYFAIR EXAMPLE, inputHIDETHEGOLDINTHETREESTUMP→BMODZBXDNABEKUDMUIXMMOUVIF - Hill: key
GYBNQKURP, inputACT→POH
The Verify and Build Android workflow runs for pushes and pull requests targeting main, plus manual dispatches. It:
- Installs locked dependencies with Node.js 22.
- Configures Temurin Java 21 and the Android SDK.
- Runs linting, type-checking, Vitest, and the production web build.
- Synchronizes Capacitor and verifies copied web assets.
- Runs Gradle tests and builds a versioned debug APK.
- Uploads the debug APK for 14 days.
The current workflow does not require repository secrets. Gradle signs debug APKs with its automatically generated debug key, which is sufficient for development, classroom testing, and direct installation on test devices.
A private release keystore is needed only when publishing a production build to an app store or maintaining upgrade compatibility for released installations. Release signing is intentionally not configured yet. When distribution is planned, create and protect a project-owned keystore, configure encrypted repository secrets, and document the recovery/ownership process before adding a release job. Never commit keystores, passwords, or android/local.properties.
Download the template in the app or start with:
text,algorithm,operation,key,shift,rails,a,b
"KHOOR",caesar,decrypt,,3,,,
"ATTACK AT DAWN",vigenere,encrypt,LEMON,,,,Supported algorithm identifiers are caesar, vigenere, atbash, affine, rail-fence, columnar, playfair, hill, and autokey. Per-row values override the fallback configuration. Imported values remain plain text and are never rendered as HTML.
Contributions should preserve algorithm correctness, privacy, accessibility, and the distinction between educational ciphers and modern encryption.
- Read this README before making broad changes.
- Create a focused branch from the current
mainbranch. - Install dependencies with
npm ci. - Keep cipher, analyzer, parser, and scoring logic in pure TypeScript services.
- Add or update tests for every behavior change and regression fix.
- Run the complete verification commands before submitting a pull request.
- Include screenshots for visible UI changes at a mobile width and in both themes.
- Explain any native behavior that could not be exercised locally.
- Use Vue 3 Composition API with
<script setup lang="ts">. - Preserve strict typing and discriminated unions; do not introduce
anywithout a compelling boundary reason. - Keep route features lazy-loaded and browser-safe.
- Centralize user-facing validation instead of duplicating error logic in components.
- Do not log plaintext keys, AES passphrases, imported documents, or OCR content.
- Do not call classical ciphers secure or describe Base64 as encryption.
- Use rectangular, accessible controls consistent with the field-terminal design system.
- Preserve minimum 44×44 px touch targets, focus-visible states, reduced-motion behavior, and screen-reader labels.
- Avoid unrelated dependency upgrades or generated secrets.
- The change has a clear scope and no unrelated rewrites.
-
npm run lintpasses. -
npm run typecheckpasses. -
npm run test -- --runpasses. -
npm run buildpasses. - Android was synchronized and built when native-facing files changed.
- New algorithms or transformations include known vectors and round-trip tests.
- Privacy/security wording remains accurate.
- Documentation and screenshots are updated where needed.
- CipherGrid has no account requirement, backend, analytics service, Firebase dependency, cloud OCR API, or application secret key.
- History is local, optional, and user-controllable.
- AES passphrases are never persisted.
- QR payloads omit secret key material by default and warn before including it.
- Imported filenames and content are treated as untrusted text.
- Native sharing and file export happen only after explicit user action.
- Authentication failures in Secure Lab do not reveal whether a passphrase, payload, or ciphertext component was wrong.
Report security-sensitive issues privately to the repository maintainer rather than including secrets or exploit details in a public issue.
- Most classical-cipher arithmetic targets ASCII
A-Z. Caesar, Vigenère, Atbash, Affine, and Autokey preserve non-ASCII characters; Playfair and Hill intentionally normalize toA-Z. - Playfair shares I/J and retains decrypted filler characters rather than silently removing a legitimate
XorQ. - Hill adds visible
Xpadding and normalizes formatting. - Columnar Transposition preserves exact length without padding and uses stable left-to-right duplicate-key ordering.
- Browser QR image scanning depends on
BarcodeDetector; unsupported browsers retain QR generation and manual payload entry. - The bundled web OCR model is English. It can recognize Filipino Latin-script text, but no dedicated Filipino model is packaged.
- Camera behavior, OCR accuracy, device sharing, and permission recovery require physical-device testing.
- A successful CI build proves compilation and packaging, not camera quality or OCR accuracy.
The current tsconfig.json does not use baseUrl. The @/* alias is resolved through TypeScript paths and the matching Vite alias. If the warning remains, restart the IDE TypeScript server so it reloads the project configuration.
Open the project through Android Studio or set ANDROID_HOME to the installed SDK. Local SDK paths belong in android/local.properties, which is ignored by Git.
Run npm ci or npm install again. The postinstall script should recreate:
public/tessdata/eng.traineddata.gz
Rebuild and synchronize before reopening Android Studio:
npm run build
npx cap sync androidOnboarding completion is stored locally. Use the compass button in the Home header, or clear the cg-onboarding key from browser local storage during development.
The warning is non-fatal. Feature routes and browser OCR are lazy-loaded; review bundle changes before adding large dependencies rather than increasing the warning threshold without investigation.
