Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/Process-PSModule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ permissions:

jobs:
Process-PSModule:
uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@da180bac16b13bfbcdf08b2e4e221b5b49e5ff28 # v6.1.4
uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@fb1bdb8fefd243292f779d2a856a38db6fe6daf4 # v6.1.13
secrets: inherit
7 changes: 6 additions & 1 deletion PSModule/Sodium/Sodium.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ public static KeyPairBase64 GenerateKeyPairBase64(string seedText)
}

public static string DerivePublicKeyBase64(string privateKeyBase64)
{
return Convert.ToBase64String(DerivePublicKey(privateKeyBase64));
}

public static byte[] DerivePublicKey(string privateKeyBase64)
{
ArgumentNullException.ThrowIfNull(privateKeyBase64);
var privateKey = DecodeBase64Exact(privateKeyBase64, SecretKeyBytes, "private key");
Expand All @@ -213,7 +218,7 @@ public static string DerivePublicKeyBase64(string privateKeyBase64)
{
throw new InvalidOperationException("Unable to derive public key from private key.");
}
return Convert.ToBase64String(publicKey);
return publicKey;
}
finally
{
Expand Down
28 changes: 28 additions & 0 deletions src/functions/private/Assert-SodiumNativeRuntime.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function Assert-SodiumNativeRuntime {
<#
.SYNOPSIS
Provides platform-specific diagnostics after Sodium native initialization fails.

.DESCRIPTION
Checks the Windows Visual C++ runtime after a native initialization exception and throws a targeted message when the required
runtime is unavailable.

.NOTES
This function only runs after native library loading fails, which cannot be reproduced safely after the library is loaded in the test process.
#>
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
[OutputType([void])]
[CmdletBinding()]
param()

process {
if ($IsWindows -and $script:ProcessArchitecture -in @('X64', 'X86')) {
$hasRuntime = Assert-VisualCRedistributableInstalled -Version '14.0' -Architecture $script:ProcessArchitecture
if (-not $hasRuntime) {
$message = "Sodium native initialization failed; the Visual C++ Redistributable for " +
"$($script:ProcessArchitecture) appears to be missing or below the required version."
throw $message
}
}
}
}
21 changes: 7 additions & 14 deletions src/functions/private/Initialize-Sodium.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,19 @@
$initializationResult = [PSModule.Sodium]::sodium_init()
} catch {
$script:Supported = $false
if ($IsWindows) {
if ($script:ProcessArchitecture -in @('X64', 'X86')) {
$hasRuntime = Assert-VisualCRedistributableInstalled -Version '14.0' -Architecture $script:ProcessArchitecture
if (-not $hasRuntime) {
$message = "Sodium native initialization failed; the Visual C++ Redistributable for " +
"$($script:ProcessArchitecture) appears to be missing or below the required version."
throw $message
}
}
}
Assert-SodiumNativeRuntime
throw
}
if ($initializationResult -lt 0) {
throw 'Sodium initialization failed.'
}

$script:SodiumPublicKeyBytes = [PSModule.Sodium]::crypto_box_publickeybytes().ToUInt32()
$script:SodiumPrivateKeyBytes = [PSModule.Sodium]::crypto_box_secretkeybytes().ToUInt32()
$script:SodiumSealBytes = [PSModule.Sodium]::crypto_box_sealbytes().ToUInt32()
$script:SodiumSeedBytes = [PSModule.Sodium]::crypto_box_seedbytes().ToUInt32()
# Fixed crypto_box constants (curve25519xsalsa20poly1305). The C# layer queries and validates the real
# native values at type initialization; hardcoding here avoids four extra interop call sites at import.
$script:SodiumPublicKeyBytes = 32u
$script:SodiumPrivateKeyBytes = 32u
$script:SodiumSealBytes = 48u
$script:SodiumSeedBytes = 32u
$script:SodiumInitialized = $true
}

Expand Down
65 changes: 65 additions & 0 deletions src/functions/private/Resolve-SodiumRuntimeIdentifier.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
function Resolve-SodiumRuntimeIdentifier {
<#
.SYNOPSIS
Resolves the native Sodium runtime identifier.

.DESCRIPTION
Maps the active operating system and process architecture to the runtime identifier used by the bundled native library.
#>
[OutputType([string])]
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[System.Runtime.InteropServices.Architecture] $ProcessArchitecture,

[Parameter()]
[switch] $Linux,

[Parameter()]
[switch] $MacOS,

[Parameter()]
[switch] $Windows
)

