Add PasswordTransformer trait with platform implementations#1189
Add PasswordTransformer trait with platform implementations#1189
Conversation
867fb66 to
0aa9929
Compare
0dc3eff to
58196fc
Compare
Introduces `AccountRepository` for encrypted credential storage and `AesGcmPasswordTransformer`, a pure-Rust AES-256-GCM password encryption implementation exposed via UniFFI. The `PasswordTransformer` trait uses `#[uniffi::export(with_foreign)]` so platforms can provide their own implementations (e.g. hardware- backed encryption) while the Rust one serves as a cross-platform fallback — particularly for Linux where platform keystores are unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exports persistence types (AccountRepository, PasswordTransformer, etc.) to the public Swift API. Conditionally re-exports AesGcmPasswordTransformer on Linux via #if os(Linux) so third-party clients can use it through `import WordPressAPI` without reaching into WordPressAPIInternal. Adds AesGcmPasswordTransformerTests exercising the Rust-backed UniFFI transformer — guarded with #if os(Linux) since the type is only available there (the Apple xcframework is built with --no-default-features which excludes aes-gcm-encryption). On Apple platforms, SecureEnclavePasswordTransformer fills this role instead. Fixes the testRoot() test on Linux by gating it with there, and adds request timeouts to prevent hangs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tion Hardware-backed PasswordTransformer for Apple platforms using ECIES (P-256 ECDH + HKDF-SHA256 + AES-256-GCM). Falls back to software keys on simulators. Guarded with #if canImport(CryptoKit) so it compiles out cleanly on Linux. All Secure Enclave tests run under a single @suite(.serialized) to prevent cooperative thread pool deadlocks — SE key creation blocks the calling thread, and Swift Testing's fixed-size cooperative pool deadlocks when all threads block simultaneously. See: https://forums.swift.org/t/cooperative-pool-deadlock-when-calling-into-an-opaque-subsystem/70685 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hardware-backed PasswordTransformer for Android using the Android Keystore with AES-256-GCM. Prefers StrongBox (API 28+) and falls back to TEE. Exposes isHardwareBacked property for callers to check the security level. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
58196fc to
22fbd5d
Compare
|
Just for my understanding, we are going to use The
IMO, the second kind of private key is not secure, because it's stored on disk without any protection. According to the comment on Also, I'm not sure if the SecureEnclave encryption is necessary. I think we can delegate the encryption to the keychain? Here is a pseudo-code: class KeychainPasswordTransformer {
func encrypt(password: String) {
let id = UUID()
keychain.store(username: id, password: password, service: "wordpress-rs-accounts")
return id
}
func decrypt(encrypted: String) -> String {
keychain.get(username: encrypted, service: "wordpress-rs-accounts)
}
}
I wonder if we can have a Can we ask the platform to store the information for us securely, without thinking about encryption & decryption? // pseudo-code: Just a simple key-value store.
trait SecureKeyValueStore {
fn store(id: String /* AccountId */, data: Vec<u8>)
fn get(id: String) -> Vec<u8>
}The platform can decide how to store the data securely, so we likely don't need any encryption or decryption code. |
Description
Add encrypted credential storage for persisting site authentication across app launches.
This PR introduces a
PasswordTransformertrait and platform-specific implementations that encrypt credentials at rest, enablingAccountRepository(also introduced here) to persist sites and tokens securely.This is the foundation for credential storage in:
Changes
PasswordTransformertrait + AES-256-GCM implementation (wp_mobile)encrypt/decryptmethods#[uniffi::export(with_foreign)]so platforms can provide hardware-backed implementationsAesGcmPasswordTransformerserves as a cross-platform fallback (particularly for Linux where platform keystores are unavailable)AccountRepositoryfor storing and retrieving encrypted site credentialsSwift bindings for persistence types
AccountRepository,PasswordTransformer, etc. to the public Swift APIAesGcmPasswordTransformeron Linux via#if os(Linux)SecureEnclavePasswordTransformerfills this role insteadSecureEnclavePasswordTransformer(Apple)kSecAttrServicefor visibility in Keychain Access@Suite(.serialized)to prevent cooperative thread pool deadlocks during SE key creationKeystorePasswordTransformer(Android)isHardwareBackedproperty so callers can check the security levelTest plan
cargo test --lib— Rust unit tests forAesGcmPasswordTransformerandAccountRepositorySecureEnclavePasswordTransformer(22 tests: round-trip, key persistence, error paths)KeystorePasswordTransformer(15 tests: round-trip, key reuse, error paths, tampered ciphertext)cargo clippyandcargo fmtpass