I wanted to make some simple functions that would be used in the encryption and decryption using a Vigenere square.
# Define the alphabet used in the cipher once so as to not define in memory for every encrypt/decrypt action
$global:alphabet = "abcdefghijklmnopqrstuvwxyz"
function Encrypt-VigenereCipherCharacter{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[char]$Character,
[parameter(Mandatory=$true)]
[char]$Key
)
# This function will encrypt an alphabetic character using a Vigenere Cipher and the key passed.
# Set the characters to lower case for baseline calculation.
$CharacterIndex = $global:alphabet.IndexOf(([string]$Character).ToLower())
$KeyIndex = $global:alphabet.IndexOf(([string]$Key).ToLower())
Write-Verbose "The character/index to $($PSCmdlet.ParameterSetName.ToLower()) is :'$Character/$CharacterIndex' and we are using the key/index: '$Key/$KeyIndex'"
# Get the index of the encrypted character to return.
$ShiftedCharacterIndex = $CharacterIndex + $KeyIndex
# If this shift goes past Z we need to roll back the index to "wrap around" the alphabet to the be.
if($ShiftedCharacterIndex -ge $global:alphabet.Length){$ShiftedCharacterIndex -= $global:alphabet.Length}
# Return the shifted character
return $global:alphabet[$ShiftedCharacterIndex]
}
function Decrypt-VigenereCipherCharacter{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[char]$Character,
[parameter(Mandatory=$true)]
[char]$Key
)
# This function will decrypt an alphabetic character using a Vigenere Cipher and the key passed.
# Set the characters to lower case for baseline calculation.
$CharacterIndex = $global:alphabet.IndexOf(([string]$Character).ToLower())
$KeyIndex = $global:alphabet.IndexOf(([string]$Key).ToLower())
Write-Verbose "The character/index to decrypt is :'$Character/$CharacterIndex' and we are using the key/index: '$Key/$KeyIndex'"
# Decrypt the character based on the positional difference of the character and key
if($KeyIndex -le $CharacterIndex){
$ShiftedCharacterIndex = $CharacterIndex - $KeyIndex
} else {
$ShiftedCharacterIndex = $global:alphabet.Length - $KeyIndex + $CharacterIndex
}
# Return the shifted character
return $global:alphabet[$ShiftedCharacterIndex]
}
function Encrypt-PlainTextString{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[alias("Text")]
[string]$PlainText,
[parameter(Mandatory=$true)]
[string]$Key
)
# This function will encrypt a scrubbed character string using a Vigenere Cipher and the key passed.
# Scrub all the repeated characters from the key so that it is just all unique characters in their original sequence
Write-Verbose "The key requested is : $key"
$Key = -join([char[]]$Key | Select-Object -Unique)
Write-Verbose "The key being used is: $key"
# Remove all alphabetic character from the plain text string.
Write-Verbose "The text requested to encrypt is: $Plaintext"
$PlainText = $PlainText -replace "\W"
Write-Verbose "The text that will be encrypted is: $Plaintext"
# Build the key stream to be the exact length of the text being encrypted.
$keyStream = ($key * ([math]::Ceiling($PlainText.Length / $key.Length))).Substring(0,$PlainText.Length)
Write-Verbose "The text that follows will be the plain text string and its keystream below it."
Write-Verbose $PlainText
Write-Verbose $keyStream
# Encrypt the text
return -join (0..($PlainText.length - 1) | ForEach-Object{
Get-VigenereCipherCharacter -Character $PlainText[$_] -Key $keyStream[$_] -Encrypt
})
}
function Decrypt-CipherText{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[alias("Text")]
[string]$CipherText,
[parameter(Mandatory=$true)]
[string]$Key
)
# This function will decrypt a scrubbed character string using a Vigenere Cipher and the key passed.
# Scrub all the repeated characters from the key so that it is just all unique characters in their original sequence
Write-Verbose "The key requested is : $key"
$Key = -join([char[]]$Key | Select-Object -Unique)
Write-Verbose "The key being used is: $key"
# Remove all alphabetic character from the plain text string.
Write-Verbose "The text requested to decrypt is: $CipherText"
$CipherText = $CipherText -replace "\W"
Write-Verbose "The text that will be decrypted is: $CipherText"
# Build the key stream to be the exact length of the text being decrypted.
$keyStream = ($key * ([math]::Ceiling($CipherText.Length / $key.Length))).Substring(0,$CipherText.Length)
Write-Verbose "The text that follows will be the plain text string and its keystream below it."
Write-Verbose $CipherText
Write-Verbose $keyStream
# Decrypt the text
return -join (0..($CipherText.length - 1) | ForEach-Object{
Get-VigenereCipherCharacter -Character $CipherText[$_] -Key $keyStream[$_] -Decrypt
})
}
function Distribute-Spaces{
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string]$Text,
[parameter(Mandatory=$false)]
[alias("Spaces")]
[int]$NumberOfSpaces = 0
)
# This function will randomly insert a number of spaces into the text passed.
# If the number of space is not provided assume that we place about 1 every 5 characters.
if($NumberOfSpaces -le 0){$NumberOfSpaces = $Text.Length / 9}
# Get positional values for these new spaces and ensure they are not at the beginning or end of the new string.
$spacePositions = 1..$NumberOfSpaces | ForEach-Object{Get-Random -Minimum 1 -Maximum ($text.Length - 2)}
# Rebuild the string with the inserted spaces.
-join (0..($text.Length - 1) | ForEach-Object{
if($spacePositions -contains $_){
$text[$_] + " "
} else {
$text[$_]
}
})
}
The functions exists in two pairs. Encrypt-PlainTextString
will take a string and key and encrypt each character with Encrypt-VigenereCipherCharacter
using a Vigenere square. There are foil decryption functions as well. There is also a spaces distribution function called Distribute-Spaces
which is meant to insert spaces into the encrypted text to "obfuscate" words.
I originally had the encryption and decryption functions as the same function and used switches to differentiate between the two actions. It made sense since they shared several lines. The do however to different things and names the functions with appropriate meaningful names was difficult. Therefore I split them up into their own functions.
Some example usage would be:
$plaintext = "The red fox trots quietly at midnight."
$key = "jamesbond"
$ciphertext = Distribute-Spaces -Text(Encrypt-PlainTextString -PlainText $plaintext -Key $key)
$ciphertext
Decrypt-CipherText -CipherText $ciphertext -Key $key
Which would generate the following output.
chqvwe tb acraxkrivhclkeln wqqrgtx
theredfoxtrotsquietlyatmidnight