Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ The Gradle product identity is centralized in `gradle.properties`:
```text
cipherboard.applicationId=org.cipherboard.securekeyboard
cipherboard.productName=CipherBoard
cipherboard.versionCode=40001
cipherboard.versionName=0.4.1
cipherboard.versionCode=40002
cipherboard.versionName=0.4.2
cipherboard.artifactName=CipherBoard
```

Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ All notable CipherBoard changes are documented in this file. The project uses
[Semantic Versioning](https://semver.org/spec/v2.0.0.html) from version 0.1.0.
Pre-1.0 releases may contain compatibility changes that require re-pairing.

## [0.4.2] - 2026-07-14

### Fixed

- The clipboard-fallback instrumentation now waits for the protected Activity
to receive window focus before exercising Android's foreground-only clipboard
read. This removes a release-gate race without weakening the product's
clipboard policy or changing runtime behavior.
- The upstream timestamp unit test now checks the generated second-resolution
value against the full key-press interval instead of a boundary-sensitive
point-in-time tolerance.
- The two Private-panel lifecycle fixes from 0.4.1 are included unchanged.

## [0.4.1] - 2026-07-14

### Fixed
Expand Down Expand Up @@ -229,6 +242,7 @@ Pre-1.0 releases may contain compatibility changes that require re-pairing.
Android security audit. Physical GrapheneOS, StrongBox, TEE-only, live-camera
pairing, and hostile-device validation remain necessary before high-risk use.

[0.4.2]: https://github.com/bglglzd/CipherBoard/releases/tag/v0.4.2
[0.4.1]: https://github.com/bglglzd/CipherBoard/releases/tag/v0.4.1
[0.4.0]: https://github.com/bglglzd/CipherBoard/releases/tag/v0.4.0
[0.3.0]: https://github.com/bglglzd/CipherBoard/releases/tag/v0.3.0
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ HeliBoard release and is not endorsed or supported by the HeliBoard project.

| Project fact | Current value |
| --- | --- |
| Maturity | Pre-1.0; current version `0.4.1` |
| Maturity | Pre-1.0; current version `0.4.2` |
| 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.4.1 release notes](docs/releases/v0.4.1.md).
See the bilingual [CipherBoard 0.4.2 release notes](docs/releases/v0.4.2.md).

## What It Does

Expand Down Expand Up @@ -156,14 +156,14 @@ project and assume it is CipherBoard.
Verify the release checksum before installation:

```sh
sha256sum --check CipherBoard-0.4.1-release.apk.sha256
sha256sum --check CipherBoard-0.4.2-release.apk.sha256
```

On Windows PowerShell:

```powershell
(Get-FileHash .\CipherBoard-0.4.1-release.apk -Algorithm SHA256).Hash.ToLowerInvariant()
Get-Content .\CipherBoard-0.4.1-release.apk.sha256
(Get-FileHash .\CipherBoard-0.4.2-release.apk -Algorithm SHA256).Hash.ToLowerInvariant()
Get-Content .\CipherBoard-0.4.2-release.apk.sha256
```

If Android Build Tools are installed, also verify the APK signature and compare
Expand All @@ -172,13 +172,13 @@ the reported SHA-256 certificate digest with
digest through a channel you trust independently of the APK download.

```sh
apksigner verify --verbose --print-certs CipherBoard-0.4.1-release.apk
apksigner verify --verbose --print-certs CipherBoard-0.4.2-release.apk
```

Install or update the verified APK:

```sh
adb install -r CipherBoard-0.4.1-release.apk
adb install -r CipherBoard-0.4.2-release.apk
```

Debug APKs are developer artifacts signed with a public debug key. Do not use
Expand Down
6 changes: 6 additions & 0 deletions SECURITY_REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ physical-device or GrapheneOS evidence.

## Evidence Observed

- The 0.4.2 clipboard-fallback instrumentation waits for the protected
Activity's window focus before setting and explicitly reading ciphertext.
This matches Android's foreground clipboard boundary and removes a false
negative where `RESUMED` preceded focus; plaintext is still never written to
the clipboard.

