Skip to content

🩹 [Patch]: Secret crypto operations now fail fast on invalid input with lower per-call overhead - #45

Merged
Marius Storhaug (MariusStorhaug) merged 22 commits into
mainfrom
fix/44-harden-sodium-interop
May 17, 2026
Merged

🩹 [Patch]: Secret crypto operations now fail fast on invalid input with lower per-call overhead#45
Marius Storhaug (MariusStorhaug) merged 22 commits into
mainfrom
fix/44-harden-sodium-interop

Conversation

@MariusStorhaug

@MariusStorhaugMarius Storhaug (MariusStorhaug) commented May 14, 2026

Copy link
Copy Markdown
Member

Secret encryption and decryption operations in Sodium now validate malformed inputs earlier, return clearer errors for invalid key and payload shapes, and run substantially faster on repeated invocations thanks to a series of targeted performance improvements across the interop layer.

Fixed: Invalid key and sealed payload shapes now fail fast with clear errors

\Get-SodiumPublicKey\ now rejects wrong-length private keys before key derivation, and \ConvertFrom-SodiumSealedBox\ now rejects sealed payloads shorter than the required Sodium overhead. This prevents low-level failures and returns actionable validation messages earlier in the command flow.

Example: \Get-SodiumPublicKey\ rejects a 16-byte private key with 'Invalid private key. Expected 32 bytes but got 16.' Similarly, \ConvertFrom-SodiumSealedBox\ rejects sealed boxes shorter than 48 bytes (the crypto_box_seal overhead).

Changed: Repeated crypto calls now incur significantly less overhead

Seven performance issues were addressed incrementally. Each was benchmarked in isolation against the previous prerelease. All measurements in median µs per 1,000-iteration trial on Windows x64.

ScenarioBaselineFinalΔ
New-SodiumKeyPair73.6 µs49.1 µs↓33%
New-SodiumKeyPair -Seed94.9 µs48.8 µs↓49%
Get-SodiumPublicKey66.1 µs46.7 µs↓29%
ConvertTo-SodiumSealedBox135.8 µs105.4 µs↓22%
ConvertFrom-SodiumSealedBox196.3 µs109.0 µs↓44%
Cold start (import + one key pair)287 ms279 ms↓3%

Largest contributors: Base64 conversions moved to C# (↓17 to ↓42%), inlining crypto_scalarmult_base in sealed-box open (↓24%), and initializing libsodium at module import (↓6 to ↓14%).

Changed: Runtime loading behavior is now more deterministic across platforms

Runtime selection resolves from process architecture across Windows, Linux, and macOS; Windows support validation aligns with the active process architecture for more predictable module startup on mixed-architecture systems.

Implementation

  • Added managed validation wrappers in PSModule/Sodium/Sodium.cs with buffer size checks before unmanaged execution.
  • Migrated all DllImport bindings to LibraryImport source generators for compile-time marshalling.
  • Added base64-centric C# helpers (SealBase64, OpenSealBase64, DerivePublicKeyBase64, GenerateKeyPairBase64).
  • Cached crypto_box size constants as static readonly fields; fixed seed validation to use SeedBytes instead of SecretKeyBytes.
  • Added Initialize-Sodium at module load to call sodium_init once.
  • Unwrap MethodInvocationException to surface raw error messages to callers.
  • Updated Assert-VisualCRedistributableInstalled to validate architecture-specific runtime.
  • Updated PSModule/build.ps1 to fail fast on per-runtime publish failures.
  • Added regression coverage for short sealed-box payloads and wrong-length private keys.
  • Built and tested against .NET 8.0 LTS with System.Management.Automation 7.4.7 for broad compatibility.

@MariusStorhaugMarius Storhaug (MariusStorhaug) changed the title Draft: Sodium hardening for issue #44🩹 [Patch]: Secret crypto operations now fail fast on invalid input with lower per-call overheadMay 14, 2026
@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLFail ❌
TRIVYPass ✅
YAMLPass ✅

Super-linter detected linting errors

For more information, see the GitHub Actions workflow run

Powered by Super-linter

SPELL_CODESPELL
/github/workspace/PSModule/Sodium/Sodium.cs:28: clen ==> clean, clan
/github/workspace/PSModule/Sodium/Sodium.cs:78: clen ==> clean, clan
/github/workspace/PSModule/Sodium/Sodium.cs:81: clen ==> clean, clan
/github/workspace/PSModule/Sodium/Sodium.cs:86: clen ==> clean, clan
/github/workspace/PSModule/Sodium/Sodium.cs:87: clen ==> clean, clan
/github/workspace/PSModule/Sodium/Sodium.cs:91: clen ==> clean, clan

@MariusStorhaug
Marius Storhaug (MariusStorhaug) marked this pull request as ready for review May 15, 2026 20:20
CopilotAI review requested due to automatic review settings May 15, 2026 20:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the Sodium PowerShell module by adding a managed validation layer in the C# interop bridge, centralizing module initialization with cached constants, validating input shapes earlier in public commands, clearing sensitive buffers in finally blocks, and making runtime selection deterministic by process architecture.

Changes:

  • Added validated wrappers around all native libsodium P/Invoke calls and constrained DLL search paths in PSModule/Sodium/Sodium.cs.
  • Introduced Initialize-Sodium with module-scoped cached size constants and refactored public crypto commands to use them, plus added explicit length validation and finally-block buffer clearing.
  • Switched platform/runtime selection to RuntimeInformation.ProcessArchitecture and aligned the Visual C++ Redistributable check to the active architecture; made build.ps1 fail fast on publish errors.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
