Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encryption and key management (ready for review) #156

Merged
merged 48 commits into from
Oct 31, 2024

Conversation

ryardley
Copy link
Contributor

@ryardley ryardley commented Oct 23, 2024

Closes: #128

This PR addresses some security issues around key management whilst preparing for docker compatibility and as a consequence dappnode deployment.

  • Setup cipher for encryption of keys and secrets - this is done with the Cipher struct & package
  • Above is used to add AES encryption to:
    • Keyshare Secrets
    • Eth Private Keys
  • Sets up CLI system for commands and config for managing node state.
    • Adds CLI for managing a given password
    • Adds CLI for managing a wallet private key
  • Move address to config.yaml instead of passing it in to CLI you can see some config.yaml examples setup for the test here
  • Create config.yaml in ~/.config/enclave/config.yaml for managing config. See AppConfig
  • Create secrets file in ~/.config/encalve/key which can be overridden in the config.yaml This is managed by the PasswordManager
  • Ensure sled db writes to ~/.local/enclave/db by default according to linux conventions

You can now use the cli in the repo with the command:

yarn enclave --help

Be aware this will take time to compile if you have not yet done it so there might be a lag between when you attempt to run the command and the time the command responds.

This PR means that node operators can follow docker conventions for loading secrets from a protected position within the file system as opposed to using env vars for better security so a user can use kubernetes / docker swarm or something else to run their node should they desire without the danger of accidentally leaking env vars.

Also we have attempted to follow linux XDG conventions in terms of defaults for data location.

In terms of encryption we basically pad the password with Argon2 and then use it to encrypt the values. With one salt per encryption. We don't however store the padded secret but instead store the raw secret in the file in accordance with what a node operator would do as they will assume an encrypted channel to the volume mount and will likely simply set their secret through docker secrets or using a secrets manager which often loads secrets via encrypted mounted volumes.

We could if it is found to be a requirement - use individual random keys for storing the secrets that are encrypted by the password but for now this seems like overkill at this preliminary stage - so here we are just using the master password approach and can look at key rotation techniques later.

Summary by CodeRabbit

  • New Features

    • Introduced new modules and functionalities for managing encryption and decryption within the cipher node.
    • Added a command structure for managing passwords, including create, delete, and overwrite commands.
    • Implemented a comprehensive configuration management system for blockchain applications.
    • Enhanced the command-line interface for better user interaction and error handling.
    • Added new dependencies to support additional functionalities, including local paths for cipher and config.
    • Introduced a new GetErrors message type to enhance error management in the EventBus.
    • Added new configuration files for integration testing across multiple directories, specifying Ethereum addresses and RPC URLs.
    • Updated the setup_aggregator and setup_ciphernode functions for improved modularity and asynchronous operations.
  • Bug Fixes

    • Enhanced error handling across various modules, improving the robustness of operations.
  • Documentation

    • Added configuration files and scripts to facilitate integration testing and environment setup.
  • Chores

    • Updated dependencies across multiple packages to enhance functionality and maintainability.

@ryardley ryardley marked this pull request as ready for review October 23, 2024 01:43
Copy link
Contributor

coderabbitai bot commented Oct 23, 2024

Walkthrough

The pull request introduces significant changes across multiple files in the ciphernode project. Key modifications include updates to Cargo.toml files to add new workspace members and dependencies, restructuring of the command-line interface in main.rs, and enhancements to key management functionalities in the keyshare module. Additionally, new modules and methods for password management and error handling are introduced, along with various configuration files for integration testing.

Changes

File Path Change Summary
packages/ciphernode/Cargo.toml Added members cipher and config; added dependencies: aes-gcm, argon2, dirs, figment, hex, zeroize. Updated argon2 version.
packages/ciphernode/data/src/snapshot.rs Removed DataStore import; retained existing trait definitions.
packages/ciphernode/enclave/Cargo.toml Added multiple dependencies; modified config to reference local path.
packages/ciphernode/enclave/src/main.rs Introduced owo function; replaced Args with Cli; restructured main function.
packages/ciphernode/keyshare/Cargo.toml Added dependencies: actix, anyhow, async-trait.
packages/ciphernode/keyshare/src/keyshare.rs Added cipher field; introduced set_secret and get_secret methods.
packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs Updated test functions to include cipher initialization and error handling.
tests/basic_integration/test.sh Introduced CIPHERNODE_SECRET variable; modified launch_ciphernode.
.github/workflows/rust-ci.yml Added environment variable output command before running tests.
package.json Renamed script from "ciphernode:launch" to "enclave"; removed "ciphernode:aggregator".
packages/ciphernode/cipher/Cargo.toml Introduced new package with dependencies for cipher.
packages/ciphernode/cipher/src/cipher.rs Implemented cryptographic functionalities for encryption and decryption.
packages/ciphernode/cipher/src/lib.rs Added cipher and password_manager modules; exported relevant entities.
packages/ciphernode/cipher/src/password_manager.rs Introduced PasswordManager trait and its implementations.
packages/ciphernode/config/Cargo.toml Introduced new package for configuration management with dependencies.
packages/ciphernode/config/src/app_config.rs Defined configuration structures and loading mechanism.
packages/ciphernode/core/src/eventbus.rs Added GetErrors message type to EventBus.
packages/ciphernode/data/src/sled_store.rs Modified SledStore to use SledDb type; added new methods for database interaction.
packages/ciphernode/enclave/src/bin/aggregator.rs Deleted file containing main entry point for aggregator application.
packages/ciphernode/enclave/src/commands/aggregator/mod.rs Introduced command module for aggregator with execution logic.
packages/ciphernode/enclave/src/commands/password/create.rs Added functionality for password creation and management.
packages/ciphernode/enclave/src/commands/password/delete.rs Added functionality for securely deleting passwords.
packages/ciphernode/enclave/src/commands/wallet/mod.rs Introduced wallet command module for managing wallet operations.
packages/ciphernode/enclave/src/commands/wallet/set.rs Added functionality for setting wallet keys.
packages/ciphernode/enclave/src/ciphernode.rs Removed MainCiphernode; introduced setup_ciphernode function.
packages/ciphernode/enclave_node/Cargo.toml Added dependencies for config and cipher.
packages/ciphernode/enclave_node/src/lib.rs Updated module exports to include datastore and exclude app_config.
packages/ciphernode/evm/Cargo.toml Added dependencies for data and cipher.
packages/ciphernode/router/Cargo.toml Added cipher dependency.
packages/ciphernode/router/src/hooks.rs Updated features to include cipher and enhance error handling.
packages/ciphernode/router/src/repositories.rs Added eth_private_key method to Repositories struct.
tests/basic_integration/lib/ag/config.yaml Introduced new configuration file with blockchain parameters.
tests/basic_integration/lib/clean_folders.sh Added clean_folders function to clean output artifacts.
tests/basic_integration/lib/prebuild.sh Modified build command to exclude aggregator binary.