- The 0.4.1 IME lifecycle fix accepts Android's temporarily missing
`InputBinding.connectionToken` only when the exact live `InputConnection`
object, host UID/package and editor metadata still match. Unit tests reject a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,25 @@ public void clipboardFallbackReadsOnlyAfterClickAndDoesNotReplaceClipboard() {
false
);
AtomicReference<ClipData> originalClip = new AtomicReference<>();
AtomicReference<CiphertextClipboardActivity> clipboardActivity = new AtomicReference<>();
AtomicReference<SecureMessageViewerActivity> viewer = new AtomicReference<>();
try (ActivityScenario<CiphertextClipboardActivity> scenario = ActivityScenario.launch(
new Intent(targetContext, CiphertextClipboardActivity.class)
)) {
scenario.onActivity(activity -> {
clipboardActivity.set(activity);
assertSecureWindow(activity);
});
waitUntil(
"clipboard fallback did not receive window focus",
() -> clipboardActivity.get() != null && clipboardActivity.get().hasWindowFocus()
);
scenario.onActivity(activity -> {
ClipboardManager clipboard =
(ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
originalClip.set(clipboard.getPrimaryClip());
ClipData ciphertextClip = ClipData.newPlainText("", CLIPBOARD_CIPHERTEXT_SENTINEL);
clipboard.setPrimaryClip(ciphertextClip);
assertSecureWindow(activity);
List<Button> buttons = findDescendants(activity, Button.class);
Button action = null;
for (Button candidate : buttons) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,9 +826,11 @@ class InputLogicTest {

@Test fun timestamp() {
chainInput("hello")
val beforeKeyPress = System.currentTimeMillis()
functionalKeyPress(KeyCode.TIMESTAMP)
assertEquals(Calendar.getInstance().time.time.toDouble(),
getTimestampFormatter(latinIME).parse(text.substring(5))!!.time.toDouble(), 1000.0)
val afterKeyPress = System.currentTimeMillis()
val parsedTimestamp = getTimestampFormatter(latinIME).parse(text.substring(5))!!.time
assertTrue(parsedTimestamp in (beforeKeyPress - 999)..afterKeyPress)
}

@Test fun inlineEmojiSearchStart() {
Expand Down
79 changes: 79 additions & 0 deletions docs/releases/v0.4.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# CipherBoard 0.4.2

## English

CipherBoard 0.4.2 contains the two IME lifecycle fixes prepared in 0.4.1 and
deterministic Android release tests. It does not change identities, pairing, Olm
sessions, message envelopes, or Russian/English word presentations.

### Private panel fixes

- The language key changes only the enabled CipherBoard layout while Private
mode is open. Russian/English switching works while the Vault is locked or
the draft is temporarily unavailable.
- Private mode opens after switching to another Android keyboard and returning
to CipherBoard, including when Android restores a live editor before its
Binder connection token.
- Ordinary text, numeric, multiline and `TYPE_NULL` editors share the same
activation path. Password fields retain the explicit warning.

### Editor-scope safety

The compatibility fallback does not trust editor metadata or a client Binder
token by itself. Private mode and the one-shot ciphertext handoff both require
the exact current `InputConnection` object, host UID/package and field metadata.
Changing focus or replacing the connection fails closed before `commitText()`.
The only exception is one metadata-matching rebind after an explicit successful
Vault unlock; the locked draft is wiped before that transition.

The release instrumentation now waits for the protected clipboard Activity to
receive window focus before testing Android's foreground-only clipboard read.
This fixes a test race only; runtime clipboard behavior is unchanged.

Install `CipherBoard-0.4.2-release.apk` over the existing app. Do not uninstall
or clear app data: doing so destroys the local identity, contacts and ratchet
state and requires pairing again.

## Русский

CipherBoard 0.4.2 содержит два исправления жизненного цикла клавиатуры,
подготовленные в 0.4.1, и детерминированные Android release-тесты.
Криптографические личности, сопряжение, сессии Olm, формат сообщений и
представление русскими или английскими словами не менялись.

### Исправления приватного редактора

- Клавиша языка переключает только активную раскладку CipherBoard в приватном
режиме. Русская и английская раскладки переключаются и при заблокированном
Vault, и во временном состоянии ожидания редактора.
- Приватный режим снова открывается после переключения на другую Android-
клавиатуру и возврата в CipherBoard, даже если Android уже вернул рабочее
поле, но временно не передал Binder-token соединения.
- Поддерживается единый путь для обычных, числовых, многострочных полей и
`TYPE_NULL`. Для полей пароля сохраняется явное предупреждение.

### Привязка к полю

Режим совместимости не доверяет только метаданным поля или Binder-token.
Приватный редактор и одноразовая вставка шифротекста требуют тот же самый живой
объект `InputConnection`, UID/package приложения и метаданные поля. Смена
фокуса или соединения блокирует вставку до вызова `commitText()`.
Единственное исключение - одно повторное связывание с совпадающими метаданными
после явной успешной разблокировки Vault; заблокированный черновик очищается до
перехода.

Release-тест теперь ожидает focus защищённого clipboard-окна до проверки
ограниченного Android чтения буфера обмена. Это исправляет только гонку теста;
runtime-поведение буфера обмена не менялось.

Установите `CipherBoard-0.4.2-release.apk` поверх существующего приложения. Не
удаляйте приложение и не очищайте его данные: это уничтожит локальную identity,
контакты и ratchet-state, после чего потребуется повторное сопряжение.

CipherBoard uses reviewed cryptographic primitives and automated tests, but the
complete product has not received an independent applied-cryptography and
Android security audit.

CipherBoard использует проверенные криптографические примитивы и автоматические
тесты, но продукт целиком не проходил независимый аудит прикладной криптографии
и Android security.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx2048m
# CipherBoard product identity. Keep branding and artifact metadata centralized.
cipherboard.applicationId=org.cipherboard.securekeyboard
cipherboard.productName=CipherBoard
cipherboard.versionCode=40001
cipherboard.versionName=0.4.1
cipherboard.versionCode=40002
cipherboard.versionName=0.4.2
cipherboard.artifactName=CipherBoard
cipherboard.buildToolsVersion=36.1.0