Transfer ASCII-armored GPG public and private keys through single- or multipart QR codes using Android-native camera/display adapters.
Scope
Use CameraX Preview and ImageAnalysis with the runtime camera permission for scanning; pass normalized frame bytes/planes and orientation to Rust-owned QR decoding and multipart-envelope parsing.
Render Rust-provided QR matrices in Compose Canvas for export; Kotlin must not construct payloads or re-encode key armor.
Preserve exact armored bytes. Parsing, fingerprinting, public/secret matching, passphrase validation, duplicate handling, import transaction, and default-key selection remain in crates/storage.
Present progress for duplicate/out-of-order/missing frames and allow safe pause/cancel across rotation, fold, permission interruption, and app background.
Require explicit security confirmation plus storage-derived fingerprint/identity before importing or displaying private material.
Apply FLAG_SECURE, brightness/keep-screen-on only while needed, and immediate masking on background/lock; never copy armor to clipboard, save it to photos, cache camera frames, or log payloads.
Handle permission denial/permanent denial, unavailable camera, invalid/incomplete/mismatched armor, duplicate key, interrupted import, and process death safely.
Prove compatibility with existing ASCII-armored GPG fixtures and QR envelope versions.
Acceptance criteria
Single and multipart fixtures reconstruct byte-for-byte and import transactionally.
Invalid/incomplete/mismatched data cannot replace valid keys/config.
Camera analysis stays responsive and bounded on low-memory devices and changing fold orientations.
Private export/import is never visible in recents/screenshots and leaves no ordinary Android persistence.
Kotlin contains no QR payload, GPG parser, fingerprint, matching, or import policy.
Depends on Rust/UniFFI packaging, lifecycle security, biometric authentication, and onboarding. Part of #87.
Android support update (2026-10-08)
User-directed scope: Android release and CI targets are arm64-v8a and armeabi-v7a. x86_64 Android is excluded for now. Validation for every Android milestone issue uses emulator devices only; physical-device testing and physical-device checklists are excluded. Record the limits of available ARM emulator/API images without claiming physical-device coverage.
## Goal
Transfer ASCII-armored GPG public and private keys through single- or multipart QR codes using Android-native camera/display adapters.
## Scope
- Use CameraX Preview and ImageAnalysis with the runtime camera permission for scanning; pass normalized frame bytes/planes and orientation to Rust-owned QR decoding and multipart-envelope parsing.
- Render Rust-provided QR matrices in Compose Canvas for export; Kotlin must not construct payloads or re-encode key armor.
- Preserve exact armored bytes. Parsing, fingerprinting, public/secret matching, passphrase validation, duplicate handling, import transaction, and default-key selection remain in `crates/storage`.
- Present progress for duplicate/out-of-order/missing frames and allow safe pause/cancel across rotation, fold, permission interruption, and app background.
- Require explicit security confirmation plus storage-derived fingerprint/identity before importing or displaying private material.
- Apply `FLAG_SECURE`, brightness/keep-screen-on only while needed, and immediate masking on background/lock; never copy armor to clipboard, save it to photos, cache camera frames, or log payloads.
- Handle permission denial/permanent denial, unavailable camera, invalid/incomplete/mismatched armor, duplicate key, interrupted import, and process death safely.
- Prove compatibility with existing ASCII-armored GPG fixtures and QR envelope versions.
## Acceptance criteria
- Single and multipart fixtures reconstruct byte-for-byte and import transactionally.
- Invalid/incomplete/mismatched data cannot replace valid keys/config.
- Camera analysis stays responsive and bounded on low-memory devices and changing fold orientations.
- Private export/import is never visible in recents/screenshots and leaves no ordinary Android persistence.
- Kotlin contains no QR payload, GPG parser, fingerprint, matching, or import policy.
Depends on Rust/UniFFI packaging, lifecycle security, biometric authentication, and onboarding. Part of #87.
## Android support update (2026-10-08)
User-directed scope: Android release and CI targets are **arm64-v8a** and **armeabi-v7a**. x86_64 Android is excluded for now. Validation for every Android milestone issue uses emulator devices only; physical-device testing and physical-device checklists are excluded. Record the limits of available ARM emulator/API images without claiming physical-device coverage.
hugo
added this to the 06 - Implement an Android version of the software milestone 2026-08-17 19:15:15 +00:00
Added lifecycle-bound CameraX Preview/ImageAnalysis with camera permission, pause/resume, denial/settings and unavailable-camera recovery. Bounded Y-plane bytes/strides/orientation go directly to Rust; Kotlin never decodes QR payloads or parses GPG material.
Reused the shared Rust camera/key-transfer contracts, added quarter-turn decoding, byte-exact multipart reassembly with zeroizing chunks, duplicate/out-of-order progress, and bounded export matrices. Imported ISKT1/ASCII armor retains the shared format.
Integrated the scanner into recovery and onboarding. Onboarding stages the reviewed key through its existing Rust transaction; it retains the separate local/HTTPS store setup choice and refreshes prepared-key selection correctly.
Added explicit fingerprint confirmation for private import/export, export identity labels, frame navigation/animation, scoped brightness/keep-screen-on, and a Rust-owned visibility deadline. Background/lock/dismissal clears matrices, inputs and transfer handles. Input camera bytes are cleared before publishing completion; no frame/armor persistence or clipboard path was added.
Reviewed and pinned CameraX/transitive checksums, locks and licenses. Audited its two native libraries and removed the unused transitive network-state permission.
Verification:
All required Rust 1.97.1 workspace gates passed: fmt, warning-denied check, Clippy, and cargo test --workspace. Fixture tests cover real encrypted import/export, wrong passphrases, rollback, exact/multipart camera reconstruction, orientations/strides, stale/cancel cleanup, export bounds and non-renewing expiry.
androidVerification and release lint passed, including both ARM ABI builds, debug/release/AAB, JVM tests, ktlint, architecture checks, ELF/APK 16 KB audits. Exact license/SBOM, packaged manifest/backup exclusions and matching FULL release-symbol audits passed.
API 26 arm64: native settings/viewer test with successful private export and relock erasure; 14 bridge tests; app runner OK (32 reported, including four opt-in/biometric methods not enabled); final onboarding/settings group 4 passed; actual CameraX close/reopen passed.
API 37 arm64, 16 KB with compatibility disabled: final native private-export/erasure test, 14 bridge tests and actual CameraX close/reopen passed. armeabi-v7a has build/package evidence; runtime checks used arm64 emulators.
Computer use on the persistent API 37 emulator verified update-state retention, permission interruption, actual live preview, scrolling/clipping, and disabled private export before explicit confirmation. A preview overlap found in this pass was fixed and rechecked.
The retained-profile private-export prompt remains an optional user check; isolated encrypted fixtures provide the successful-private-operation evidence. Seven broader Keystore tests requiring separate enrolled-biometric setup failed their prerequisites and are not counted as camera coverage. Physical devices remain excluded by the milestone support policy.
Implementation/security details and per-environment evidence: Android key transfer. Completion review found and fixed the onboarding refresh and byte-erasure ordering defects; no remaining #106 implementation gap was found.
Implemented in [d466b17](https://git.rfc1437.de/hugo/IronStorage/commit/d466b170ab407ea68452975dbb46486dc7b1d1ba).
- Added lifecycle-bound CameraX Preview/ImageAnalysis with camera permission, pause/resume, denial/settings and unavailable-camera recovery. Bounded Y-plane bytes/strides/orientation go directly to Rust; Kotlin never decodes QR payloads or parses GPG material.
- Reused the shared Rust camera/key-transfer contracts, added quarter-turn decoding, byte-exact multipart reassembly with zeroizing chunks, duplicate/out-of-order progress, and bounded export matrices. Imported ISKT1/ASCII armor retains the shared format.
- Integrated the scanner into recovery and onboarding. Onboarding stages the reviewed key through its existing Rust transaction; it retains the separate local/HTTPS store setup choice and refreshes prepared-key selection correctly.
- Added explicit fingerprint confirmation for private import/export, export identity labels, frame navigation/animation, scoped brightness/keep-screen-on, and a Rust-owned visibility deadline. Background/lock/dismissal clears matrices, inputs and transfer handles. Input camera bytes are cleared before publishing completion; no frame/armor persistence or clipboard path was added.
- Reviewed and pinned CameraX/transitive checksums, locks and licenses. Audited its two native libraries and removed the unused transitive network-state permission.
Verification:
- All required Rust 1.97.1 workspace gates passed: fmt, warning-denied check, Clippy, and cargo test --workspace. Fixture tests cover real encrypted import/export, wrong passphrases, rollback, exact/multipart camera reconstruction, orientations/strides, stale/cancel cleanup, export bounds and non-renewing expiry.
- androidVerification and release lint passed, including both ARM ABI builds, debug/release/AAB, JVM tests, ktlint, architecture checks, ELF/APK 16 KB audits. Exact license/SBOM, packaged manifest/backup exclusions and matching FULL release-symbol audits passed.
- API 26 arm64: native settings/viewer test with successful private export and relock erasure; 14 bridge tests; app runner OK (32 reported, including four opt-in/biometric methods not enabled); final onboarding/settings group 4 passed; actual CameraX close/reopen passed.
- API 37 arm64, 16 KB with compatibility disabled: final native private-export/erasure test, 14 bridge tests and actual CameraX close/reopen passed. armeabi-v7a has build/package evidence; runtime checks used arm64 emulators.
- Computer use on the persistent API 37 emulator verified update-state retention, permission interruption, actual live preview, scrolling/clipping, and disabled private export before explicit confirmation. A preview overlap found in this pass was fixed and rechecked.
The retained-profile private-export prompt remains an optional user check; isolated encrypted fixtures provide the successful-private-operation evidence. Seven broader Keystore tests requiring separate enrolled-biometric setup failed their prerequisites and are not counted as camera coverage. Physical devices remain excluded by the milestone support policy.
Implementation/security details and per-environment evidence: [Android key transfer](https://git.rfc1437.de/hugo/IronStorage/src/branch/main/docs/android/key-transfer.md). Completion review found and fixed the onboarding refresh and byte-erasure ordering defects; no remaining #106 implementation gap was found.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Goal
Transfer ASCII-armored GPG public and private keys through single- or multipart QR codes using Android-native camera/display adapters.
Scope
crates/storage.FLAG_SECURE, brightness/keep-screen-on only while needed, and immediate masking on background/lock; never copy armor to clipboard, save it to photos, cache camera frames, or log payloads.Acceptance criteria
Depends on Rust/UniFFI packaging, lifecycle security, biometric authentication, and onboarding. Part of #87.
Android support update (2026-10-08)
User-directed scope: Android release and CI targets are arm64-v8a and armeabi-v7a. x86_64 Android is excluded for now. Validation for every Android milestone issue uses emulator devices only; physical-device testing and physical-device checklists are excluded. Record the limits of available ARM emulator/API images without claiming physical-device coverage.
Implemented in d466b17.
Verification:
The retained-profile private-export prompt remains an optional user check; isolated encrypted fixtures provide the successful-private-operation evidence. Seven broader Keystore tests requiring separate enrolled-biometric setup failed their prerequisites and are not counted as camera coverage. Physical devices remain excluded by the milestone support policy.
Implementation/security details and per-environment evidence: Android key transfer. Completion review found and fixed the onboarding refresh and byte-erasure ordering defects; no remaining #106 implementation gap was found.