Skip to content

chore(deps): bump eu.anifantakis:ksafe from 2.2.1 to 3.1.0 - #230

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/gradle/eu.anifantakis-ksafe-3.1.0
Open

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/gradle/eu.anifantakis-ksafe-3.1.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bumps eu.anifantakis:ksafe from 2.2.1 to 3.1.0.

Release notes

Sourced from eu.anifantakis:ksafe's releases.

3.1.0

KSafe no longer depends on a third-party cryptography library — on any platform. Drop-in upgrade: existing data is untouched, nothing migrates.

implementation("eu.anifantakis:ksafe:3.1.0")
implementation("eu.anifantakis:ksafe-compose:3.1.0")     // optional
implementation("eu.anifantakis:ksafe-biometrics:3.1.0")  // optional

New

  • Own Apple CryptoKit bridgedev.whyoleg.cryptography is gone. Apple still does the crypto; the wrapper (and its transitive IrLinkageError risk) disappeared. iosArm64 footprint: 13 artifacts / 3.7 MB → 1 / 16 KB. Old ciphertext verified byte-compatible on a physical iPhone, 286 device tests green.
  • Mode-typed viewsKSafePlain, KSafeEncrypted, KSafeHardwareIsolated: the write mode becomes a type, not an argument. Own section below. 👇
  • Interrupted key rotation resumes automatically on the next KSafe instance — same generation, even under Policy.Never. Entries skipped by a completed rotation (e.g. device locked) are retried on later instances with a bounded budget: KSafeConfig(keyRotationRetryAttempts = 3). 📖 https://github.com/ioannisa/ksafe/blob/HEAD/docs/KEY_ROTATION.md
  • Typed AES key strengthKSafeConfig(aesKeySize = KSafeAesKeySize.BITS_128) (default BITS_256); WebCrypto now honours it too. New key material only; existing keys keep their size until rotateKeys().

Mode-typed views: KSafePlain / KSafeEncrypted / KSafeHardwareIsolated

When one store holds both preferences and secrets, the per-call mode = argument is a convention — and one forgotten argument silently writes with the wrong protection. The three view types turn that convention into a compiler rule: each wraps an existing KSafe instance and freezes the write mode at construction. No member of these types takes a mode parameter, so a call site can't store a secret in plaintext — or encrypt a trivial preference — by picking the wrong argument.

val prefs = KSafePlain(ksafe)            // or: ksafe.plain
val vault = KSafeHardwareIsolated(ksafe) // or: ksafe.hardwareIsolated
prefs.putDirect("theme", "dark")         // always Plain — nothing to forget
vault.put("master_key", secret)          // always requests StrongBox / Secure Enclave
var theme by prefs("dark")               // delegate: key = property name, writes Plain
val pin by vault.asWritableFlow("", key = "pin")   // .set() writes hardware-isolated

The full write surface is covered — put/putDirect, the by view(...) delegate, asFlow/asWritableFlow/asStateFlow/asMutableStateFlow/getStateFlow, and via :ksafe-compose both mutableStateOf and rememberKSafeState — so the guarantee has no gap where writes actually happen.

In Koin, the types replace stringly named(...) qualifiers. One store, distinct injectable views:

single { KSafe(context = androidApplication(), fileName = "app") }
single { KSafePlain(get()) }
single { KSafeHardwareIsolated(get()) }
class SettingsRepository(private val prefs: KSafePlain)          // writes always Plain
class AuthRepository(private val vault: KSafeHardwareIsolated)   // writes always request SE/StrongBox

All views over one instance share the same file, key namespace and cache — mixed-mode entries keep working, and a value written through one view is immediately visible through any other. KSafeEncrypted/KSafeHardwareIsolated also freeze the unlock policy: KSafeEncrypted(ksafe, requireUnlockedDevice = true) makes every write through that view strict, while the default constructor inherits the instance's configured policy.

Three honest boundaries:

  • Write-side only — reads stay mode-free and auto-detect each entry's protection.
  • KSafeHardwareIsolated requests, it doesn't guarantee — without StrongBox / Secure Enclave the write degrades to the documented next-best custody and reports it via protectionInfo.

... (truncated)

Changelog

Sourced from eu.anifantakis:ksafe's changelog.

[3.1.0] - 2026-08-24

