Skip to content

[Enhancement] Encrypt delegate passphrases with operator password #247

Description

@al-onyxprotocol

Summary

Delegate passphrases are currently stored in plain text in the node config file. This issue tracks adding support for operator-password-encrypted passphrases so that a compromised config file does not expose forging keys.

Motivation

A node operator may run on a shared or remotely managed host. If the config file is leaked (backup, misconfigured permissions, supply-chain tooling), all delegate passphrases are immediately exposed. Encrypting them at rest significantly raises the bar for credential theft while keeping the operational flow simple: one password unlocks all delegates on startup.

Detailed description

Proposed behavior

  • The operator encrypts each delegate passphrase with a single operator-chosen password before writing it to the config.
  • On node startup, the node detects that a passphrase is encrypted and prompts the operator for the password (interactive) or reads it from a designated environment variable / startup flag (non-interactive / service mode).
  • The password is kept in process memory only for the duration of the decryption step and is never written to disk, logs, or any storage.
  • If the node is restarted, the password must be supplied again.
  • When multiple delegate passphrases are present in the config (multi-delegate host), all of them are encrypted with the same single password, so the operator only enters it once per startup.
  • Backward compatibility: until a separate deprecation notice is issued, the node continues to accept plain-text passphrases in the config without any migration requirement.

Encryption design sketch

  • Use a well-established symmetric encryption scheme (e.g., AES-256-GCM) with a key derived from the operator password via a memory-hard KDF (e.g., scrypt or Argon2id).
  • Store the encrypted value as a self-describing string in the config (e.g., a prefixed base64 blob that includes the algorithm identifier, KDF parameters, salt, IV, and ciphertext), so the node can distinguish an encrypted passphrase from a plain-text one reliably.
  • The plain/encrypted detection must be deterministic and not rely on heuristics (length, character set, etc.).

Operator workflow

  1. Run an included CLI helper (or npm run script) to encrypt a passphrase interactively and receive the encrypted string.
  2. Replace the plain-text passphrase in config.json with the encrypted string.
  3. Start (or restart) the node; it detects the encrypted format and prompts for the password.

Security constraints

  • Never log the password, the decrypted passphrase, or any intermediate key material.
  • Protect against trivial brute-force by choosing adequate KDF parameters.
  • Follow the existing security rules: no weakening of signature verification, no new unvalidated inputs.

Alternatives

  • Vault / secrets manager integration: more powerful but adds a hard external dependency and complexity for small independent operators — at odds with the project's lightweight-node goal.
  • OS-level keychain / credential store: platform-specific; complicates headless and Docker deployments.
  • Environment variable only (no encryption): still leaves the secret exposed in process tables and shell history; plain env var does not solve the at-rest config leak.

Proposed technical implementation

  • Add a CLI helper (e.g., tools/encrypt-passphrase.js) that takes a plain passphrase, prompts for the operator password, and outputs the encrypted config value.
  • Update helpers/config.js (and/or the startup sequence in app.js) to detect encrypted passphrases and perform decryption before the passphrase is handed to delegate / forging logic.
  • Add a schema entry or convention for the encrypted format string in schema/ and align with adamant-schema if the config shape is externally documented.
  • Update README.md and node documentation (Adamant-im/docs) with operator instructions for migration and startup.
  • Add unit tests for the encrypt/decrypt helper and for the config-loading path (both plain and encrypted inputs).

Metadata

Metadata

Assignees

No one assigned

    Labels

    NodeJSBackend logic, APIs, and Node.js environmentNodesADM node software issues, APIs, connectivity, consensusSecurityTopics about security approaches, cryptography, authentication, or vulnerabilitiesenhancementNew feature or request

    Projects

    Status
    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions