333 lines
11 KiB
Markdown
333 lines
11 KiB
Markdown
<!-- file: deltas/0.2.5/pre.004.md -->
|
|
<!-- version: 1 -->
|
|
|
|
# Delta `0.2.5-pre.004` — Argon2id + XChaCha20-Poly1305 + CSPRNG + vecteur crypto
|
|
|
|
## Base requise
|
|
|
|
```text
|
|
livraison : 0.2.5-pre.003-fix.001
|
|
workspace.package.version = "0.2.5-pre.3.fix.1"
|
|
```
|
|
|
|
La base effective est `pre.003` complétée par `pre.003-fix.001` et par les deux réorganisations opérateur conservées dans `constants.rs` et `lib.rs` : bloc unique de `pub const` avant `pub(crate) const`, puis groupe unique de `pub use` avant le groupe `pub(crate) use`.
|
|
|
|
Les validations opérateur fournies pour cette base sont propres :
|
|
|
|
```text
|
|
cargo fmt --all -> terminé
|
|
cargo check --workspace -> terminé sans warning
|
|
cargo clippy --workspace --all-targets -> terminé sans warning
|
|
cargo test -p ksp-wallet-lib -> 18 unit tests OK
|
|
2 dependency-boundary tests OK
|
|
5 public API tests OK
|
|
2 doc-tests compile_fail OK
|
|
0 échec
|
|
cargo tree -p ksp-wallet-lib -d -> aucune duplication dans le sous-arbre Wallet
|
|
```
|
|
|
|
Le workspace possède par ailleurs plusieurs générations transitives de `base64` (`0.21.7`, `0.22.1`, `0.23.1`), mais le sous-arbre `ksp-wallet-lib` validé en `pre.003-fix.001` ne contient aucune duplication. Les audits inverses doivent donc qualifier la version (`base64@0.23.1`) lorsque nécessaire.
|
|
|
|
## Objectif
|
|
|
|
Matérialiser la première couche cryptographique **in-memory** du format V1 sans encore créer/ouvrir un wallet complet :
|
|
|
|
```text
|
|
Argon2id v19 password KDF
|
|
KEK 32 octets
|
|
XChaCha20-Poly1305
|
|
content keys 32 octets
|
|
wrapping / unwrapping authentifié
|
|
CSPRNG OS via getrandom
|
|
zeroization des clés/buffers secrets possédés
|
|
premier vecteur public KDF + wrapping
|
|
benchmark opérateur des candidats Argon2 de création
|
|
```
|
|
|
|
Restent explicitement hors tranche :
|
|
|
|
```text
|
|
payload owner-control réel
|
|
payload metadata réel
|
|
payload secret réel
|
|
state signature Ed25519 effective
|
|
create/open VIEW/OWNER
|
|
filesystem/persistence
|
|
signature Solana
|
|
rotations de passwords
|
|
import/export
|
|
```
|
|
|
|
## Version Cargo
|
|
|
|
Conformément à `VER-ID-009` :
|
|
|
|
```text
|
|
0.2.5-pre.3.fix.1 -> 0.2.5-pre.4
|
|
```
|
|
|
|
Le compteur documentaire du `Cargo.toml` racine passe de `146` à `148` : `pre.003-fix.001` avait modifié ce fichier sans consommer le numéro `147`; cette livraison restaure l'historique `GEN-FILE-004` avant sa propre modification. Le même principe est appliqué à `wire.rs` (`1 -> 3`, avec `2` consommé conceptuellement par `pre.003-fix.001`) et à `lib.rs` (`2 -> 4`, avec `3` correspondant à la réorganisation opérateur post-`pre.003`).
|
|
|
|
## Dépendances
|
|
|
|
Nouvelles dépendances communes sous `[workspace.dependencies]` :
|
|
|
|
```toml
|
|
argon2 = { version = "^0.5", default-features = false }
|
|
chacha20poly1305 = { version = "^0.11", default-features = false }
|
|
getrandom = { version = "^0.4", default-features = false }
|
|
```
|
|
|
|
Le manifest Wallet active uniquement les features consommées :
|
|
|
|
```toml
|
|
argon2 = { workspace = true, features = ["zeroize"] }
|
|
chacha20poly1305 = { workspace = true, features = ["alloc", "zeroize"] }
|
|
getrandom.workspace = true
|
|
```
|
|
|
|
Audit actuel de la tranche :
|
|
|
|
```text
|
|
argon2 génération stable 0.5.x, publiée 0.5.3 ; 0.6 reste release-candidate
|
|
chacha20poly1305 génération stable 0.11.x, publiée 0.11.0
|
|
getrandom génération stable 0.4.x, publiée 0.4.3
|
|
zeroize déjà présent au workspace
|
|
```
|
|
|
|
`argon2` n'active ni API PHC/password-hash, ni rand, ni alloc par commodité ; Wallet utilise directement `hash_password_into`. `chacha20poly1305` active `alloc` parce que l'API AEAD utilisée retourne les ciphertexts/plaintexts dans des `Vec<u8>`, et `zeroize` afin de durcir les états internes de la primitive. Le CSPRNG est possédé explicitement par Wallet via `getrandom` plutôt que par une feature de génération aléatoire de l'AEAD.
|
|
|
|
Aucun client RPC, aucune crate Solana supplémentaire, Config, Transport, Store, Tauri ou `tracing` direct n'est ajouté.
|
|
|
|
## Argon2id V1
|
|
|
|
La dérivation utilise exactement :
|
|
|
|
```text
|
|
algorithm Argon2id
|
|
version 19 / 0x13
|
|
password octets UTF-8 exacts fournis par le caller
|
|
salt octets sérialisés dans le key slot
|
|
m_cost memory_kib sérialisé
|
|
t_cost iterations sérialisé
|
|
p_cost parallelism sérialisé
|
|
output 32 octets
|
|
pepper aucun
|
|
secret ext. aucun
|
|
```
|
|
|
|
Les bornes V1 déjà figées sont réappliquées avant le KDF. La tranche ajoute explicitement l'invariant Argon2 :
|
|
|
|
```text
|
|
memory_kib >= 8 * parallelism
|
|
```
|
|
|
|
Un password vide ou supérieur à `1024` octets est rejeté par la primitive interne.
|
|
|
|
Le KDF reste sync/in-memory à ce niveau bas. `pre.005+` doit l'appeler depuis les futurs flux async create/open via la frontière blocking prévue par le plan ; aucune API async fictive n'est ajoutée ici.
|
|
|
|
## Default Argon2 non figé
|
|
|
|
Cette livraison **ne choisit pas arbitrairement** le profil de création. Le test opérateur ignoré par défaut compare :
|
|
|
|
```text
|
|
64 MiB / 3 passes / 1 lane
|
|
128 MiB / 3 passes / 1 lane
|
|
256 MiB / 3 passes / 1 lane
|
|
```
|
|
|
|
Commande dédiée après les validations normales :
|
|
|
|
```bash
|
|
cargo test -p ksp-wallet-lib benchmark_argon2_creation_candidates -- --ignored --nocapture --test-threads=1
|
|
```
|
|
|
|
Le résultat doit être conservé dans le retour opérateur. `pre.005` ne figera le default de création qu'après examen de ces mesures. Les wallets existants resteront indépendants de ce default grâce aux paramètres sérialisés dans chaque slot.
|
|
|
|
## XChaCha20-Poly1305
|
|
|
|
La primitive V1 utilise :
|
|
|
|
```text
|
|
key 32 octets
|
|
nonce 24 octets
|
|
AAD bytes TLV domain-separated figés en pre.003
|
|
ciphertext = encrypted bytes || tag Poly1305 16 octets
|
|
```
|
|
|
|
Le nonce est toujours fourni séparément à l'AEAD. La tranche ne construit aucune canonicalisation JSON crypto : les AAD restent ceux du codec sémantique TLV de `pre.003`.
|
|
|
|
Toute erreur de tag/déchiffrement est ramenée au code générique :
|
|
|
|
```text
|
|
wallet/authentication_failed
|
|
```
|
|
|
|
Le code ne produit donc pas d'oracle public distinguant key, nonce, AAD ou ciphertext incorrect.
|
|
|
|
## CSPRNG et secrets en mémoire
|
|
|
|
`getrandom::fill` fournit directement les octets provenant de la source cryptographique de l'OS. Une défaillance devient :
|
|
|
|
```text
|
|
wallet/randomness_failed
|
|
```
|
|
|
|
Aucun secret, seed ou état RNG KSP n'est introduit.
|
|
|
|
Le type interne de clé 32 octets :
|
|
|
|
```text
|
|
n'est ni Copy ni Clone
|
|
Debug => SecretKeyV1(<redacted>)
|
|
zeroize ses octets au Drop
|
|
```
|
|
|
|
L'unwrap zeroize également son buffer plaintext intermédiaire après transfert dans le type secret possédé.
|
|
|
|
Les primitives restent volontairement privées en `pre.004`. Un `allow(dead_code)` **local au seul module `crypto.rs` et documenté** existe parce que cette tranche matérialise ces primitives une prerelease avant leurs callers production `create/open` de `pre.005`; il ne modifie aucun lint workspace et doit disparaître lorsque ces callers sont branchés.
|
|
|
|
## Vecteur cryptographique public
|
|
|
|
Nouveau fixture :
|
|
|
|
```text
|
|
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_crypto_vectors.json
|
|
```
|
|
|
|
Il contient exclusivement des valeurs publiques **TEST ONLY** et fixe de manière reproductible :
|
|
|
|
```text
|
|
password UTF-8
|
|
salt
|
|
m/t/p Argon2id
|
|
KEK dérivée attendue
|
|
content key 32 octets
|
|
nonce XChaCha 24 octets
|
|
AAD
|
|
wrapped key attendu
|
|
```
|
|
|
|
Les paramètres du vecteur (`32 KiB / 2 passes / 1 lane`) sont volontairement faibles pour conserver un test déterministe rapide. Ils ne constituent jamais le default de production ni une recommandation de sécurité.
|
|
|
|
Le vecteur a été recalculé indépendamment du code Rust avec une implémentation Argon2id et une construction XChaCha20-Poly1305 `HChaCha20 + ChaCha20-Poly1305 IETF`; l'implémentation indépendante a d'abord été vérifiée contre le vecteur HChaCha20 publié par la spécification XChaCha.
|
|
|
|
Les tests vérifient :
|
|
|
|
```text
|
|
KEK attendue
|
|
ciphertext/tag attendu
|
|
unwrap exact de la content key
|
|
tampering -> authentication_failed
|
|
Debug secret redacted
|
|
CSPRNG key/nonce callable
|
|
```
|
|
|
|
## Wire et spécification
|
|
|
|
`wire.rs` rejette maintenant avant crypto un tuple Argon2 dont la mémoire ne satisfait pas les huit blocs de 1 KiB par lane.
|
|
|
|
`docs/formats/KSPWALLET_V1.md` documente désormais indépendamment du code Rust :
|
|
|
|
```text
|
|
Argon2id v19 exact
|
|
password UTF-8 sans normalisation implicite
|
|
output KEK 32 octets
|
|
absence de pepper/secret externe
|
|
XChaCha20-Poly1305 key/nonce/tag
|
|
CSPRNG OS
|
|
content keys 32 octets
|
|
wrapping OWNER / VIEW
|
|
emplacement du vecteur crypto public
|
|
statut explicitement non fixé du default Argon2 de création
|
|
```
|
|
|
|
Le format V1 reste autonome : tous les salts, paramètres et nonces nécessaires sont dans le `.kspwallet`; aucun facteur externe n'est introduit.
|
|
|
|
## Canaries de dépendances
|
|
|
|
`dependency_boundary.rs` vérifie les trois nouvelles dépendances Wallet et leurs features, tout en conservant les interdictions :
|
|
|
|
```text
|
|
Wallet -X-> Config
|
|
Wallet -X-> Transport
|
|
Wallet -X-> ExecutionPolicy
|
|
Wallet -X-> Store
|
|
Wallet -X-> Tauri
|
|
Wallet -X-> tracing direct
|
|
Wallet -X-> solana-pubkey direct
|
|
```
|
|
|
|
`Pubkey` reste possédée/réexportée par `ksp-core-lib`; cette tranche n'ajoute aucune dépendance Solana Wallet.
|
|
|
|
## Validation attendue
|
|
|
|
Après application :
|
|
|
|
```bash
|
|
cargo fmt --all
|
|
cargo check --workspace
|
|
cargo clippy --workspace --all-targets
|
|
cargo test -p ksp-wallet-lib
|
|
cargo test --workspace
|
|
```
|
|
|
|
Audit de dépendances/features de la tranche :
|
|
|
|
```bash
|
|
cargo tree -p ksp-wallet-lib
|
|
cargo tree -p ksp-wallet-lib -d
|
|
cargo tree -e features -p ksp-wallet-lib
|
|
cargo tree -i argon2@0.5.3
|
|
cargo tree -i chacha20poly1305@0.11.0
|
|
cargo tree -i getrandom@0.4.3
|
|
cargo tree -i base64@0.23.1
|
|
cargo tree -i zeroize@1.9.0
|
|
```
|
|
|
|
L'audit doit confirmer au minimum :
|
|
|
|
```text
|
|
pas de duplication dans le sous-arbre Wallet sans justification
|
|
pas de default features Argon2/ChaCha réactivées accidentellement
|
|
pas de Config/Transport/Tauri/RPC Solana transitif propre à Wallet
|
|
base64 0.23.1 reste la génération consommée directement par Wallet
|
|
```
|
|
|
|
Puis exécuter séparément le benchmark opérateur :
|
|
|
|
```bash
|
|
cargo test -p ksp-wallet-lib benchmark_argon2_creation_candidates -- --ignored --nocapture --test-threads=1
|
|
```
|
|
|
|
## Fichiers ajoutés
|
|
|
|
```text
|
|
crates/ksp-wallet-lib/src/crypto.rs
|
|
crates/ksp-wallet-lib/unit_tests/crypto.rs
|
|
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_crypto_vectors.json
|
|
deltas/0.2.5/pre.004.md
|
|
```
|
|
|
|
## Fichiers modifiés
|
|
|
|
```text
|
|
Cargo.toml
|
|
ROADMAP.md
|
|
crates/ksp-wallet-lib/Cargo.toml
|
|
crates/ksp-wallet-lib/src/error.rs
|
|
crates/ksp-wallet-lib/src/lib.rs
|
|
crates/ksp-wallet-lib/src/wire.rs
|
|
crates/ksp-wallet-lib/tests/dependency_boundary.rs
|
|
crates/ksp-wallet-lib/tests/public_api.rs
|
|
crates/ksp-wallet-lib/unit_tests/wire.rs
|
|
docs/formats/000-README.md
|
|
docs/formats/KSPWALLET_V1.md
|
|
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
|
docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md
|
|
```
|
|
|
|
## Suite
|
|
|
|
`0.2.5-pre.005` consommera ces primitives pour les compartiments `owner_control` / metadata / secret, `create/open VIEW/OWNER` et l'authentification d'état OWNER niveau B. Le default Argon2 de création sera figé uniquement après réception du benchmark opérateur de cette tranche.
|