Repository navigation
refactor: rust - #117
Merged
Merged
refactor: rust#117
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
passkey 0.6 makes the authenticator's crypto backend pluggable; pass the crate's default RustCryptoBackend. argon2 0.6 needs no code changes; the password-domain KAT and both golden backups still pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
register_passkey filled user_name from rp.name, so every new passkey was
stored under the site's display name ("Example Corp") instead of the
account it belongs to ("alice@example.com").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only backups and the password KEK had known-answer tests. The wrapped ARK, vault and item keys, item ciphertext, and stored passkey bytes are all persisted too, and any drift in cipher, nonce layout, or AAD encoding would make them unreadable without a compile error. Freeze one of each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every key uses AES-256-GCM-SIV, so name the cipher once and drop the per-key algorithm generic. That collapses the old surface: - AeadWrappedKey<T, W>, AeadCiphertext<K> and the WrappedKey trait become Sealed<T>, where T is the wrapped key type or [u8] for data. Sealed::from_parts returns an error on a bad nonce instead of panicking, which a corrupt row from Kotlin could previously trigger across the FFI. - KeyMaterial/AeadKey/KeyWrapper/AeadEncryptor become SymmetricKey, Wraps<K> and Encrypts. The whole hierarchy now reads in keys.rs. - define_aead_key!/define_wrap! become one crate-private symmetric_key!. - TryDeriveFrom becomes RootKEK::from_password, owning PASSWORD_DOMAIN. - ItemDataAad becomes Encrypts::Aad = [u8]; BCS encodes both identically. - Unused ScopedSigningKey and its macro are removed. Errors carry their cause: BCS/KDF strings become AadEncoding, EmptyPassword, SaltTooShort, Argon2MemoryTooHigh, Argon2 and InvalidNonceLength. Derived KDF output is zeroized. ArkSession takes wrapped keys by reference and bundles salt + wrapped ARK as PasswordWrappedArk. Argon2 still runs outside the session lock. All goldens and the password KAT pass with their vectors unchanged. The Kotlin-facing FFI is unchanged: regenerated bindings differ only in the UniFFI checksums of methods taking ItemKey, whose declaration moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
passkey: RegistrationError and ProviderError overlapped variant for variant; merge them into one PasskeyError, mapped once at the FFI. register and authenticate share request parsing, origin and response encoding. The remaining unwrap()s become NoCredentialCreated and ResponseEncoding errors instead of panics in an async FFI call. The codec's wire types go private behind encode/decode, so their serde shape is no longer public API. totp: algorithm, digits and period travel as one TotpParams instead of three positional arguments, and secrets are borrowed. get_totp, get_totp_url and get_totp_info_from_uri become generate, to_uri and parse_uri. csv: ColumnMapping uses u32 like CsvColumn.index, so the FFI re-exports the core type instead of keeping a usize-to-u32 copy of it. The Kotlin-facing API is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-dalek - [profile.release] lto + codegen-units = 1 shrinks the arm64 .so from 3.96 MB to 2.78 MB. Symbols are kept (strip = debuginfo) because uniffi-bindgen reads its metadata from the library; bindings generated from the LTO build match exactly. panic stays unwind so UniFFI can turn a panic into a Kotlin exception. - keygo-core has no unsafe code; forbid it so it stays that way. - ed25519-dalek was only used by the removed ScopedSigningKey. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
keygo-uniffi and keygo-core (dev) both depend on it; the workspace now owns the version and each crate keeps its own features. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the standard templates for files the operating system drops into working folders: Finder's .DS_Store and friends, Windows thumbnail and shortcut files, Linux editor backups and trash folders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGP strips native libraries when it packages the APK, after extracting their symbol tables for Play Console (debugSymbolLevel = SYMBOL_TABLE). Other consumers, such as a future PyO3 wheel built by maturin, strip on their own terms too. The Cargo strip setting had no measurable effect here anyway: the arm64 library is byte-for-byte the same size with or without it. The size win from the release profile is LTO + codegen-units = 1: the stripped arm64 library that ships goes from 2.67 MB to 2.25 MB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Unlock reports a failed password unwrap as WrongPassword, the same as verify_password; it used to surface as KeyWrap(UnwrapFailed). Kotlin already mapped both to "incorrect password", so the app behaves the same. FakeSession follows. - Salts come from aead's Generate like keys and nonces, through one kdf::new_salt and SALT_LEN. crypto/random.rs and the direct rand dependency are gone. - The CSV TOTP check decodes with totp-rs's Secret::try_from_base32, which calls the same base32 decoder, so the base32 dependency is gone. - passkey-authenticator no longer enables "testable", which only pulled mockall into the shipped library. - encryption::open takes the ciphertext by value, saving a full copy of every imported JSON backup. - Registration and CreationInfo cross the FFI as remote records instead of field-for-field copies. Kotlin: RegistrationResponse -> Registration, PasskeyInformation -> CreationInfo. - Drop the never-constructed InvalidKey variants from KeyWrapError and ItemCryptoError. - SymmetricKey::as_bytes is a default method; one local macro supplies generate() for the ARK, vault and item keys. - with_core's comment now says the ARK is copied for the call, which is what with_ark does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop comments that restate names or narrate tests, and shorten the rest to a line or two. Format freezes, locking contracts, and other non-obvious invariants stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Item data is encrypted under ItemDataAad { item_id, kind: SecretKind }
instead of bytes built by hand in Kotlin. Rust now owns the pinned
labels, and the custom Serialize keeps the 2.1.0 layout (item_id ||
label) byte for byte. A new golden vector, sealed by the old raw-bytes
path, proves it and replaces the synthetic b"item-aad" one.
- Kotlin: SecretBlueprint.label: String -> kind: SecretKind, a domain enum
in core:item. core:security maps it to the UniFFI enum with an
exhaustive when; the health report uses PasswordHealthReport.
- UserId, VaultId and ItemId are newtypes, so swapping them in a wrap or
an ItemAad no longer compiles. BCS encodes them as before, and Kotlin
still sees java.util.UUID.
- Wraps/Encrypts require an Aad, declared through aad! or an explicit
impl, so [u8] and bare Uuids are no longer accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
passkey-rs 0.6.0's Option<Passkey> store ignores the request's rp_id (upstream TODO), so a passkey registered for example.com signed an assertion for evil.com. authenticate() now compares the request's rp_id with the one sealed inside the stored passkey and fails with RpMismatch, which reaches Kotlin as the existing InvalidDomain. The new test pins the behaviour; once upstream filters by rp_id and the test passes without our check, the check can go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
accountScope handed a vault key to CryptographicScopeImpl as an item key. That compiled only because UniFFI lowers both to ByteArray, so the password-health report bypassed the key types the Rust refactor added. - Rust: NamespaceKey, wrapped by the ARK under NamespaceKeyAad and encrypting under NamespaceDataAad. Both AADs carry a domain tag (v1:ns/key, v1:ns/data), so a namespace key's wrap can never encode like a vault key's. ArkSession seals and opens records itself, so the key never crosses UniFFI. A new DecryptionFailed error separates a corrupted record from a key that will not unwrap. - Kotlin: AccountRecordSealer (seal/open returning Result) replaces accountScope. HealthReportStoreRepositoryImpl no longer catches ItemCryptoException, and CryptographicScopeProvider loses accountScope and its VaultManager dependency. - Every seal uses a fresh key, so a stored key that no longer unwraps cannot block later writes. Breaking: reports stored by 2.1.0 used the old layout and no longer open. The store is a cache, so a failed load triggers a rescan and the next store overwrites the old report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A backup's Argon2 parameters come from its header, and only the memory cost was bounded, so a crafted file with iters = u32::MAX hung the import. Argon2Params::build() now rejects more than MAX_ARGON2_ITERS (16) with Argon2ItersTooHigh, beside the existing memory check. Every backup so far was written with the default of 3 iterations, so none is rejected; a test keeps the defaults inside both caps. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.