Sodium.psm1

$baseName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$script:PSModuleInfo = Test-ModuleManifest -Path "$PSScriptRoot\$baseName.psd1"
$script:PSModuleInfo | Format-List | Out-String -Stream | ForEach-Object { Write-Debug $_ }
$scriptName = $script:PSModuleInfo.Name
Write-Debug "[$scriptName] - Importing module"
#region [functions] - [public]
Write-Debug "[$scriptName] - [functions] - [public] - Processing folder"
#region [functions] - [public] - [ConvertFrom-SodiumEncryptedString]
Write-Debug "[$scriptName] - [functions] - [public] - [ConvertFrom-SodiumEncryptedString] - Importing"
function ConvertFrom-SodiumEncryptedString {
    <#
        .SYNOPSIS
        Decrypts a base64-encoded, Sodium-encrypted string.

        .DESCRIPTION
        Converts a base64-encoded, Sodium-encrypted string into its original plaintext form.
        Uses the provided public and private keys to decrypt the sealed message.

        .EXAMPLE
        $params = @{
            EncryptedSecret = $encryptedSecret
            PublicKey = $publicKey
            PrivateKey = $privateKey
        }
        ConvertFrom-SodiumEncryptedString @params

        Decrypts the given encrypted secret using the specified public and private keys and returns the original string.

        .NOTES
        Uses the Sodium library for encryption and decryption.
        Ensure the provided keys are correctly formatted in base64.
    #>

    [OutputType([string])]
    [CmdletBinding()]
    param(
        # The base64-encoded encrypted secret string to decrypt.
        [Parameter(Mandatory)]
        [string] $EncryptedSecret,

        # The base64-encoded public key used for decryption.
        [Parameter(Mandatory)]
        [string] $PublicKey,

        # The base64-encoded private key used for decryption.
        [Parameter(Mandatory)]
        [string] $PrivateKey
    )

    try {
        # Convert from base64 to raw bytes
        $sealedBoxBytes = [System.Convert]::FromBase64String($EncryptedSecret)
        $publicKeyBytes = [System.Convert]::FromBase64String($PublicKey)
        $privateKeyBytes = [System.Convert]::FromBase64String($PrivateKey)

        # Decrypt using the SealedPublicKeyBox class from Sodium
        $decryptedBytes = [Sodium.SealedPublicKeyBox]::Open(
            $sealedBoxBytes,
            $privateKeyBytes,
            $publicKeyBytes
        )

        # Convert decrypted bytes back to a string
        $decryptedString = [System.Text.Encoding]::UTF8.GetString($decryptedBytes)

        return $decryptedString
    } catch {
        Write-Error "Failed to decrypt the sealed message."
        throw $_
    }
}
Write-Debug "[$scriptName] - [functions] - [public] - [ConvertFrom-SodiumEncryptedString] - Done"
#endregion [functions] - [public] - [ConvertFrom-SodiumEncryptedString]
#region [functions] - [public] - [ConvertTo-SodiumEncryptedString]
Write-Debug "[$scriptName] - [functions] - [public] - [ConvertTo-SodiumEncryptedString] - Importing"
function ConvertTo-SodiumEncryptedString {
    <#
        .SYNOPSIS
        Encrypts a secret using a sealed public key box.

        .DESCRIPTION
        This function encrypts a given secret using a public key with the SealedPublicKeyBox method from the Sodium library.
        The result is a base64-encoded sealed box that can only be decrypted by the corresponding private key.

        .EXAMPLE
        ConvertTo-SodiumEncryptedString -Secret "mysecret" -PublicKey "BASE64_PUBLIC_KEY"

        Encrypts the secret "mysecret" using the provided base64-encoded public key and returns a base64-encoded sealed box.
    #>

    [OutputType([string])]
    [CmdletBinding()]
    param(
        # The secret string to be encrypted.
        [Parameter(Mandatory)]
        [string] $Secret,

        # The base64-encoded public key used for encryption.
        [Parameter(Mandatory)]
        [string] $PublicKey
    )

    [System.Convert]::ToBase64String(
        [Sodium.SealedPublicKeyBox]::Create(
            [System.Text.Encoding]::UTF8.GetBytes($Secret),
            [System.Convert]::FromBase64String($PublicKey)
        )
    )
}
Write-Debug "[$scriptName] - [functions] - [public] - [ConvertTo-SodiumEncryptedString] - Done"
#endregion [functions] - [public] - [ConvertTo-SodiumEncryptedString]
#region [functions] - [public] - [New-SodiumKeyPair]
Write-Debug "[$scriptName] - [functions] - [public] - [New-SodiumKeyPair] - Importing"
function New-SodiumKeyPair {
    <#
        .SYNOPSIS
        Generates a new Sodium key pair.

        .DESCRIPTION
        This function creates a new cryptographic key pair using Sodium's PublicKeyBox.
        The keys are returned as a PowerShell custom object, with both the public and private keys
        encoded in base64 format.

        .EXAMPLE
        New-SodiumKeyPair

        Generates a new key pair and returns a custom object containing the base64-encoded
        public and private keys.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSUseShouldProcessForStateChangingFunctions', '',
        Scope = 'Function',
        Justification = 'Does not change state'
    )]
    [OutputType([pscustomobject])]
    [CmdletBinding()]
    param()

    $keyPair = [Sodium.PublicKeyBox]::GenerateKeyPair()
    [pscustomobject]@{
        PublicKey  = [System.Convert]::ToBase64String($keyPair.PublicKey)
        PrivateKey = [System.Convert]::ToBase64String($keyPair.PrivateKey)
    }
}
Write-Debug "[$scriptName] - [functions] - [public] - [New-SodiumKeyPair] - Done"
#endregion [functions] - [public] - [New-SodiumKeyPair]
Write-Debug "[$scriptName] - [functions] - [public] - Done"
#endregion [functions] - [public]

#region Member exporter
$exports = @{
    Alias    = '*'
    Cmdlet   = ''
    Function = @(
        'ConvertFrom-SodiumEncryptedString'
        'ConvertTo-SodiumEncryptedString'
        'New-SodiumKeyPair'
    )
}
Export-ModuleMember @exports
#endregion Member exporter