Added

  • KSafe now owns its Apple CryptoKit integration. A small bundled Swift/C bridge calls CryptoKit.AES.GCM directly on iOS and macOS, while Kotlin owns validation and the frozen 12-byte nonce || ciphertext || 16-byte tag envelope. NIST AES-128/AES-256 vectors, an independent AAD vector, and tamper tests pin the bridge's output and compatibility.

  • AES key strength is typed and works on every platform. Configure KSafeConfig(aesKeySize = KSafeAesKeySize.BITS_128) or keep the default BITS_256. WebCrypto now honors the same choice when minting a new non-extractable key; existing keys on every platform retain their inherent size until rotateKeys() creates a new generation.

  • Interrupted key rotations resume automatically at the same generation on the next KSafe instance. A 3.1.0 rotation writes "r":1 atomically with its generation bump, before it touches any entry, and changes that lifecycle state to "r":0 only after the entry pass and superseded-master sweep finish. A process death therefore leaves a readable mixed-generation store that the next instance repairs idempotently at the same generation, even under KSafeKeyRotationPolicy.Never; this is one lifecycle bit, not a per-entry journal.

    3.0.0 compatibility is deliberately conservative. The released 3.0.0 generation record has no r field, so absence cannot distinguish a completed rotation from one interrupted by a crash. On its first 3.1.0 startup, KSafe treats every such record as a completed 3.0.0 rotation, adds "r":0, preserves its generation/timestamp, and performs no resume, generation bump, entry rewrite, key sweep, or same-launch MaxAge rotation. Normal policy resumes on the following launch. Thus upgrading can never make 3.1.0 guess wrong and disturb an already shipped 3.0.0 store; if 3.0.0 really did leave entries behind, they remain readable under their recorded old key and a later explicit rotateKeys() (or due MaxAge pass) moves them normally. Unknown future lifecycle values are preserved and rejected fail-closed.

  • A normally completed rotation no longer loses retryable work. If a pass returns with skipped entries — most importantly a strict requireUnlockedDevice entry while the device is locked — KSafe records "r":0 plus "rp":N, a bounded next-instance retry budget. KSafeConfig.keyRotationRetryAttempts controls the initial count (3 by default; 0 disables this retry path). The current instance starts no timer and performs no same-run retry. Each new KSafe instance consumes at most one attempt and retries the same generation, without minting another key or resetting the generation-birth "ts" clock; this lifecycle completion also runs under Never. The claim durably changes r:0,rp:N to r:1,rp:N-1 before work, so a crash cannot refill the budget; r:1,rp:0 can recover only the final already-claimed attempt. If MaxAge is already due, its fresh-generation rotation takes precedence. failed alone never arms retry because it denotes a definitive, not retryable, problem.

  • Mode-typed views: KSafePlain, KSafeEncrypted, KSafeHardwareIsolated. Thin wrappers over an existing KSafe instance that freeze the write mode at construction — no member of these types takes a mode parameter, so a call site can never accidentally encrypt a preference or store a secret in plaintext by picking the wrong argument. They cover the full write surface (put/putDirect, the by view(...) delegate, asFlow/asWritableFlow/ asStateFlow/asMutableStateFlow/getStateFlow, and — via :ksafe-composemutableStateOf and rememberKSafeState), and forward the nullable key untouched so key-from-property-name derivation behaves exactly as on KSafe. All views over one instance share the same file, key namespace and cache, so a single store keeps serving mixed-mode ezntries; in Koin the types

... (truncated)

Commits
  • 8daad53 release: 3.1.0
  • 9d20165 ci: pin setup-gradle to v5, not v6
  • 7afa2f1 ci: bump actions to their node24-native majors
  • 63d613f release: 3.0.0
  • a1d6d26 Update README.md
  • d22d93b docs(release): fold 2.2.0 into a single 2.2.1 changelog entry, bump doc versions
  • c461a7e fix(jvm): sweep FileKeyVault crash-leftover temp files holding the plaintext ...
  • da93de7 fix(core): harden the snapshot collector, teardown, and null-sentinel handling
  • 54a71fa docs(comments): strip non-essential commentary from the 2.2.x biometrics/simu...
  • See full diff in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [eu.anifantakis:ksafe](https://github.com/ioannisa/ksafe) from 2.2.1 to 3.1.0.
- [Release notes](https://github.com/ioannisa/ksafe/releases)
- [Changelog](https://github.com/ioannisa/KSafe/blob/main/CHANGELOG.md)
- [Commits](ioannisa/KSafe@2.2.1...3.1.0)

---
updated-dependencies:
- dependency-name: eu.anifantakis:ksafe
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file java Pull requests that update java code labels Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file java Pull requests that update java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants