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@fb1bdb8fefd243292f779d2a856a38db6fe6daf4 # v6.1.13
uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@1653be8d36607d9535f600278c44789979477813 # v6.1.16
secrets: inherit
108 changes: 108 additions & 0 deletions tests/Sodium.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' }

Describe 'Sodium' {
BeforeAll {
$script:ModuleName = 'Sodium'
if (-not (Get-Module -Name $script:ModuleName -ErrorAction SilentlyContinue)) {
$srcRoot = Split-Path -Path $PSScriptRoot -Parent
$manifestPath = Join-Path -Path $srcRoot -ChildPath 'src\Sodium.psd1'
if (Test-Path -Path $manifestPath) {
Import-Module -Name $manifestPath -Force -ErrorAction Stop
} else {
throw "Module '$script:ModuleName' is not loaded and no source manifest was found at '$manifestPath'. Build the module first."
}
}
}

Context 'SealedBox - Encryption and Decryption' {
It 'Encrypts and decrypts a message correctly using valid keys' {
$keyPair = New-SodiumKeyPair
Expand Down Expand Up @@ -49,6 +62,71 @@ Describe 'Sodium' {
Should -Throw 'Invalid sealed box. Expected at least 48 bytes but got 16.'
}

It 'Rejects an empty message because the parameter is mandatory' {
$keyPair = New-SodiumKeyPair

{ ConvertTo-SodiumSealedBox -Message '' -PublicKey $keyPair.PublicKey } | Should -Throw
}

It 'Encrypts and decrypts a message containing Unicode and special characters' {
$keyPair = New-SodiumKeyPair
$message = 'Hello 🌍! Æøå 日本語 <script>alert(1)</script>'

$encryptedMessage = ConvertTo-SodiumSealedBox -Message $message -PublicKey $keyPair.PublicKey
$decryptedString = ConvertFrom-SodiumSealedBox -SealedBox $encryptedMessage -PublicKey $keyPair.PublicKey -PrivateKey $keyPair.PrivateKey

$decryptedString | Should -BeExactly $message
}

It 'Produces a different sealed box each time the same message is encrypted' {
$keyPair = New-SodiumKeyPair
$message = 'Deterministic input should not yield deterministic output'

$encrypted1 = ConvertTo-SodiumSealedBox -Message $message -PublicKey $keyPair.PublicKey
$encrypted2 = ConvertTo-SodiumSealedBox -Message $message -PublicKey $keyPair.PublicKey

$encrypted1 | Should -Not -Be $encrypted2
}

It 'Fails decryption when the public key does not match the private key' {
$keyPair1 = New-SodiumKeyPair
$keyPair2 = New-SodiumKeyPair
$message = 'Mismatched public key test'

$encryptedMessage = ConvertTo-SodiumSealedBox -Message $message -PublicKey $keyPair1.PublicKey

{ ConvertFrom-SodiumSealedBox -SealedBox $encryptedMessage -PublicKey $keyPair2.PublicKey -PrivateKey $keyPair1.PrivateKey } |
Should -Throw 'Decryption failed.'
}

It 'Rejects encryption with a public key that is valid base64 but the wrong length' {
$message = 'Wrong length public key'
$shortPublicKey = [Convert]::ToBase64String([byte[]]::new(16))

{ ConvertTo-SodiumSealedBox -Message $message -PublicKey $shortPublicKey } |
Should -Throw 'Invalid public key. Expected 32 bytes but got 16.'
}

It 'Rejects decryption with a private key that is valid base64 but the wrong length' {
$keyPair = New-SodiumKeyPair
$message = 'Wrong length private key'
$encryptedMessage = ConvertTo-SodiumSealedBox -Message $message -PublicKey $keyPair.PublicKey
$shortPrivateKey = [Convert]::ToBase64String([byte[]]::new(16))

{ ConvertFrom-SodiumSealedBox -SealedBox $encryptedMessage -PrivateKey $shortPrivateKey } |
Should -Throw 'Invalid private key. Expected 32 bytes but got 16.'
}

It 'Requires a non-null message parameter' {
$keyPair = New-SodiumKeyPair

{ ConvertTo-SodiumSealedBox -Message $null -PublicKey $keyPair.PublicKey } | Should -Throw
}

It 'Requires a non-empty public key parameter' {
{ ConvertTo-SodiumSealedBox -Message 'test' -PublicKey '' } | Should -Throw
}

It 'Encrypts a message correctly when using pipeline input on ConvertTo-SodiumSealedBox' {
$keyPair = New-SodiumKeyPair
$publicKey = $keyPair.PublicKey
Expand Down Expand Up @@ -103,6 +181,13 @@ Describe 'Sodium' {
$result = $encryptedMessage | ConvertFrom-SodiumSealedBox -PrivateKey $kp.PrivateKey
$result | Should -Be $message
}

It 'Requires a non-empty private key when no public key is given' {
$kp = New-SodiumKeyPair
$encryptedMessage = ConvertTo-SodiumSealedBox -Message 'test' -PublicKey $kp.PublicKey

{ ConvertFrom-SodiumSealedBox -SealedBox $encryptedMessage -PrivateKey '' } | Should -Throw
}
}

Context 'Key Pair Generation' {
Expand Down Expand Up @@ -150,6 +235,24 @@ Describe 'Sodium' {
$keyPair1.PublicKey | Should -Be $keyPair2.PublicKey
$keyPair1.PrivateKey | Should -Be $keyPair2.PrivateKey
}

It 'Returns a PSCustomObject with PublicKey and PrivateKey properties' {
$keyPair = New-SodiumKeyPair

$keyPair | Should -BeOfType [PSCustomObject]
$keyPair.PublicKey | Should -Not -BeNullOrEmpty
$keyPair.PrivateKey | Should -Not -BeNullOrEmpty
($keyPair | Get-Member -MemberType NoteProperty).Name | Should -Contain 'PublicKey'
($keyPair | Get-Member -MemberType NoteProperty).Name | Should -Contain 'PrivateKey'
}

It 'Generates different random key pairs when no seed is provided' {
$keyPair1 = New-SodiumKeyPair
$keyPair2 = New-SodiumKeyPair

$keyPair1.PublicKey | Should -Not -Be $keyPair2.PublicKey
$keyPair1.PrivateKey | Should -Not -Be $keyPair2.PrivateKey
}
}

Context 'Public Key Derivation' {
Expand Down Expand Up @@ -183,6 +286,11 @@ Describe 'Sodium' {
{ Get-SodiumPublicKey -PrivateKey $shortPrivateKey } |
Should -Throw 'Invalid private key. Expected 32 bytes but got 16.'
}

It 'Get-SodiumPublicKey - Requires a non-empty private key' {
{ Get-SodiumPublicKey -PrivateKey '' } | Should -Throw
}

}

Context 'Runtime diagnostics' {
Expand Down