Assessment against linked issues

Objective Addressed Explanation
Manage encrypted data for Secret Shares and EVM Private Keys (#128)
Implement key management strategy for ZK Friendly Private Keys (#128)

Possibly related PRs

Suggested reviewers

  • auryn-macmillan
  • nginnever
  • samepant
  • hmzakhalid

🐰 In the meadow where secrets lie,
We encrypt our dreams, oh so high.
With ciphers strong and keys in hand,
We hop through code, a brave new land.
Let’s manage our treasures, both near and far,
In this rabbit's tale, we shine like a star! ✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ryardley ryardley requested a review from fhedude October 23, 2024 01:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (6)
packages/ciphernode/keyshare/Cargo.toml (1)

8-8: Good choice of cryptographic libraries.

The selection of cryptographic libraries aligns well with the PR objectives:

  • aes-gcm: Provides authenticated encryption
  • argon2: Strong password-based key derivation
  • rand: Secure random number generation
  • zeroize: Secure memory wiping

Consider implementing the following security best practices:

  1. Use zeroize on all sensitive buffers containing keys or plaintext
  2. Ensure Argon2 parameters are tuned appropriately for your use case
  3. Never reuse AES-GCM nonces with the same key

Also applies to: 10-10, 15-15, 18-18

packages/ciphernode/enclave/Cargo.toml (1)

16-16: Consider using workspace versioning for config dependency.

The config crate is explicitly pinned to version 0.14.0 while other dependencies use workspace-level version management. This inconsistency could lead to maintenance overhead and version conflicts.

Apply this change to align with the project's versioning strategy:

-config = "0.14.0"
+config = { workspace = true }
packages/ciphernode/data/src/snapshot.rs (2)

Line range hint 1-50: Consider documenting encryption implications in trait documentation.

Given that this PR introduces encryption features, it would be helpful to document how these traits interact with encrypted data, particularly:

  • How Snapshot handles encrypted fields
  • Whether Checkpoint performs any encryption/decryption during persistence
  • How FromSnapshot and FromSnapshotWithParams handle encrypted data during reconstitution

Example documentation addition for Snapshot trait:

 /// This trait enables the self type to report their state snapshot
+///
+/// When implementing this trait for types containing encrypted data:
+/// - Ensure the Snapshot type can properly serialize encrypted fields
+/// - Consider whether the snapshot should store encrypted or decrypted form
 pub trait Snapshot
 where
     Self: Sized,
 {

Line range hint 18-29: Consider encryption-aware Repository implementation.

Since this PR introduces encryption features, ensure that the Repository implementation properly handles encrypted data persistence. Consider implementing encryption/decryption at the Repository level rather than requiring each implementation to handle it separately.

Key considerations:

  1. Implement transparent encryption/decryption in Repository operations
  2. Handle encryption key management within Repository
  3. Ensure atomic operations when writing encrypted data
packages/ciphernode/keyshare/src/keyshare.rs (1)

Line range hint 18-23: Enhance memory safety for sensitive data storage

The secret field stores sensitive cryptographic material but isn't protected against memory dumps. Consider using Zeroizing<Vec<u8>> to ensure secure cleanup of sensitive data when it goes out of scope.

Apply this change:

pub struct Keyshare {
    fhe: Arc<Fhe>,
    store: Repository<KeyshareState>,
    bus: Addr<EventBus>,
-   secret: Option<Vec<u8>>,
+   secret: Option<Zeroizing<Vec<u8>>>,
    address: String,
}
tests/basic_integration/test.sh (1)

83-85: Document and validate the secret parameter.

The function should validate that the secret parameter is not empty and document its purpose.

Apply this diff to improve the implementation:

 launch_ciphernode() {
+    # $1: Ethereum address of the ciphernode
+    # $2: Secret key used for encrypting Keyshare Secrets
     local address="$1"
     local secret="$2"
+    
+    if [ -z "$secret" ]; then
+        echo "Error: CIPHERNODE_SECRET must not be empty" >&2
+        return 1
+    fi
+
     heading "Launch ciphernode $address"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 1c91550 and 6c7d28a.

⛔ Files ignored due to path filters (1)
  • packages/ciphernode/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • packages/ciphernode/Cargo.toml (4 hunks)
  • packages/ciphernode/data/src/snapshot.rs (1 hunks)
  • packages/ciphernode/enclave/Cargo.toml (1 hunks)
  • packages/ciphernode/enclave/src/main.rs (2 hunks)
  • packages/ciphernode/keyshare/Cargo.toml (1 hunks)
  • packages/ciphernode/keyshare/src/encryption.rs (1 hunks)
  • packages/ciphernode/keyshare/src/keyshare.rs (5 hunks)
  • packages/ciphernode/keyshare/src/lib.rs (1 hunks)
  • packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs (3 hunks)
  • tests/basic_integration/test.sh (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/ciphernode/keyshare/src/lib.rs
🧰 Additional context used
📓 Learnings (2)
packages/ciphernode/Cargo.toml (2)
Learnt from: ryardley
PR: gnosisguild/enclave#133
File: packages/ciphernode/Cargo.toml:19-63
Timestamp: 2024-10-08T19:45:18.209Z
Learning: The dependency versions specified are acceptable as per project standards.
Learnt from: ryardley
PR: gnosisguild/enclave#133
File: packages/ciphernode/Cargo.toml:19-63
Timestamp: 2024-10-04T00:33:53.250Z
Learning: The dependency versions specified are acceptable as per project standards.
packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs (1)
Learnt from: ryardley
PR: gnosisguild/enclave#145
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:82-83
Timestamp: 2024-10-22T02:10:34.864Z
Learning: In the file `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, when reviewing test functions like `generate_pk_share`, minor performance optimizations (e.g., minimizing mutex locks) are not a priority.
🔇 Additional comments (13)
packages/ciphernode/enclave/Cargo.toml (2)

14-14: LGTM: Good choice for error handling.

The addition of anyhow is appropriate for handling various error types that may occur during cryptographic operations.


19-20: Verify logging configuration for sensitive data.

Adding tracing capabilities in a cryptographic context requires careful consideration to prevent accidental logging of sensitive information like encryption keys or plaintext data.

Consider:

  1. Implementing appropriate log filtering for sensitive data
  2. Using debug-level logging for crypto operations
  3. Adding log sanitization middleware

Run this check to identify potential sensitive data logging:

✅ Verification successful

Let me gather more context about the logging patterns, particularly focusing on the encryption and cryptographic operations.

The above scripts will help us understand:

  1. The context around encryption operations and their logging
  2. Any trace-level logging specifically in crypto-related modules
  3. Logging configuration files that might contain filtering rules

Let's check the logger implementation and configuration since we found the logger module, and also look for any encryption-related logging patterns.

This will help us understand:

  1. The logging implementation and any built-in safeguards
  2. The context of encryption-related logging
  3. The patterns of sensitive data handling in encryption methods

Based on the gathered information, I can now provide the final response:

Logging implementation appears secure with appropriate safeguards

The logging implementation in the codebase shows good security practices:

  • The SimpleLogger only logs event metadata and error conditions without exposing sensitive data
  • No direct logging of encryption keys, secrets, or encrypted content was found
  • Error logging is properly abstracted through the EnclaveEvent system
  • The only encryption-related log found is a high-level error message that doesn't expose sensitive data

The tracing dependencies can be safely used as currently implemented, as the logging patterns show appropriate abstraction and sanitization of sensitive information.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential logging of sensitive data
rg -i "trace!|debug!|info!|warn!|error!" | grep -i "key\|secret\|password\|encrypt"

Length of output: 722


Script:

#!/bin/bash
# Search for encryption-related functions and their logging
ast-grep --pattern 'fn $_($$$) {
  $$$
  encrypt$_($$$)
  $$$
}'

# Also check for any trace-level logging in crypto-related files
rg -i "trace!" packages/ciphernode/crypto/
rg -i "trace!" packages/ciphernode/enclave/

# Look for logging configuration files
fd -e rs -e toml . packages/ciphernode/ --exec grep -l -i "log\|trace"

Length of output: 1137


Script:

#!/bin/bash
# Check logger implementation for any filtering or sanitization
cat packages/ciphernode/logger/src/lib.rs
cat packages/ciphernode/logger/src/logger.rs

# Look for encryption-related logging in the codebase
rg -i "encrypt" -C 2 packages/ciphernode/ | grep -i "trace\|debug\|info\|warn\|error"

# Check for any sensitive data handling patterns
ast-grep --pattern 'impl $_ {
  $$$
  fn encrypt($$$) {
    $$$
  }
  $$$
}'

Length of output: 1810

packages/ciphernode/Cargo.toml (2)

22-22: LGTM! Cryptographic dependencies are appropriate and up-to-date.

The selected cryptographic dependencies (aes-gcm, argon2, and zeroize) are well-maintained, widely-used implementations that align perfectly with the PR's objective of implementing secure AES encryption and key management.

Also applies to: 31-31, 68-68


45-45: LGTM! Property-based testing is valuable for cryptographic implementations.

Adding proptest is a good choice as it will help ensure the robustness of the encryption implementation through property-based testing.

packages/ciphernode/data/src/snapshot.rs (1)

1-4: Verify the removal of DataStore import.

While removing unused imports is good practice, let's verify that the DataStore removal doesn't impact the new encryption features being introduced.

packages/ciphernode/enclave/src/main.rs (1)

1-2: Verify environment variable handling.

While the std::env import is added, there's no validation of the required CIPHERNODE_SECRET environment variable during startup. This could lead to runtime errors if the secret is missing.

Let's verify how CIPHERNODE_SECRET is used in the codebase:

Consider adding validation during startup:

// Suggested addition after line 43
let secret = std::env::var("CIPHERNODE_SECRET")
    .expect("CIPHERNODE_SECRET environment variable must be set");
packages/ciphernode/keyshare/src/keyshare.rs (1)

1-1: Verify encryption dependencies configuration

Let's ensure the encryption-related dependencies are properly configured with secure versions and features.

tests/basic_integration/test.sh (1)

121-124: 🛠️ Refactor suggestion

Consider testing with different secrets per node.

Currently, all nodes use the same secret. To thoroughly test encryption isolation and key management, consider using different secrets for each node.

Let's verify if the system requires the same secret across all nodes:

If different secrets are supported, consider this improvement:

-launch_ciphernode "$CIPHERNODE_ADDRESS_1" "$CIPHERNODE_SECRET"
-launch_ciphernode "$CIPHERNODE_ADDRESS_2" "$CIPHERNODE_SECRET"
-launch_ciphernode "$CIPHERNODE_ADDRESS_3" "$CIPHERNODE_SECRET"
-launch_ciphernode "$CIPHERNODE_ADDRESS_4" "$CIPHERNODE_SECRET"
+# Test with different secrets to ensure proper encryption isolation
+launch_ciphernode "$CIPHERNODE_ADDRESS_1" "test-secret-node1"
+launch_ciphernode "$CIPHERNODE_ADDRESS_2" "test-secret-node2"
+launch_ciphernode "$CIPHERNODE_ADDRESS_3" "test-secret-node3"
+launch_ciphernode "$CIPHERNODE_ADDRESS_4" "test-secret-node4"
✅ Verification successful

Let me gather more information about the secret handling in the codebase.

The previous results showed some references to secret shares in the keyshare module, but we need more context about how secrets are validated and used in the ciphernode implementation to determine if different secrets per node are supported or if there are any constraints requiring shared secrets.


Let me check one more aspect about how the secrets are used in the encryption/decryption process.

The keyshare implementation shows that each node generates its own keyshare and secret independently during the CiphernodeSelected event, but we need to verify if the FHE (Fully Homomorphic Encryption) implementation requires shared secrets for proper communication between nodes.


Based on the code analysis, I can now provide the final response:

Using different secrets per node is supported and recommended

The codebase reveals that:

  • Each node independently generates its own secret key and public key share via generate_keyshare()
  • The FHE implementation uses a threshold cryptography scheme where:
    • Nodes generate individual key shares
    • Public keys are aggregated (get_aggregate_public_key)
    • Decryption shares are combined (get_aggregate_plaintext)
  • There's no requirement or validation enforcing shared secrets between nodes

The original review suggestion to use different secrets per node is correct and aligns with the system's design for proper encryption isolation testing.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any documentation or code that indicates whether nodes should share secrets
rg -i "secret.*share" --type rust
rg -i "same.*secret" --type rust

Length of output: 516


Script:

#!/bin/bash
# Check how secrets are used in the ciphernode implementation
ast-grep --pattern 'fn launch_ciphernode'

# Look for secret validation or requirements
rg -i "secret.*valid" --type rust
rg -i "secret.*require" --type rust

# Check keyshare implementation for any constraints
fd keyshare.rs --exec cat {}

Length of output: 5561


Script:

#!/bin/bash
# Check how secrets are used in encryption/decryption and FHE operations
fd fhe.rs --exec cat {}

# Look for any communication between nodes that might require shared secrets
rg -i "node.*communicate" --type rust
rg -i "node.*connection" --type rust

Length of output: 5656

packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs (1)

274-274: Verify secret handling in remaining test cases

The secret environment variable is only set in two test cases. Other test cases might need the same environment setup for consistency.

Let's verify if other test cases require the secret:

Also applies to: 380-380

packages/ciphernode/keyshare/src/encryption.rs (4)

12-23: Ensure Argon2 and AES parameters meet current security recommendations

The Argon2 parameters (ARGON2_M_COST, ARGON2_T_COST, ARGON2_P_COST) and AES parameters (AES_SALT_LEN, AES_NONCE_LEN) are critical for security and performance. Please verify that these values align with the latest security best practices to prevent vulnerabilities. For example, increasing the memory cost or iterations may enhance resistance against brute-force attacks.


24-41: argon2_derive_key function is implemented correctly with secure practices

The key derivation function correctly uses Argon2id with appropriate parameters and zeroizes sensitive data. Error handling is properly managed.


43-78: encrypt_data function securely encrypts data with proper handling of sensitive information

The encrypt_data function appropriately handles encryption using AES-GCM and derives the key securely using Argon2. Sensitive data is zeroized after use, and random salt and nonce are correctly generated and stored.


80-105: decrypt_data function correctly decrypts data with proper error handling

The decrypt_data function properly extracts the salt and nonce, derives the key, and decrypts the ciphertext. Error handling is managed correctly, and sensitive data is zeroized.

packages/ciphernode/keyshare/Cargo.toml Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/keyshare.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/keyshare.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/keyshare.rs Outdated Show resolved Hide resolved
tests/basic_integration/test.sh Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6c7d28a and 76461f5.

📒 Files selected for processing (2)
  • packages/ciphernode/keyshare/Cargo.toml (1 hunks)
  • packages/ciphernode/keyshare/src/keyshare.rs (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ciphernode/keyshare/Cargo.toml
🧰 Additional context used
🔇 Additional comments (4)
packages/ciphernode/keyshare/src/keyshare.rs (4)

Line range hint 1-16: LGTM! Appropriate security-focused imports.

The addition of zeroize and encryption-related imports aligns well with the security objectives.


128-134: LGTM! Proper encryption integration

The integration with the new encryption system is implemented correctly with appropriate error handling.


52-56: 🛠️ Refactor suggestion

Enhance memory safety with Zeroizing wrapper

While the encryption is implemented correctly, consider wrapping the input data with Zeroizing to ensure secure handling:

-    fn set_secret(&mut self, mut data: Vec<u8>) -> Result<()> {
+    fn set_secret(&mut self, data: Zeroizing<Vec<u8>>) -> Result<()> {
-        let encrypted = encrypt_data(&mut data)?;
+        let encrypted = encrypt_data(&data)?;
         self.secret = Some(encrypted);
         Ok(())
     }

Likely invalid or redundant comment.


161-171: 🛠️ Refactor suggestion

Verify secure cleanup of decrypted secret

While the decryption process is correct, ensure the secret is securely cleared from memory after use:

Consider wrapping the secret in a scope to ensure cleanup:

         let Ok(secret) = self.get_secret() else {
             self.bus.err(
                 EnclaveErrorType::Decryption,
                 anyhow!("Secret not available for Keyshare for e3_id {e3_id}"),
             );
             return;
         };
-
-        let Ok(decryption_share) = self.fhe.decrypt_ciphertext(DecryptCiphertext {
-            ciphertext: ciphertext_output.clone(),
-            unsafe_secret: secret,
-        }) else {
+        let decryption_share = {
+            let Ok(result) = self.fhe.decrypt_ciphertext(DecryptCiphertext {
+                ciphertext: ciphertext_output.clone(),
+                unsafe_secret: secret,
+            }) else {
+                self.bus.err(
+                    EnclaveErrorType::Decryption,
+                    anyhow!("error decrypting ciphertext: {:?}", ciphertext_output),
+                );
+                return;
+            };
+            result
+        }; // secret is dropped here

packages/ciphernode/keyshare/src/keyshare.rs Outdated Show resolved Hide resolved
@ryardley
Copy link
Contributor Author

Just going to refactor to have a struct accept a secret so I can run tests in parallel as more comprehensive tests fail.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (1)
packages/ciphernode/keyshare/src/keyshare.rs (1)

51-69: Document encryption implementation and future improvements

The current implementation aligns with Phase 1 of the security enhancement plan, using environment variables for encryption. Consider adding documentation that:

  1. Describes the current encryption strategy
  2. Outlines plans for Phase 2 key rotation
  3. Lists security considerations for production deployment

This will help future maintainers understand the security roadmap and implementation decisions.

Add the following documentation above the set_secret method:

/// Encrypts and stores the secret using AES-GCM with a key derived from CIPHERNODE_SECRET.
/// 
/// # Security Considerations
/// - Current implementation (Phase 1):
///   - Uses environment variable for key material
///   - No key rotation support
/// 
/// # Future Improvements (Phase 2)
/// - Implement key rotation
/// - Store encrypted keys separately
/// - Add key version tracking
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 76461f5 and 42b54d2.

📒 Files selected for processing (2)
  • packages/ciphernode/keyshare/src/encryption.rs (1 hunks)
  • packages/ciphernode/keyshare/src/keyshare.rs (5 hunks)
🧰 Additional context used
📓 Learnings (1)
packages/ciphernode/keyshare/src/encryption.rs (1)
Learnt from: ryardley
PR: gnosisguild/enclave#156
File: packages/ciphernode/keyshare/src/keyshare.rs:52-56
Timestamp: 2024-10-23T01:59:19.277Z
Learning: The `encrypt_data` function zeroizes the plaintext data internally, so additional zeroizing is unnecessary.
🔇 Additional comments (3)
packages/ciphernode/keyshare/src/keyshare.rs (2)

60-69: ⚠️ Potential issue

Validate environment variable presence during initialization

The current implementation attempts to create an Encryptor for each operation, which could fail if the environment variable is not set. This should be validated during initialization instead.

#!/bin/bash
# Check if CIPHERNODE_SECRET is validated elsewhere
rg "CIPHERNODE_SECRET" --type rust

1-1: Verify usage of imported Zeroizing

The Zeroizing import appears to be unused in the current implementation. If it's not being used elsewhere in the codebase, consider removing it.

Also applies to: 12-15

packages/ciphernode/keyshare/src/encryption.rs (1)

24-41: LGTM! Secure implementation of key derivation

The implementation follows cryptographic best practices with proper:

  • Memory safety through zeroization
  • Error handling
  • Parameter validation

packages/ciphernode/keyshare/src/keyshare.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/encryption.rs Outdated Show resolved Hide resolved
@ryardley ryardley marked this pull request as draft October 23, 2024 02:56
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
packages/ciphernode/keyshare/src/encryption.rs (2)

61-62: Consider using a generic error message for encryption failures

The specific error message "Could not AES Encrypt given plaintext" could potentially leak timing information in case of errors. Consider using a generic message like "Encryption failed" instead.

-        .map_err(|_| anyhow!("Could not AES Encrypt given plaintext."))?;
+        .map_err(|_| anyhow!("Encryption failed"))?;

102-105: Add documentation for the Encryptor struct

Consider adding documentation comments to explain the purpose, usage, and security considerations of the Encryptor struct.

+/// Encryptor provides secure encryption and decryption of data using AES-GCM.
+/// It implements ZeroizeOnDrop to ensure sensitive key material is securely erased from memory.
+///
+/// # Example
+/// ```
+/// use ciphernode::Encryptor;
+///
+/// let encryptor = Encryptor::new("my_secure_password".to_owned());
+/// let mut data = b"secret data".to_vec();
+/// let encrypted = encryptor.encrypt_data(&mut data).unwrap();
+/// let decrypted = encryptor.decrypt_data(&encrypted).unwrap();
+/// ```
 #[derive(ZeroizeOnDrop)]
 pub struct Encryptor {
     key: Zeroizing<Vec<u8>>,
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 42b54d2 and 95a1fb7.

📒 Files selected for processing (1)
  • packages/ciphernode/keyshare/src/encryption.rs (1 hunks)
🧰 Additional context used
📓 Learnings (1)
packages/ciphernode/keyshare/src/encryption.rs (1)
Learnt from: ryardley
PR: gnosisguild/enclave#156
File: packages/ciphernode/keyshare/src/encryption.rs:77-100
Timestamp: 2024-10-23T02:49:42.460Z
Learning: In the `packages/ciphernode/keyshare/src/encryption.rs` file, avoid adding extra complexity to the `encrypt_data` and `decrypt_data` functions, such as adding a magic number or version prefix to the encrypted data format, unless there is a significant benefit.
🔇 Additional comments (2)
packages/ciphernode/keyshare/src/encryption.rs (2)

77-100: LGTM! Well-structured decryption implementation.

The decryption function includes proper input validation, clear separation of components, and secure error handling.


133-264: Excellent test coverage!

The test suite is comprehensive, covering:

  • Basic encryption/decryption
  • Empty and large data handling
  • Password mismatches
  • Binary and Unicode data
  • Corrupted data
  • Multiple encryption cycles
  • Performance measurements

@gnosisguild gnosisguild deleted a comment from coderabbitai bot Oct 23, 2024
@ryardley ryardley changed the title Encryption and simple key management Encryption and key management Oct 24, 2024
@ryardley
Copy link
Contributor Author

ryardley commented Oct 25, 2024

To complete this we need to build these commands:

# start enclave
enclave start 

# save privatekey encrypted to DataStore
enclave wallet set --from-env "PRIVATE_KEY" 

# start aggregator
enclave aggregator start

We can also look at this if it is easy:

# Store ciphernode secret in the correct location with the correct permissions
enclave password set --from-env "CIPHERNODE_SECRET"

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between b083df2 and f19caf7.

📒 Files selected for processing (2)
  • packages/ciphernode/cipher/src/cipher.rs (1 hunks)
  • packages/ciphernode/cipher/src/password_manager.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ciphernode/cipher/src/cipher.rs
🔇 Additional comments (9)
packages/ciphernode/cipher/src/password_manager.rs (9)

12-17: Trait PasswordManager is well-defined

The trait PasswordManager is clearly defined with asynchronous methods for password management, providing a consistent interface for different implementations.


19-29: InMemPasswordManager implementation is appropriate

The InMemPasswordManager correctly handles sensitive data in memory using Zeroizing, ensuring that the data is securely wiped when no longer needed.


40-57: EnvPasswordManager correctly implements PasswordManager trait

The implementation properly retrieves, sets, and deletes the key, handling sensitive data securely with Zeroizing.


59-76: InMemPasswordManager correctly implements PasswordManager trait

The in-memory password manager functions as expected, securely managing sensitive data and conforming to the defined trait.


78-88: FilePasswordManager constructor is correctly implemented

The constructor for FilePasswordManager properly initializes the path to the keyfile.


90-148: Implementation of PasswordManager for FilePasswordManager is well-structured

The methods for managing the keyfile are logically organized and make appropriate use of asynchronous execution.


98-106: Note on existing potential issue with file permissions

Previous comments have addressed potential race conditions and security concerns with file permission enforcement in get_key. Ensure that these are resolved appropriately.


117-147: Note on existing potential issue with keyfile creation permissions

Previous comments have highlighted concerns regarding the window of broader file permissions during keyfile creation in set_key. Verify that these issues have been addressed.


150-164: Note on existing suggestion to simplify ensure_file_permissions

There is an existing suggestion to simplify the ensure_file_permissions function for improved clarity and reliability. Please consider this in your revisions.

hmzakhalid
hmzakhalid previously approved these changes Oct 28, 2024
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (4)
packages/ciphernode/enclave/src/main.rs (2)

Line range hint 8-21: Consider moving ASCII art to a separate constants file.

The ASCII art constant could be moved to a separate constants module to keep the main file focused on core functionality and improve maintainability.


22-25: Improve function name and newline handling.

The function could be improved by:

  1. Using a more descriptive name (e.g., print_banner or display_logo)
  2. Consolidating multiple newline prints
-pub fn owo() {
+pub fn print_banner() {
     println!("\n\n\n\n\n{}", OWO);
-    println!("\n\n\n\n");
+    println!("\n");
 }
packages/ciphernode/keyshare/src/keyshare.rs (1)

166-176: Consider adding debug logging for troubleshooting

While the error handling is solid, consider adding debug-level logging before encryption/decryption operations to aid in troubleshooting issues in production. Ensure logs don't contain sensitive information.

Example:

+       tracing::debug!("Attempting to decrypt ciphertext for e3_id: {}", e3_id);
        let Ok(secret) = self.get_secret() else {
            self.bus.err(
                EnclaveErrorType::Decryption,
                anyhow!("Secret not available for Keyshare for e3_id {e3_id}"),
            );
            return;
        };
packages/ciphernode/config/src/app_config.rs (1)

213-318: Add tests for error cases

The test suite lacks coverage for error cases such as invalid configurations and directory creation failures.

Add the following test cases:

  1. Invalid Ethereum addresses in configuration
  2. Missing required fields
  3. Directory creation failures
  4. Invalid YAML syntax

Example test:

#[test]
fn test_invalid_config() {
    Jail::expect_with(|jail| {
        let home = format!("{}", jail.directory().to_string_lossy());
        jail.set_env("HOME", &home);
        jail.create_file(
            "config.yaml",
            r#"
chains:
  - name: "hardhat"
    rpc_url: ""  # Invalid: empty RPC URL
    contracts:
      enclave: "invalid-address"  # Invalid Ethereum address
"#,
        )?;

        let result = load_config(Some("config.yaml"));
        assert!(result.is_err());
        Ok(())
    });
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c5d3ad6 and 15d24c6.

⛔ Files ignored due to path filters (1)
  • packages/ciphernode/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • packages/ciphernode/config/src/app_config.rs (1 hunks)
  • packages/ciphernode/enclave/src/main.rs (2 hunks)
  • packages/ciphernode/evm/Cargo.toml (1 hunks)
  • packages/ciphernode/evm/src/helpers.rs (2 hunks)
  • packages/ciphernode/keyshare/src/keyshare.rs (7 hunks)
  • tests/basic_integration/lib/clean_folders.sh (1 hunks)
🧰 Additional context used
📓 Learnings (1)
tests/basic_integration/lib/clean_folders.sh (1)
Learnt from: ryardley
PR: gnosisguild/enclave#156
File: tests/basic_integration/lib/clean_folders.sh:1-3
Timestamp: 2024-10-28T11:35:41.176Z
Learning: In the file `tests/basic_integration/lib/clean_folders.sh`, the `clean_folders` function does not require argument validation for `SCRIPT_DIR` as per the user's preference.
🪛 Shellcheck
tests/basic_integration/lib/clean_folders.sh

[warning] 3-3: In POSIX sh, 'local' is undefined.

(SC3043)

🔇 Additional comments (14)
packages/ciphernode/evm/Cargo.toml (1)

12-18: LGTM! Dependencies align well with security requirements.

The added dependencies support the PR's encryption and key management objectives:

  • cipher: For implementing AES encryption
  • data: For managing encrypted data persistence
  • zeroize: For secure handling of sensitive data in memory

Let's verify the workspace configuration:

✅ Verification successful

Dependencies are correctly configured in the workspace

The verification confirms that:

  • All dependencies are properly configured in the workspace root (packages/ciphernode/Cargo.toml)
  • zeroize is correctly specified in the workspace dependencies with version "1.6.0"
  • The dependency is consistently used across packages with workspace inheritance
  • Local dependencies (data, cipher, sortition) are correctly referenced using relative paths
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify workspace configuration and dependency versions

# Test 1: Check if these are workspace dependencies
rg -A 10 '^\[workspace\]' Cargo.toml

# Test 2: Verify consistent versions across workspace
rg --type toml 'zeroize.*workspace.*true' 

Length of output: 358


Script:

#!/bin/bash
# Let's check for the workspace configuration in the root Cargo.toml
fd -t f "^Cargo.toml$" -d 1 --exec cat {}

# Also check if there's a workspace configuration in the packages directory
fd -t f "^Cargo.toml$" -d 1 packages/ --exec cat {}

Length of output: 101


Script:

#!/bin/bash
# Let's try a different approach to locate and examine Cargo.toml files
# First, find all Cargo.toml files in the repository
fd -t f "Cargo.toml"

# Then examine the directory structure to understand the workspace layout
ls -R packages/ciphernode/

Length of output: 3947


Script:

#!/bin/bash
# Let's check the root workspace configuration
cat packages/ciphernode/Cargo.toml

# And verify the version specifications for zeroize in cipher package
cat packages/ciphernode/cipher/Cargo.toml | grep -A 5 -B 5 "zeroize"

Length of output: 2066

tests/basic_integration/lib/clean_folders.sh (3)

2-3: LGTM!

The function definition is clean and straightforward.

🧰 Tools
🪛 Shellcheck

[warning] 3-3: In POSIX sh, 'local' is undefined.

(SC3043)


5-6: 🛠️ Refactor suggestion

Improve output artifacts cleanup reliability.

The current cleanup might fail silently if no files match or if the directory doesn't exist.

     # Delete output artifacts
-    rm -rf "$SCRIPT_DIR/output/"*
+    if [ -d "$SCRIPT_DIR/output" ]; then
+        rm -rf "$SCRIPT_DIR/output/"* || echo "Warning: Failed to clean output directory" >&2
+    fi

Likely invalid or redundant comment.


8-12: 🛠️ Refactor suggestion

Consider improving maintainability of preserved files list.

The current implementation works well but could be more maintainable.

     # Delete enclave artifacts
+    # Define preserved files for better maintainability
+    local preserved_files=".*/\(config\.yaml\|\.gitignore\)$"
     for name in cn1 cn2 cn3 cn4 ag; do
         # List all files and directories except config.yaml, then delete them
-        find "$SCRIPT_DIR/lib/$name" -mindepth 1 ! -regex '.*/config\.yaml$' ! -regex '.*/.gitignore$' -exec rm -rf {} +
+        find "$SCRIPT_DIR/lib/$name" -mindepth 1 ! -regex "$preserved_files" -exec rm -rf {} +
     done

Likely invalid or redundant comment.

packages/ciphernode/enclave/src/main.rs (4)

27-37: Well-structured CLI implementation!

The CLI structure effectively implements the required commands for key management while following best practices:

  • Clear documentation
  • Global config option
  • Proper subcommand organization

57-57: Update the actix_rt::main attribute.

As mentioned in the previous review, the actix_rt crate is deprecated. Update to actix::main to ensure future compatibility.


Line range hint 1-69: Consider secure memory handling for sensitive data.

Given that this CLI handles sensitive data like private keys and secrets, consider:

  1. Using secure memory wiping after processing sensitive data
  2. Adding warnings if running with elevated privileges
  3. Implementing proper file permissions for config files
#!/bin/bash
# Check for existing security measures in the codebase
echo "Checking for secure memory handling..."
rg -i "secure|wipe|zeroize"

echo "Checking for permission handling..."
rg -i "chmod|permission|umask"

39-53: 🛠️ Refactor suggestion

Add config path validation.

While the implementation is clean, consider validating the config path before loading it to provide better error messages.

 pub async fn execute(self) -> Result<()> {
     let config_path = self.config.as_deref();
+    
+    if let Some(path) = config_path {
+        if !std::path::Path::new(path).exists() {
+            anyhow::bail!("Config file not found: {}", path);
+        }
+    }
 
     let config = load_config(config_path)?;
packages/ciphernode/keyshare/src/keyshare.rs (3)

4-4: LGTM: Proper integration of cipher functionality

The addition of the Cipher type and its integration into the structs is well-implemented with proper thread-safety considerations using Arc.

Also applies to: 21-21, 33-33, 49-49, 99-99


53-70: LGTM: Secure implementation of secret management

The implementation follows security best practices:

  • Proper encryption/decryption using the cipher
  • Efficient memory handling with no unnecessary copies
  • Clear error messages without leaking sensitive information

134-139: LGTM: Robust error handling in event handlers

The error handling implementation properly propagates errors with appropriate error types while maintaining the security of sensitive data.

packages/ciphernode/evm/src/helpers.rs (2)

13-15: LGTM: Imports are appropriate for secure key management.

The added imports provide the necessary components for secure key handling and encryption operations.

Also applies to: 18-18, 21-21


143-157: ⚠️ Potential issue

Security improvements needed for private key handling.

While the function correctly uses Zeroizing for secure memory handling, there are several security considerations to address:

  1. Add validation for the private key format before parsing
  2. Avoid unnecessary copying of sensitive data with to_vec()
  3. Consider adding logging for security-relevant events

Apply these security improvements:

 pub async fn get_signer_from_repository(
     repository: Repository<Vec<u8>>,
     cipher: &Arc<Cipher>,
 ) -> Result<Arc<PrivateKeySigner>> {
     let Some(private_key_encrypted) = repository.read().await? else {
+        trace!("Attempt to access non-existent private key");
         bail!("No private key was found!")
     };

     let encoded_private_key = Zeroizing::new(cipher.decrypt_data(&private_key_encrypted)?);
 
-    let private_key = Zeroizing::new(String::from_utf8(encoded_private_key.to_vec())?);
+    let private_key = Zeroizing::new(String::from_utf8(encoded_private_key.as_ref().to_vec())?);
+
+    // Validate private key format
+    if !private_key.starts_with("0x") || private_key.len() != 66 {
+        trace!("Invalid private key format detected");
+        bail!("Invalid private key format - must be 0x-prefixed and 32 bytes");
+    }

     let signer = private_key.parse()?;
+    trace!("Successfully loaded private key from repository");
     Ok(Arc::new(signer))
 }

Let's verify the private key format used elsewhere in the codebase:

packages/ciphernode/config/src/app_config.rs (1)

95-97: Clarify the purpose of use_in_mem_store

The method always returns false, which suggests it might be a placeholder or incomplete implementation.

tests/basic_integration/lib/clean_folders.sh Show resolved Hide resolved
tests/basic_integration/lib/clean_folders.sh Outdated Show resolved Hide resolved
packages/ciphernode/keyshare/src/keyshare.rs Show resolved Hide resolved
packages/ciphernode/config/src/app_config.rs Show resolved Hide resolved
packages/ciphernode/config/src/app_config.rs Show resolved Hide resolved
packages/ciphernode/config/src/app_config.rs Show resolved Hide resolved
packages/ciphernode/config/src/app_config.rs Show resolved Hide resolved
packages/ciphernode/config/src/app_config.rs Show resolved Hide resolved
ryardley and others added 2 commits October 29, 2024 10:19
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
packages/ciphernode/enclave/src/main.rs (1)

22-25: Consider memory cleanup after ASCII art display.

Since this is a security-focused application dealing with sensitive data, ensure that any large string constants are properly cleaned up from memory after use.

Apply this diff to implement secure string handling:

 pub fn owo() {
-    println!("\n\n\n\n\n{}", OWO);
-    println!("\n\n\n\n");
+    {
+        let output = format!("\n\n\n\n\n{}\n\n\n\n", OWO);
+        println!("{}", output);
+        // Ensure the formatted string is cleaned up
+        drop(output);
+    }
 }
packages/ciphernode/cipher/src/password_manager.rs (2)

42-47: Enhance error messages for better debugging

The error message "No key found" could be more specific about the context.

Consider:

-        Err(anyhow!("No key found"))
+        Err(anyhow!("No environment key found in EnvPasswordManager"))

154-168: Add documentation for permission constants

The function would benefit from documentation explaining the permission constants and their security implications.

Add documentation:

+/// Ensures file permissions are set correctly for secure key storage.
+/// 
+/// # Arguments
+/// * `path` - Path to the keyfile
+/// * `perms` - Unix permission bits:
+///   - 0o400: Read-only for owner (used for stored keys)
+///   - 0o600: Read-write for owner (used during key operations)
 fn ensure_file_permissions(path: &PathBuf, perms: u32) -> Result<()> {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7c02437 and bede3ed.

📒 Files selected for processing (3)
  • packages/ciphernode/cipher/src/password_manager.rs (1 hunks)
  • packages/ciphernode/enclave/src/commands/password/create.rs (1 hunks)
  • packages/ciphernode/enclave/src/main.rs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ciphernode/enclave/src/commands/password/create.rs
🧰 Additional context used
📓 Learnings (1)
packages/ciphernode/cipher/src/password_manager.rs (3)
Learnt from: ryardley
PR: gnosisguild/enclave#156
File: packages/ciphernode/cipher/src/password_manager.rs:126-131
Timestamp: 2024-10-28T10:50:28.550Z
Learning: In `FilePasswordManager::set_key`, since we need to write to the keyfile, we must open it with write permissions (e.g., `0o600`). Setting permissions to `0o400` at creation time is not feasible because it would prevent writing to the file.
Learnt from: ryardley
PR: gnosisguild/enclave#156
File: packages/ciphernode/cipher/src/password_manager.rs:34-37
Timestamp: 2024-10-28T10:46:32.167Z
Learning: In `EnvPasswordManager::new`, wrapping the environment variable into `Zeroizing` upon retrieval is unnecessary because it is dropped immediately.
Learnt from: ryardley
PR: gnosisguild/enclave#156
File: packages/ciphernode/cipher/src/password_manager.rs:121-123
Timestamp: 2024-10-28T10:49:45.743Z
Learning: In `packages/ciphernode/cipher/src/password_manager.rs`, the `FilePasswordManager` struct includes an overwrite method to allow securely overwriting existing key files when necessary.
🔇 Additional comments (6)
packages/ciphernode/enclave/src/main.rs (3)

57-57: Update the actix_rt::main attribute.

As noted in previous reviews, actix_rt is deprecated. Update to actix::main for future compatibility.


39-53: Review error messages for potential information leakage.

When handling errors in a security-focused application, ensure that error messages don't expose sensitive information like keys, paths, or internal states.

Run the following script to analyze error handling in command modules:

#!/bin/bash
# Search for error handling patterns in command modules
rg "Err\(|Error::new|anyhow::" packages/ciphernode/enclave/src/commands/

31-33: Verify config file permissions on load.

Since the config file may contain sensitive information, ensure that proper file permissions are checked when loading the config file.

Run the following script to check if file permissions are validated:

packages/ciphernode/cipher/src/password_manager.rs (3)

1-17: Well-structured trait definition with appropriate security considerations

The trait definition and imports demonstrate good practices:

  • Using Zeroizing for secure memory handling
  • Async trait for non-blocking operations
  • Comprehensive error handling with anyhow

61-64: Consider avoiding clone() on sensitive data

While Zeroizing handles secure memory cleanup, cloning sensitive data creates additional copies in memory that need to be tracked and cleaned up.

Consider using references or implementing a more secure way to handle the key retrieval:

-        if let Some(key) = self.0.clone() {
+        if let Some(ref key) = self.0 {
-            return Ok(key);
+            return Ok(key.clone());
         }

117-151: 🛠️ Refactor suggestion

Consider checking parent directory permissions

While file permissions are properly handled, the security of the keyfile also depends on the parent directory permissions.

Add directory permission check:

 async fn set_key(&mut self, contents: Zeroizing<Vec<u8>>) -> Result<()> {
     let path = &self.path;
+    
+    // Check parent directory permissions
+    if let Some(parent) = path.parent() {
+        let metadata = fs::metadata(parent)
+            .context("Failed to get parent directory metadata")?;
+        let dir_mode = metadata.permissions().mode() & 0o777;
+        if dir_mode & 0o077 != 0 {
+            bail!("Parent directory has too permissive permissions");
+        }
+    }

packages/ciphernode/enclave/src/main.rs Show resolved Hide resolved
@ryardley ryardley mentioned this pull request Oct 29, 2024
2 tasks
@ryardley ryardley changed the title Encryption and key management Encryption and key management (ready for review) Oct 29, 2024
@ryardley ryardley merged commit d9867ed into main Oct 31, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement key management strategy
2 participants