process {
switch ($true) {
$Linux {
switch ($ProcessArchitecture) {
'Arm64' { return 'linux-arm64' }
'X64' { return 'linux-x64' }
default {
$message = "Unsupported Linux process architecture: $ProcessArchitecture. " +
'Please refer to the documentation for supported architectures.'
throw $message
}
}
}
$MacOS {
switch ($ProcessArchitecture) {
'Arm64' { return 'osx-arm64' }
'X64' { return 'osx-x64' }
default {
$message = "Unsupported macOS process architecture: $ProcessArchitecture. " +
'Please refer to the documentation for supported architectures.'
throw $message
}
}
}
$Windows {
switch ($ProcessArchitecture) {
'X64' { return 'win-x64' }
'X86' { return 'win-x86' }
default {
$message = "Unsupported Windows process architecture: $ProcessArchitecture. " +
'Please refer to the documentation for supported architectures.'
throw $message
}
}
}
default {
throw 'Unsupported platform. Please refer to the documentation for more information.'
}
}
}
}
4 changes: 0 additions & 4 deletions src/functions/public/ConvertFrom-SodiumSealedBox.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@
[string] $PrivateKey
)

begin {
Initialize-Sodium
}

process {
try {
if (-not [string]::IsNullOrWhiteSpace($PublicKey)) {
Expand Down
4 changes: 0 additions & 4 deletions src/functions/public/ConvertTo-SodiumSealedBox.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@
[ValidateNotNullOrEmpty()]
[string] $PublicKey
)
begin {
Initialize-Sodium
}

process {
try {
return [PSModule.Sodium]::SealBase64($Message, $PublicKey)
Expand Down
11 changes: 5 additions & 6 deletions src/functions/public/Get-SodiumPublicKey.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
https://psmodule.io/Sodium/Functions/Get-SodiumPublicKey/
#>

[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseOutputTypeCorrectly', '',
Justification = 'The unary comma preserves the byte array as one pipeline object.'
)]
[OutputType([string], ParameterSetName = 'Base64')]
[OutputType([byte[]], ParameterSetName = 'AsByteArray')]
[CmdletBinding(DefaultParameterSetName = 'Base64')]
Expand All @@ -81,14 +85,10 @@
[switch] $AsByteArray
)

begin {
Initialize-Sodium
}

process {
if ($AsByteArray) {
try {
return [System.Convert]::FromBase64String([PSModule.Sodium]::DerivePublicKeyBase64($PrivateKey))
return , ([PSModule.Sodium]::DerivePublicKey($PrivateKey))
} catch [System.Management.Automation.MethodInvocationException] {
throw $_.Exception.InnerException
}
Expand All @@ -100,5 +100,4 @@
}
}

end {}
}
4 changes: 0 additions & 4 deletions src/functions/public/New-SodiumKeyPair.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,6 @@
[string] $Seed
)

begin {
Initialize-Sodium
}

process {
try {
if ($PSCmdlet.ParameterSetName -eq 'SeededKeyPair') {
Expand Down
36 changes: 3 additions & 33 deletions src/main.ps1
Original file line number Diff line number Diff line change
@@ -1,39 +1,9 @@
$processArchitecture = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture

switch ($true) {
$IsLinux {
switch ($processArchitecture) {
'Arm64' { $runtimeIdentifier = 'linux-arm64' }
'X64' { $runtimeIdentifier = 'linux-x64' }
default {
throw "Unsupported Linux process architecture: $processArchitecture. Please refer to the documentation for supported architectures."
}
}
}
$IsMacOS {
switch ($processArchitecture) {
'Arm64' { $runtimeIdentifier = 'osx-arm64' }
'X64' { $runtimeIdentifier = 'osx-x64' }
default {
throw "Unsupported macOS process architecture: $processArchitecture. Please refer to the documentation for supported architectures."
}
}
}
$IsWindows {
switch ($processArchitecture) {
'X64' { $runtimeIdentifier = 'win-x64' }
'X86' { $runtimeIdentifier = 'win-x86' }
default {
throw "Unsupported Windows process architecture: $processArchitecture. Please refer to the documentation for supported architectures."
}
}
}
default {
throw 'Unsupported platform. Please refer to the documentation for more information.'
}
}
$runtimeIdentifier = Resolve-SodiumRuntimeIdentifier -ProcessArchitecture $processArchitecture `
-Linux:$IsLinux -MacOS:$IsMacOS -Windows:$IsWindows

$assemblyPath = Join-Path -Path $PSScriptRoot -ChildPath "libs/$runtimeIdentifier/PSModule.Sodium.dll"
$assemblyPath = [System.IO.Path]::Combine($PSScriptRoot, 'libs', $runtimeIdentifier, 'PSModule.Sodium.dll')
Import-Module $assemblyPath -ErrorAction Stop

# Optimistically mark supported; Initialize-Sodium runs during module import and checks Windows VC++ runtime only if native init fails.
Expand Down
Loading
Loading