feat(derive_encrypt): Add KdfEncryptedData type#392
Conversation
KdfEncryptData combines two operations, key derivation and encryption, to generate a blob that contains both the key derivation parameters and the encrypted data. This way the derivation parameters do not need to be stored separately or defined statically in the application.
There was a problem hiding this comment.
Pull request overview
Adds a new “derive + encrypt” managed blob type (KdfEncryptedData) that packages key-derivation parameters together with ciphertext, enabling password-only decryption across the core Rust crate and its language/tooling wrappers.
Changes:
- Introduces
derive_encryptmodule withKdfEncryptedDataserialization/deserialization and encrypt/decrypt helpers (with optional AAD). - Extends enums/headers (
DataType,KdfEncryptedDataVersion/Subtype) and header validation to recognize the new blob type. - Exposes the feature through UniFFI, Python bindings, C FFI, and the CLI.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| uniffi/devolutions-crypto-uniffi/src/lib.rs | Exposes the new module/types to UniFFI and adds KdfEncryptedData to DataType. |
| uniffi/devolutions-crypto-uniffi/src/derive_encrypt.rs | Adds UniFFI-exported derive+encrypt / derive+decrypt helpers. |
| src/utils.rs | Updates validate_header to recognize DataType::KdfEncryptedData. |
| src/lib.rs | Documents and re-exports the new derive_encrypt API surface. |
| src/key_derivation/mod.rs | Adds DerivationParameters::derive() helper for deriving SecretKey from stored parameters. |
| src/key_derivation/key_derivation_v2.rs | Adds Argon2::derive_and_encrypt() convenience API and tests. |
| src/enums.rs | Introduces KdfEncryptedDataVersion and KdfEncryptedDataSubtype, and extends DataType. |
| src/derive_encrypt/mod.rs | Implements KdfEncryptedData type, encryption/decryption, parsing, and tests. |
| src/derive_encrypt/kdf_encrypted_data_v1.rs | Defines V1 payload format for KdfEncryptedData. |
| python/src/lib.rs | Adds Python bindings for derive+encrypt / derive+decrypt. |
| python/devolutions_crypto.pyi | Adds Python type stubs/docs for the new functions. |
| ffi/src/lib.rs | Adds C FFI functions for derive+encrypt sizing/encrypt/decrypt. |
| cli/src/main.rs | Adds CLI commands to derive+encrypt and derive+decrypt and updates header printing/detection. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 312aab91b8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "Codex (@codex) review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".
| let password = Zeroizing::new(slice::from_raw_parts(password, password_length).to_vec()); | ||
| let result = slice::from_raw_parts_mut(result, result_length); | ||
|
|
||
| let derivation_parameters = match derive_key(&password, key_derivation_version) { |
There was a problem hiding this comment.
Avoid deriving the password twice in FFI encryption
When this FFI path is used, derive_key already runs the selected KDF and then discards the returned SecretKey; the subsequent encrypt_with_password_and_aad call derives from the same password and parameters again. With the default Argon2 path, every DeriveEncryptData call therefore pays the memory-hard KDF cost twice, unlike the other wrappers that construct parameters directly before encrypting.
Useful? React with 👍 / 👎.
af495c0
into
master
KdfEncryptData combines two operations, key derivation and encryption, to generate a blob that contains both the key derivation parameters and the encrypted data. This way the derivation parameters do not need to be stored separately or defined statically in the application.