Offline-first encrypted Android keyboard for physically QR-paired messaging.
CipherBoard is an offline-first encrypted text keyboard for Android, designed primarily for current GrapheneOS devices. It combines a HeliBoard-based input method with local identities, physical QR pairing, an embedded Private panel, and a protected message viewer.
CipherBoard is an unofficial modified fork of HeliBoard. It is not an official HeliBoard release and is not endorsed or supported by the HeliBoard project.
Warning
CipherBoard is pre-1.0 security-sensitive software. It uses reviewed cryptographic primitives and has automated test coverage, but the complete product has not received an independent applied-cryptography and Android security audit. Do not treat it as audited or risk-free.
| Project fact | Current value |
|---|---|
| Maturity | Pre-1.0; current version 0.2.0 |
| Application ID | org.cipherboard.securekeyboard |
| Android baseline | minSdk 23, targetSdk 36; acceptance target is current GrapheneOS |
| Release ABI | arm64-v8a; debug builds also include x86_64 for emulators |
| Runtime network | No Internet or network-state permission; no runtime network feature |
| Interface languages | English and Russian |
See the bilingual CipherBoard 0.2.0 release notes.
Two people can install the same APK and exchange encrypted text without accounts, phone numbers, email addresses, or a CipherBoard server:
- Each device creates a local cryptographic identity inside an authenticated Vault.
- The devices pair in person by scanning an offer QR code and a response QR code.
- Both people compare the same Safety Number before marking the contact as verified.
- The sender taps the shield to switch the keyboard into Private mode and writes in the CipherBoard-owned panel above the keys.
- CipherBoard advances and durably stores the Olm ratchet, then commits only a
CB1:ciphertext envelope to the external app. - The recipient selects the ciphertext and uses Decrypt in CipherBoard. Plaintext is displayed in a protected, read-only CipherBoard window and is not returned to the transport app.
The transport can be SMS, email, a messenger, or any other application that can carry text. CipherBoard does not send messages itself.
- No
android.permission.INTERNET, network client, Firebase, Google Play Services, analytics, advertising, or crash-reporting SDK is part of the runtime design. - Pairing is local and serverless. Version 1 supports physical two-way QR pairing only.
- The cryptographic core uses pinned
vodozemac 0.10.0Olm sessions with the version 2 session configuration. CipherBoard does not implement Curve25519, Ed25519, AEAD, or the Double Ratchet primitives itself. - Ratchet state, replay state, and pending operations are transactionally
committed before ciphertext leaves the IME or plaintext is displayed. A
pending send moves from
READYto durableCOMMIT_UNCERTAINbefore the hostcommitText()call; an uncertain operation is never retried automatically. - Vault records are encrypted with a random data-encryption key wrapped by a non-exportable, hardware-backed Android Keystore key. StrongBox is attempted first; a verified TEE-backed key is the fallback. Software-only keys are not accepted.
- Android backup and device-transfer extraction are disabled for application data.
- Private mode keeps a bounded draft in the IME process, disables personalized
learning, suggestions, clipboard history, copy/cut/paste, saved view state,
and content capture, and protects the IME window with
FLAG_SECURE. Software key input is routed to the local draft; only persisted ciphertext can reach the hostInputConnection. - The protected viewer uses
FLAG_SECURE, disables plaintext selection and sharing, clears on backgrounding, and does not return plaintext throughACTION_PROCESS_TEXT. - Transport and QR parsers have explicit size/count limits and reject malformed, duplicate, non-canonical, inconsistent, or trailing data.
CipherBoard cannot fully protect messages when the unlocked device, operating
system, installed APK, or accessibility environment is compromised. It also
cannot prevent a camera or nearby person from seeing the screen, hide transport
metadata, resist physical coercion, or eliminate implementation and dependency
defects. FLAG_SECURE and best-effort memory clearing are useful controls, not
absolute guarantees.
The normal keyboard mode retains HeliBoard behavior and may use learning or clipboard features according to its ordinary settings. The stricter controls above apply to Private mode and the protected viewer. Private drafts must be entered with the on-screen keyboard: Android can deliver a hardware keyboard directly to the focused host application, bypassing IME draft routing.
Read the complete threat model, protocol specification, and current security review status before evaluating the application for sensitive use.
Use only a release published by this CipherBoard repository or build from a reviewed source commit. Do not install an APK linked from the upstream HeliBoard project and assume it is CipherBoard.
Verify the release checksum before installation:
sha256sum --check CipherBoard-0.2.0-release.apk.sha256On Windows PowerShell:
(Get-FileHash .\CipherBoard-0.2.0-release.apk -Algorithm SHA256).Hash.ToLowerInvariant()
Get-Content .\CipherBoard-0.2.0-release.apk.sha256If Android Build Tools are installed, also verify the APK signature and compare
the reported SHA-256 certificate digest with
SIGNING_CERTIFICATE_SHA256. Obtain the expected
digest through a channel you trust independently of the APK download.
apksigner verify --verbose --print-certs CipherBoard-0.2.0-release.apkInstall or update the verified APK:
adb install -r CipherBoard-0.2.0-release.apkDebug APKs are developer artifacts signed with a public debug key. Do not use them for real secrets.
To receive stable updates without giving CipherBoard network access, add
https://github.com/bglglzd/CipherBoard to Obtainium and leave pre-releases
disabled. CipherBoard does not contact GitHub or update itself; the external
installer is a separate trust boundary and is the only component that needs
network access. Android may require confirmation for the first install or an
update, depending on OS policy and which installer owns the existing install.
CipherBoard intentionally has neither android.permission.INTERNET nor
android.permission.REQUEST_INSTALL_PACKAGES, so an in-app updater is outside
its security model. Use the release-asset filter
^CipherBoard-[0-9]+\.[0-9]+\.[0-9]+-release\.apk$ so source archives and debug
artifacts are not selected.
Do not uninstall CipherBoard before updating. Install the new APK over the existing application so Android can verify signing-certificate continuity and the Vault, identity, contacts, and ratchet state remain in application data. If Android reports a signer mismatch, stop and investigate instead of uninstalling to bypass the warning. See the complete GrapheneOS installation and update guide.
On GrapheneOS, open Settings > System > Keyboard > On-screen keyboard > Manage on-screen keyboards and enable CipherBoard. Menu wording can differ slightly between Android releases.
In Settings > Apps > CipherBoard, keep Network denied as defense in depth, deny Sensors if your OS exposes that permission and it is not needed, and grant Camera only when you intentionally start QR scanning. CipherBoard does not need Contacts, SMS, or storage access.
- Open CipherBoard and choose a local owner name. The name is not the cryptographic identity and is not shared during pairing.
- Unlock the Vault with a strong device credential or strong biometric.
- On device A, add a contact, enter a local label, and show the offer QR.
- On device B, add a contact, scan the offer, enter a local label, and show the response QR.
- On device A, scan the response.
- Compare the full Safety Number on both devices in person. Mark the contact verified only when every group matches.
If either identity changes, stop using the old session and pair again. Never silently accept a changed key.
To send, focus the destination text field, open CipherBoard, and tap the shield.
The keyboard expands a Private mode panel above its keys without opening a
separate screen. Choose a verified contact, write with the on-screen keys, and
tap Encrypt. The plaintext remains visible in that panel after a successful
insertion so you can confirm what was sent; it is wiped when you clear or close
the panel or move to another host field. The host field receives only text
beginning with CB1:. Do not type a private draft with a hardware keyboard.
To receive, select all ciphertext parts in the transport app and choose Decrypt in CipherBoard from Android's text actions. Confirm decryption, unlock the Vault, and read the result in the protected viewer. Ciphertext may be copied as a fallback; plaintext is never copied automatically.
By default CipherBoard does not keep plaintext history or message keys for convenient re-reading. A previously viewed message may therefore be impossible to decrypt again after its temporary local display record is removed.
CipherBoard - офлайн-клавиатура для обмена зашифрованным текстом без аккаунтов,
телефонных номеров и сервера CipherBoard. Обычный режим основан на HeliBoard. В
приватном режиме над клавишами открывается собственная панель CipherBoard:
программные клавиши пишут в локальный черновик, а внешнему приложению передаётся
только шифротекст CB1:.
Для начала:
- Установите только проверенный release APK из этого репозитория и сверьте SHA-256 и fingerprint сертификата подписи.
- Для обновлений без выдачи CipherBoard сетевого доступа добавьте
https://github.com/bglglzd/CipherBoardв Obtainium и отключите получение pre-release. Установите фильтр release-файлов^CipherBoard-[0-9]+\.[0-9]+\.[0-9]+-release\.apk$. Не удаляйте приложение перед обновлением: установите новую версию поверх старой, чтобы сохранить Vault, identity, контакты и состояние ratchet. - Включите CipherBoard в системных настройках клавиатур. На GrapheneOS дополнительно запретите приложению Network.
- Создайте локальную identity и разблокируйте Vault.
- Выполните взаимное физическое QR-сопряжение двух устройств.
- Полностью сравните Safety Number на обоих экранах и только после этого подтвердите контакт.
- Для отправки нажмите кнопку со щитом, выберите проверенный контакт, введите
сообщение программными клавишами и нажмите Зашифровать. Открытый текст
останется в панели для проверки, а во внешнем поле появится только
CB1:-шифротекст. Черновик очищается при очистке/закрытии панели или смене внешнего поля. Не используйте для приватного черновика физическую клавиатуру: Android может направить её ввод прямо во внешнее приложение. - Для чтения выделите шифротекст и выберите Расшифровать в CipherBoard.
CipherBoard не проверяет и не устанавливает обновления самостоятельно: у него
нет разрешений android.permission.INTERNET и
android.permission.REQUEST_INSTALL_PACKAGES. Сеть использует только выбранный
вами внешний установщик, например Obtainium. Android может потребовать
подтверждение первой установки или обновления. Подробности приведены в инструкции для
GrapheneOS.
Приложение не считается независимо аудированным. Оно не защищает от полного компрометационного доступа к разблокированному устройству, вредоносной Accessibility-службы, подменённого APK, съёмки экрана камерой, анализа метаданных транспорта или физического принуждения. Перед использованием в ситуации высокого риска прочитайте модель угроз и текущий отчёт о проверках.
The full, pinned environment and release procedure are documented in
BUILD.md and RELEASE.md. The short debug path is:
./scripts/build-debug.shOn Windows PowerShell:
.\scripts\build-debug.ps1The scripts run source-policy checks, Android lint, module unit tests, build the APK, and verify its manifest policy. A production release additionally requires a clean worktree, external signing material, Rust checks, Android device tests, an offline vulnerability database, and exact APK verification. Never commit a keystore, signing password, private key, production identity, QR payload, or session state.
| Path | Responsibility |
|---|---|
app/ |
HeliBoard-based IME, embedded Private panel, onboarding, contacts, protected viewer, and Android integration |
crypto-core/ |
Minimal Kotlin/JNI boundary and Rust vodozemac protocol core |
secure-storage/ |
Keystore key management, encrypted records, replay state, and atomic operations |
pairing/ |
Offline pairing state machine and local QR integration |
scripts/ |
Reproducible build, signing, APK policy, SBOM, and security checks |
Architecture and review documents:
PROJECT_CONTEXT.md- scope and product invariantsARCHITECTURE.md- components and trust boundariesCRYPTO_PROTOCOL.md- wire and state protocolTHREAT_MODEL.md- threats, assumptions, and limitationsSECURITY_CHECKLIST.md- requirement traceabilityTEST_PLAN.md- test matrix and acceptance evidencedocs/GRAPHENEOS.md- GrapheneOS installation and external update guideUPSTREAM.md- exact HeliBoard provenanceLICENSES.mdandTHIRD_PARTY_NOTICES.md- licensing inventory
Read CONTRIBUTING.md before opening a pull request. Bug
reports must use synthetic content and must not include real plaintext,
ciphertext, contact names, full fingerprints, Safety Numbers, QR payloads,
private keys, or session state.
- General usage and build help:
SUPPORT.md - Security vulnerabilities:
SECURITY.md - Community expectations:
CODE_OF_CONDUCT.md
Security reports are accepted in English or Russian. Do not disclose an unpatched vulnerability in a public issue.
CipherBoard is distributed under the GNU General Public License version 3.0.
See LICENSE for the license text and LICENSES.md
for component-specific notices. Distributors of modified binaries must satisfy
the GPL corresponding-source and notice requirements.
CipherBoard is based on HeliBoard v4.0, pinned to commit
bd48798b99cccc99704eebf2a9259c02dbd684d5. The exact provenance and the
limitations of the unsigned upstream tag are documented in
UPSTREAM.md. Credits and notices for HeliBoard, OpenBoard, AOSP
Keyboard, LineageOS, and other upstream contributors are preserved in the
source and notice files.