PSModule/Sodium/Sodium.csWraps native imports in a Native inner class with buffer length validation and constrained DLL search paths.
PSModule/build.ps1Sets $ErrorActionPreference = 'Stop', builds with -c Release, checks $LASTEXITCODE, and ensures Pop-Location in finally.
src/main.ps1Resolves runtime identifier from ProcessArchitecture for Linux/macOS/Windows and centralizes module import.
src/functions/private/Assert-VisualCRedistributableInstalled.ps1Adds Architecture parameter, validates Installed != 0, and uses -ErrorAction SilentlyContinue.
src/functions/private/Initialize-Sodium.ps1New helper that initializes Sodium once and caches public/private/seal byte sizes.
src/variables/private/Initialized.ps1Declares module-scoped Sodium state and size variables.
src/functions/public/New-SodiumKeyPair.ps1Uses cached sizes, disposes SHA256, clears sensitive buffers in finally.
src/functions/public/Get-SodiumPublicKey.ps1Removes duplicate [CmdletBinding()], validates private-key length, clears the key buffer.
src/functions/public/ConvertTo-SodiumSealedBox.ps1Uses cached sizes, validates public key length, clears plaintext in finally.
src/functions/public/ConvertFrom-SodiumSealedBox.ps1Validates short sealed boxes and key lengths with explicit messages; clears sensitive buffers in finally.
tests/Sodium.Tests.ps1Adds regression tests for short sealed box and wrong-length private key.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

@github-actions

Copy link
Copy Markdown

✅ New prerelease: PowerShell Gallery - Sodium 2.2.3-fix44hardensodiuminterop001

@github-actions

Copy link
Copy Markdown

✅ New prerelease: GitHub - Sodium v2.2.3-fix44hardensodiuminterop001

Replaces disposable SHA256 instance with the static SHA256.HashData API in the seeded keypair path. Reduces per-call allocations.
CopilotAI review requested due to automatic review settings May 17, 2026 10:43
@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment threadPSModule/Sodium/Sodium.cs Outdated
@github-actions

Copy link
Copy Markdown

✅ New prerelease: PowerShell Gallery - Sodium 2.2.3-fix44hardensodiuminterop002

@github-actions

Copy link
Copy Markdown

✅ New prerelease: GitHub - Sodium v2.2.3-fix44hardensodiuminterop002

Skips the registry probe during module import; only runs it as a diagnostic if native sodium_init() throws on Windows. Reduces cold-start overhead.
@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

…ge after lazy probe
Adds InModuleScope tests for the private VC++ runtime probe so the deferred-init refactor (#54) does not regress code coverage.
CopilotAI review requested due to automatic review settings May 17, 2026 10:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment threadPSModule/Sodium/Sodium.cs Outdated
Comment threadsrc/functions/private/Initialize-Sodium.ps1 Outdated
CopilotAI review requested due to automatic review settings May 17, 2026 12:43
@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.

Comment threadsrc/functions/private/Initialize-Sodium.ps1
@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLFail ❌
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

Super-linter detected linting errors

For more information, see the GitHub Actions workflow run

Powered by Super-linter

POWERSHELL

�[32;1mRuleName �[0m�[32;1m Severity �[0m�[32;1m ScriptName�[0m�[32;1m Line �[0m�[32;1m Message�[0m
�[32;1m-------- �[0m �[32;1m-------- �[0m �[32;1m----------�[0m �[32;1m---- �[0m �[32;1m-------�[0m
PSAvoidLongLines Warning Initialize 30 Line exceeds
-Sodium.ps the configure
1 d maximum len
gth of 150 ch
aracters

@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLFail ❌
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

Super-linter detected linting errors

For more information, see the GitHub Actions workflow run

Powered by Super-linter

POWERSHELL

�[32;1mRuleName �[0m�[32;1m Severity �[0m�[32;1m ScriptName�[0m�[32;1m Line �[0m�[32;1m Message�[0m
�[32;1m-------- �[0m �[32;1m-------- �[0m �[32;1m----------�[0m �[32;1m---- �[0m �[32;1m-------�[0m
PSUseConsistentIndentation Warning Initialize 31 Indentation n
-Sodium.ps ot consistent
1

CopilotAI review requested due to automatic review settings May 17, 2026 13:55

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

@github-actions

Copy link
Copy Markdown

Super-linter summary

LanguageValidation result
CHECKOVPass ✅
CSHARPPass ✅
GITHUB_ACTIONSPass ✅
GITLEAKSPass ✅
GIT_MERGE_CONFLICT_MARKERSPass ✅
MARKDOWNPass ✅
NATURAL_LANGUAGEPass ✅
POWERSHELLPass ✅
PRE_COMMITPass ✅
SPELL_CODESPELLPass ✅
TRIVYPass ✅
YAMLPass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

@github-actions

Copy link
Copy Markdown

✅ New prerelease: PowerShell Gallery - Sodium 2.2.3-fix44hardensodiuminterop013

@github-actions

Copy link
Copy Markdown

✅ New prerelease: GitHub - Sodium v2.2.3-fix44hardensodiuminterop013

@MariusStorhaug
Marius Storhaug (MariusStorhaug) merged commit 44fed7f into mainMay 17, 2026
45 checks passed
@MariusStorhaug
Marius Storhaug (MariusStorhaug) deleted the fix/44-harden-sodium-interop branch May 17, 2026 14:09
@github-actions

Copy link
Copy Markdown

✅ New release: PowerShell Gallery - Sodium 2.2.3

@github-actions

Copy link
Copy Markdown

✅ New release: GitHub - Sodium v2.2.3

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment