Skip to content

Harden Sodium native interop and reduce per-call cryptographic overhead #44

@MariusStorhaug

Description

The Sodium module is used to encrypt and decrypt secrets in automation workflows where reliability and defensive behavior are required. These workflows often run repeatedly in CI environments, so small per-call costs and weak input boundaries become significant over time.

Request

Current experience

Native interop calls accept input buffers without a consistent managed guard layer, key and ciphertext validation is distributed across commands, and cryptographic constants are repeatedly queried per command invocation. Sensitive intermediate byte arrays can also remain in memory longer than necessary after operation completion.

Desired experience

Native interop boundaries should fail fast on invalid buffer shapes, command paths should initialize Sodium once and reuse fixed-size constants for subsequent calls, and sensitive transient buffers should be cleared after use. Platform/runtime selection should be deterministic and based on process architecture, with clear support validation on Windows runtimes.

User impact

Without these improvements, malformed input can surface as low-level failures instead of clear command errors, repeated invocations pay avoidable overhead, and secret-related buffers can persist in managed memory longer than required.

Acceptance criteria

  • Native interop methods validate buffer lengths before unmanaged calls and return deterministic argument errors for invalid input shapes.
  • Sodium initialization and static size constants are cached once per module session and reused by public commands.
  • ConvertFrom-SodiumSealedBox rejects ciphertext shorter than crypto_box_sealbytes with a clear validation error.
  • Get-SodiumPublicKey validates private key byte length before key derivation and emits a clear error on mismatch.
  • Transient secret/plaintext/private-key byte arrays are cleared after use in public crypto commands.
  • Runtime selection uses process architecture consistently across Windows, Linux, and macOS, with Windows runtime prerequisite checks aligned to process architecture.
  • Regression tests cover wrong-length private keys and too-short sealed-box payloads.

References


Technical decisions

Interop boundary hardening: Wrap native DllImport calls with managed validation methods to enforce minimum and exact buffer sizes before entering unmanaged code.

DLL search safety: Use constrained native library search paths at import boundaries to reduce unintended library resolution behavior.

Initialization strategy: Add a private Initialize-Sodium function that initializes Sodium once and caches crypto_box_publickeybytes, crypto_box_secretkeybytes, and crypto_box_sealbytes in script scope.

Memory hygiene: Clear sensitive transient buffers (private key, seed, derived seed, plaintext) in finally blocks after operation completion.

Runtime selection: Resolve runtime identifier from process architecture (RuntimeInformation.ProcessArchitecture) rather than external shell probing.

Windows support detection: Validate Visual C++ runtime for the active process architecture and require Installed != 0 plus minimum version compliance.

Build robustness: Update local build orchestration to fail fast when publish fails for a runtime target to avoid cascading copy-stage errors.

Test strategy: Extend Pester with explicit negative-path assertions for short sealed box inputs and wrong-length private keys.


Implementation plan

Native bridge

  • Add a managed validation layer in the C# Sodium bridge for exact/minimum buffer checks before each native crypto call.
  • Constrain native DLL import search paths for libsodium.

PowerShell module behavior

  • Add module-scoped initialization state and cached Sodium size constants.
  • Introduce private Initialize-Sodium helper and adopt it in public functions.
  • Update public crypto functions to validate key and ciphertext lengths using cached constants.
  • Clear sensitive byte arrays in finally blocks where applicable.
  • Standardize runtime selection by process architecture in module startup.
  • Align Windows VC runtime check to selected process architecture.

Build and test

  • Make local publish/build script fail fast on runtime-specific publish errors.
  • Add Pester tests for short sealed-box payload rejection.
  • Add Pester tests for invalid private-key byte length rejection.
  • Run full Sodium test suite and confirm no behavior regressions for valid encryption/decryption paths.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions