Skip to content

Instantly share code, notes, and snippets.

@Kagre
Forked from jbtule/AESGCM.cs
Last active September 3, 2021 23:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kagre/e8825af009d243542041a786230f4600 to your computer and use it in GitHub Desktop.
Save Kagre/e8825af009d243542041a786230f4600 to your computer and use it in GitHub Desktop.
Convert the AESThenHMAC code example to script for best practice encrypting a string in PowerShell. It uses authenticated encryption. http://stackoverflow.com/a/10366194/637783
<#
* This work (Modern Encryption of a String C#, by James Tuley),
* identified by James Tuley, is free of known copyright restrictions.
* https://gist.github.com/4336842
* http://creativecommons.org/publicdomain/mark/1.0/
#>
#using System;
#using System.IO;
#using System.Security.Cryptography;
#using System.Text;
#namespace Encryption
.{ class AESThenHMAC {
hidden static [System.Security.Cryptography.RandomNumberGenerator] $Random = ([System.Security.Cryptography.RandomNumberGenerator]::Create());
#Preconfigured Encryption Parameters
static [int] $BlockBitSize = 128;
static [int] $KeyBitSize = 256;
#Preconfigured Password Key Derivation Parameters
static [int] $SaltBitSize = 64;
static [int] $Iterations = 10000;
static [int] $MinPasswordLength = 12;
# <summary>
# Helper that generates a random key on each call.
# </summary>
# <returns></returns>
static [byte[]] NewKey(){
$key = new-object byte[] ([AESThenHMAC]::KeyBitSize / 8);
[AESThenHMAC]::Random.GetBytes($key);
return $key;
}
# <summary>
# Simple Encryption (AES) then Authentication (HMAC) for a UTF8 Message.
# </summary>
# <param name="secretMessage">The secret message.</param>
# <param name="cryptKey">The crypt key.</param>
# <param name="authKey">The auth key.</param>
# <param name="nonSecretPayload">(Optional) Non-Secret Payload.</param>
# <returns>
# Encrypted Message
# </returns>
# <exception cref="System.ArgumentException">Secret Message Required!;secretMessage</exception>
# <remarks>
# Adds overhead of (Optional-Payload + BlockSize(16) + Message-Padded-To-Blocksize + HMac-Tag(32)) * 1.33 Base64
# </remarks>
static [string] SimpleEncrypt(
[string]$secretMessage,
[byte[]]$cryptKey,
[byte[]]$authKey,
[byte[]]$nonSecretPayload = $null
){
if([string]::IsNullOrEmpty($secretMessage))
{throw [System.ArgumentException]::new("Secret Message Required!", "secretMessage")}
$plainText = [System.Text.Encoding]::UTF8.GetBytes($secretMessage);
$cipherText = [AESThenHMAC]::SimpleEncrypt($plainText, $cryptKey, $authKey, $nonSecretPayload);
return ([System.Convert]::ToBase64String($cipherText))
}
# <summary>
# Simple Authentication (HMAC) then Decryption (AES) for a secrets UTF8 Message.
# </summary>
# <param name="encryptedMessage">The encrypted message.</param>
# <param name="cryptKey">The crypt key.</param>
# <param name="authKey">The auth key.</param>
# <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
# <returns>
# Decrypted Message
# </returns>
# <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
static [string] SimpleDecrypt(
[string]$encryptedMessage,
[byte[]]$cryptKey,
[byte[]]$authKey,
[int]$nonSecretPayloadLength = 0
){
if([string]::IsNullOrWhiteSpace($encryptedMessage))
{throw [System.ArgumentException]::new("Encrypted Message Required!", "encryptedMessage");}
$cipherText = [System.Convert]::FromBase64String($encryptedMessage);
$plainText = [AESThenHMAC]::SimpleDecrypt($cipherText, $cryptKey, $authKey, $nonSecretPayloadLength);
if($plainText -eq $null){return $null}
return ([System.Text.Encoding]::UTF8.GetString($plainText))
}
# <summary>
# Simple Encryption (AES) then Authentication (HMAC) of a UTF8 message
# using Keys derived from a Password (PBKDF2).
# </summary>
# <param name="secretMessage">The secret message.</param>
# <param name="password">The password.</param>
# <param name="nonSecretPayload">The non secret payload.</param>
# <returns>
# Encrypted Message
# </returns>
# <exception cref="System.ArgumentException">password</exception>
# <remarks>
# Significantly less secure than using random binary keys.
# Adds additional non secret payload for key generation parameters.
# </remarks>
static [string] SimpleEncryptWithPassword(
[string]$secretMessage,
[string]$password,
[byte[]]$nonSecretPayload = $null
){
if([string]::IsNullOrEmpty($secretMessage))
{throw [System.ArgumentException]::new("Secret Message Required!", "secretMessage")}
$plainText = [System.Text.Encoding]::UTF8.GetBytes($secretMessage);
$cipherText = [AESThenHMAC]::SimpleEncryptWithPassword($plainText, $password, $nonSecretPayload);
return ([System.Convert]::ToBase64String($cipherText))
}
# <summary>
# Simple Authentication (HMAC) and then Descryption (AES) of a UTF8 Message
# using keys derived from a password (PBKDF2).
# </summary>
# <param name="encryptedMessage">The encrypted message.</param>
# <param name="password">The password.</param>
# <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
# <returns>
# Decrypted Message
# </returns>
# <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
# <remarks>
# Significantly less secure than using random binary keys.
# </remarks>
static [string] SimpleDecryptWithPassword(
[string]$encryptedMessage,
[string]$password,
[int]$nonSecretPayloadLength = 0
){
if([string]::IsNullOrWhiteSpace($encryptedMessage))
{throw [System.ArgumentException]::new("Encrypted Message Required!", "encryptedMessage")}
$cipherText = [System.Convert]::FromBase64String($encryptedMessage);
$plainText = [AESThenHMAC]::SimpleDecryptWithPassword($cipherText, $password, $nonSecretPayloadLength);
if($plainText -eq $null){return $null}
return ([System.Text.Encoding]::UTF8.GetString($plainText))
}
# <summary>
# Simple Encryption(AES) then Authentication (HMAC) for a UTF8 Message.
# </summary>
# <param name="secretMessage">The secret message.</param>
# <param name="cryptKey">The crypt key.</param>
# <param name="authKey">The auth key.</param>
# <param name="nonSecretPayload">(Optional) Non-Secret Payload.</param>
# <returns>
# Encrypted Message
# </returns>
# <remarks>
# Adds overhead of (Optional-Payload + BlockSize(16) + Message-Padded-To-Blocksize + HMac-Tag(32)) * 1.33 Base64
# </remarks>
static [byte[]] SimpleEncrypt(
[byte[]]$secretMessage,
[byte[]]$cryptKey,
[byte[]]$authKey,
[byte[]]$nonSecretPayload = $null
){
#User Error Checks
if($cryptKey -eq $null -or $cryptKey.Length -ne ([AESThenHMAC]::KeyBitSize / 8))
{throw [System.ArgumentException]::new(("Key needs to be {0} bit!" -f [AESThenHMAC]::KeyBitSize), "cryptKey")}
if($authKey -eq $null -or $authKey.Length -ne ([AESThenHMAC]::KeyBitSize / 8))
{throw [System.ArgumentException]::new(("Key needs to be {0} bit!" -f [AESThenHMAC]::KeyBitSize), "authKey")}
if($secretMessage -eq $null -or $secretMessage.Length -lt 1)
{throw [System.ArgumentException]::new("Secret Message Required!", "secretMessage")}
#non-secret payload optional
if($nonSecretPayload -eq $null){[byte[]]$nonSecretPayload = @()}
#byte[] cipherText;
#byte[] iv;
$aes = [System.Security.Cryptography.AesManaged]::new()
$aes.KeySize = [AESThenHMAC]::KeyBitSize
$aes.BlockSize = [AESThenHMAC]::BlockBitSize
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
#Use random IV
$aes.GenerateIV();
$iv = $aes.IV;
$encrypter = $aes.CreateEncryptor($cryptKey, $iv)
$cipherStream = [System.IO.MemoryStream]::new()
$cryptoStream = [System.Security.Cryptography.CryptoStream]::new($cipherStream, $encrypter, [System.Security.Cryptography.CryptoStreamMode]::Write)
$binaryWriter = [System.IO.BinaryWriter]::new($cryptoStream)
#Encrypt Data
$binaryWriter.Write($secretMessage);
$cryptoStream.Dispose();$binaryWriter.Dispose();
$cipherText = $cipherStream.ToArray();
$encrypter.Dispose();$cipherStream.Dispose()
$aes.Dispose()
#Assemble encrypted message and add authentication
$hmac = [System.Security.Cryptography.HMACSHA256]::new($authKey)
$encryptedStream = [System.IO.MemoryStream]::new()
$binaryWriter = [System.IO.BinaryWriter]::new($encryptedStream)
#Prepend non-secret payload if any
$binaryWriter.Write($nonSecretPayload);
#Prepend IV
$binaryWriter.Write($iv);
#Write Ciphertext
$binaryWriter.Write($cipherText);
$binaryWriter.Flush();
#Authenticate all data
$tag = $hmac.ComputeHash($encryptedStream.ToArray());
#Postpend tag
$binaryWriter.Write($tag);
$ret = $encryptedStream.ToArray()
$binaryWriter.Dispose()
$hmac.Dispose();$encryptedStream.Dispose();
return $ret
}
# <summary>
# Simple Authentication (HMAC) then Decryption (AES) for a secrets UTF8 Message.
# </summary>
# <param name="encryptedMessage">The encrypted message.</param>
# <param name="cryptKey">The crypt key.</param>
# <param name="authKey">The auth key.</param>
# <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
# <returns>Decrypted Message</returns>
static [byte[]] SimpleDecrypt(
[byte[]]$encryptedMessage,
[byte[]]$cryptKey,
[byte[]]$authKey,
[int]$nonSecretPayloadLength = 0
){
#Basic Usage Error Checks
if($cryptKey -eq $null -or $cryptKey.Length -ne ([AESThenHMAC]::KeyBitSize / 8))
{throw [System.ArgumentException]::new(("Key needs to be {0} bit!" -f [AESThenHMAC]::KeyBitSize), "cryptKey")}
if($authKey -eq $null -or $authKey.Length -ne ([AESThenHMAC]::KeyBitSize / 8))
{throw [System.ArgumentException]::new(("Key needs to be {0} bit!" -f [AESThenHMAC]::KeyBitSize), "authKey")}
if($encryptedMessage -eq $null -or $encryptedMessage.Length -eq 0)
{throw [System.ArgumentException]::new("Encrypted Message Required!", "encryptedMessage")}
$hmac = [System.Security.Cryptography.HMACSHA256]::new($authKey)
$sentTag = new-object byte[] ($hmac.HashSize / 8)
#Calculate Tag
$calcTag = $hmac.ComputeHash($encryptedMessage, 0, $encryptedMessage.Length - $sentTag.Length);
$ivLength = ([AESThenHMAC]::BlockBitSize / 8);
#if message length is to small just return null
if($encryptedMessage.Length -lt $sentTag.Length + $nonSecretPayloadLength + $ivLength)
{return $null}
#Grab Sent Tag
[Array]::Copy($encryptedMessage, $encryptedMessage.Length - $sentTag.Length, $sentTag, 0, $sentTag.Length);
#Compare Tag with constant time comparison
$compare = 0;
for($i = 0; $i -lt $sentTag.Length; $i++)
{$compare = $compare -bOr ($sentTag[$i] -bXor $calcTag[$i])}
#if message doesn't authenticate return null
if($compare -ne 0)
{return $null}
$aes = [System.Security.Cryptography.AesManaged]::new()
$aes.KeySize = [AESThenHMAC]::KeyBitSize
$aes.BlockSize = [AESThenHMAC]::BlockBitSize
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
#Grab IV from message
$iv = new-object byte[] $ivLength;
[Array]::Copy($encryptedMessage, $nonSecretPayloadLength, $iv, 0, $iv.Length);
$decrypter = $aes.CreateDecryptor($cryptKey, $iv)
$plainTextStream = [System.IO.MemoryStream]::new()
$decrypterStream = [System.Security.Cryptography.CryptoStream]::new($plainTextStream, $decrypter, [System.Security.Cryptography.CryptoStreamMode]::Write)
$binaryWriter = [System.IO.BinaryWriter]::new($decrypterStream)
#Decrypt Cipher Text from Message
$binaryWriter.Write(
$encryptedMessage,
$nonSecretPayloadLength + $iv.Length,
$encryptedMessage.Length - $nonSecretPayloadLength - $iv.Length - $sentTag.Length
);
$decrypterStream.Dispose();$binaryWriter.Dispose();
#Return Plain Text
$ret = $plainTextStream.ToArray()
$decrypter.Dispose();$plainTextStream.Dispose()
$aes.Dispose()
$hmac.Dispose()
return $ret
}
# <summary>
# Simple Encryption (AES) then Authentication (HMAC) of a UTF8 message
# using Keys derived from a Password (PBKDF2)
# </summary>
# <param name="secretMessage">The secret message.</param>
# <param name="password">The password.</param>
# <param name="nonSecretPayload">The non secret payload.</param>
# <returns>
# Encrypted Message
# </returns>
# <exception cref="System.ArgumentException">Must have a password of minimum length;password</exception>
# <remarks>
# Significantly less secure than using random binary keys.
# Adds additional non secret payload for key generation parameters.
# </remarks>
static [byte[]] SimpleEncryptWithPassword(
[byte[]]$secretMessage,
[string]$password,
[byte[]]$nonSecretPayload = $null
){
if($nonSecretPayload -eq $null){[byte[]]$nonSecretPayload = @()}
#User Error Checks
if([string]::IsNullOrWhiteSpace($password) -or $password.Length -lt [AESThenHMAC]::MinPasswordLength)
{throw [System.ArgumentException]::new(("Must have a password of at least {0} characters!" -f [AESThenHMAC]::MinPasswordLength), "password")}
if($secretMessage -eq $null -or $secretMessage.Length -eq 0)
{throw [System.ArgumentException]::new("Secret Message Required!", "secretMessage")}
$payload = new-object byte[] ((([AESThenHMAC]::SaltBitSize / 8) * 2) + $nonSecretPayload.Length);
[Array]::Copy($nonSecretPayload, $payload, $nonSecretPayload.Length);
[int]$payloadIndex = $nonSecretPayload.Length;
#byte[] cryptKey;
#byte[] authKey;
#Use Random Salt to prevent pre-generated weak password attacks.
$generator = [System.Security.Cryptography.Rfc2898DeriveBytes]::new($password, ([AESThenHMAC]::SaltBitSize / 8), [AESThenHMAC]::Iterations)
$salt = $generator.Salt;
#Generate Keys
$cryptKey = $generator.GetBytes(([AESThenHMAC]::KeyBitSize / 8));
#Create Non Secret Payload
[Array]::Copy($salt, 0, $payload, $payloadIndex, $salt.Length);
$payloadIndex += $salt.Length;
$generator.Dispose()
#Deriving separate key, might be less efficient than using HKDF,
#but now compatible with RNEncryptor which had a very similar wireformat and requires less code than HKDF.
$generator = [System.Security.Cryptography.Rfc2898DeriveBytes]::new($password, ([AESThenHMAC]::SaltBitSize / 8), [AESThenHMAC]::Iterations)
$salt = $generator.Salt;
#Generate Keys
$authKey = $generator.GetBytes(([AESThenHMAC]::KeyBitSize / 8));
#Create Rest of Non Secret Payload
[Array]::Copy($salt, 0, $payload, $payloadIndex, $salt.Length);
$generator.Dispose()
return ([AESThenHMAC]::SimpleEncrypt($secretMessage, $cryptKey, $authKey, $payload))
}
# <summary>
# Simple Authentication (HMAC) and then Descryption (AES) of a UTF8 Message
# using keys derived from a password (PBKDF2).
# </summary>
# <param name="encryptedMessage">The encrypted message.</param>
# <param name="password">The password.</param>
# <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
# <returns>
# Decrypted Message
# </returns>
# <exception cref="System.ArgumentException">Must have a password of minimum length;password</exception>
# <remarks>
# Significantly less secure than using random binary keys.
# </remarks>
static [byte[]] SimpleDecryptWithPassword(
[byte[]]$encryptedMessage,
[string]$password,
[int]$nonSecretPayloadLength = 0
){
#User Error Checks
if([string]::IsNullOrWhiteSpace($password) -or $password.Length -lt [AESThenHMAC]::MinPasswordLength)
{throw [System.ArgumentException]::new(("Must have a password of at least {0} characters!" -f [AESThenHMAC]::MinPasswordLength), "password")}
if($encryptedMessage -eq $null -or $encryptedMessage.Length -eq 0)
{throw [System.ArgumentException]::new("Encrypted Message Required!", "encryptedMessage")}
$cryptSalt = new-object byte[] ([AESThenHMAC]::SaltBitSize / 8);
$authSalt = new-object byte[] ([AESThenHMAC]::SaltBitSize / 8);
#Grab Salt from Non-Secret Payload
[Array]::Copy($encryptedMessage, $nonSecretPayloadLength, $cryptSalt, 0, $cryptSalt.Length);
[Array]::Copy($encryptedMessage, $nonSecretPayloadLength + $cryptSalt.Length, $authSalt, 0, $authSalt.Length);
#byte[] cryptKey;
#byte[] authKey;
#Generate crypt key
$generator = [System.Security.Cryptography.Rfc2898DeriveBytes]::new($password, $cryptSalt, [AESThenHMAC]::Iterations)
$cryptKey = $generator.GetBytes(([AESThenHMAC]::KeyBitSize / 8));
$generator.Dispose()
#Generate auth key
$generator = [System.Security.Cryptography.Rfc2898DeriveBytes]::new($password, $authSalt, [AESThenHMAC]::Iterations)
$authKey = $generator.GetBytes(([AESThenHMAC]::KeyBitSize / 8));
$generator.Dispose()
return ([AESThenHMAC]::SimpleDecrypt($encryptedMessage, $cryptKey, $authKey, $cryptSalt.Length + $authSalt.Length + $nonSecretPayloadLength));
}
}}
<#
.SYNOPSIS
Pester'ng the AESThenHMAC class library
.EXAMPLE
Invoke-Pester .\AESThenHMAC.Tests.ps1
#>param()
. (join-path $PSScriptRoot 'AESThenHMAC.ps1')
$ProjectName = 'AESThenHMAC'
$DebugPreference = 'Continue'
$SkipSlowTests = $true
$ExceptionText = @{}
$ExceptionText.secretMessage = @'
System.ArgumentException: Secret Message Required!
Parameter name: secretMessage
'@
$ExceptionText.encryptedMessage = @'
System.ArgumentException: Encrypted Message Required!
Parameter name: encryptedMessage
'@
$ExceptionText.cryptKey = @'
System.ArgumentException: Key needs to be {0} bit!
Parameter name: cryptKey
'@ -f [AESThenHMAC]::KeyBitSize
$ExceptionText.authKey = @'
System.ArgumentException: Key needs to be {0} bit!
Parameter name: authKey
'@ -f [AESThenHMAC]::KeyBitSize
$ExceptionText.password = @'
System.ArgumentException: Must have a password of at least {0} characters!
Parameter name: password
'@ -f [AESThenHMAC]::MinPasswordLength
function get-exception{
param([ScriptBlock]$code)
try{$null = & $code}catch {return $_.Exception}
}
#################################################################
Describe "$ProjectName Unit Tests" -Tag 'Unit' {
It 'the get-exception tool works' {get-exception {throw 'foo'} | out-string | should be "foo`r`n"}
Context 'Encryption Constants' {
It 'has KeyBitSize > 255' {[AESThenHMAC]::KeyBitSize | should BeGreaterThan 255}
It 'has BlockBitSize > 0' {[AESThenHMAC]::BlockBitSize | should BeGreaterThan 0}
It 'has SaltBitSize > 63' {[AESThenHMAC]::SaltBitSize | should BeGreaterThan 63}
It 'has Iterations > 9999' {[AESThenHMAC]::Iterations | should BeGreaterThan 9999}
It 'has MinPasswordLength > 10' {[AESThenHMAC]::MinPasswordLength | should BeGreaterThan 10}
}
Context 'When using the NewKey method' {
It 'provides a key' {
$res = [AESThenHMAC]::NewKey()
$res.GetType() | should be byte[]
$res.Length | should be ([AESThenHMAC]::KeyBitSize / 8)
}
It 'provides 1000 unique keys' {
$KeyDict = @{}; $Dupes = 0
for($i=0;$i -lt 1000; $i++){
$key = [System.Convert]::ToBase64String([AESThenHMAC]::NewKey())
$KeyDict.$key++
}
$KeyDict.Count | should BeGreaterThan 995 #over-kill, there's no way 1000 random keys has 5 dupes
} -Skip:$SkipSlowTests
}
[byte[]]$cryptKey = 1..([AESThenHMAC]::KeyBitSize / 8)
[byte[]]$authKey = ([AESThenHMAC]::KeyBitSize / 8)..1
[byte[]]$nonSecretPayload = $null
[int]$nonSecretPayloadLength = 0
[string]$password = 'a' * ([AESThenHMAC]::MinPasswordLength + 1)
$ogMessage = 'Text to be encrypted'
$ogNonSecretPayload = 'Clear Text'
Context 'When using the SimpleEncrypt(string,byte[],byte[],byte[]) method' {
[string]$secretMessage = $ogMessage
It 'throws on null and empty SecretMessage' {
[string]$secretMessage = ''
get-exception {[AESThenHMAC]::SimpleEncrypt($null,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.secretMessage
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.secretMessage
}
It 'encrypts secretMessage with nonSecretPayload' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
$locked = [AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)
[AESThenHMAC]::SimpleDecrypt($locked,$cryptKey,$authKey,$nonSecretPayload.Length) | should be $ogMessage
}
It 'encrypts secretMessage without nonSecretPayload' {
$locked = [AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$null)
[AESThenHMAC]::SimpleDecrypt($locked,$cryptKey,$authKey,0) | should be $ogMessage
}
}
Context 'When using the SimpleEncrypt(byte[],byte[],byte[],byte[]) method' {
[byte[]]$secretMessage = [char[]]$ogMessage
It 'throws on null and empty SecretMessage' {
[byte[]]$secretMessage = @()
get-exception {[AESThenHMAC]::SimpleEncrypt($null,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.secretMessage
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.secretMessage
}
It 'throws on null, empty, and wrong size cryptKey' {
[byte[]]$cryptKey = @()
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$null,$authKey,$nonSecretPayload)} | should be $ExceptionText.cryptKey
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.cryptKey
[byte[]]$cryptKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) - 1)
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.cryptKey
[byte[]]$cryptKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) + 1)
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.cryptKey
}
It 'throws on null, empty, and wrong size authKey' {
[byte[]]$authKey = @()
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$null,$nonSecretPayload)} | should be $ExceptionText.authKey
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.authKey
[byte[]]$authKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) - 1)
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.authKey
[byte[]]$authKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) + 1)
get-exception {[AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)} | should be $ExceptionText.authKey
}
It 'encrypts secretMessage with nonSecretPayload' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
$locked = [AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$nonSecretPayload)
$AsBytes = [AESThenHMAC]::SimpleDecrypt($locked,$cryptKey,$authKey,$nonSecretPayload.Length)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
It 'encrypts secretMessage without nonSecretPayload' {
$locked = [AESThenHMAC]::SimpleEncrypt($secretMessage,$cryptKey,$authKey,$null)
$AsBytes = [AESThenHMAC]::SimpleDecrypt($locked,$cryptKey,$authKey,0)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
}
Context 'When using the SimpleDecrypt(string,byte[],byte[],int) method' {
[string]$encryptedMessage = 'Good Base64 String'
It 'throws on null and empty encryptedMessage' {
[string]$encryptedMessage = ''
get-exception {[AESThenHMAC]::SimpleDecrypt($null,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
}
It 'decrypts encryptedMessage with nonSecretPayloadLength' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
[string]$encryptedMessage = [AESThenHMAC]::SimpleEncrypt($ogMessage,$cryptKey,$authKey,$nonSecretPayload)
[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayload.Length) | should be $ogMessage
}
It 'decrypts encryptedMessage without nonSecretPayloadLength' {
[string]$encryptedMessage = [AESThenHMAC]::SimpleEncrypt($ogMessage,$cryptKey,$authKey,$null)
[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,0) | should be $ogMessage
}
}
Context 'When using the SimpleDecrypt(byte[],byte[],byte[],int) method' {
[byte[]]$encryptedMessage = [System.Convert]::FromBase64String('Good Base64 String')
It 'throws on null and empty encryptedMessage' {
[byte[]]$encryptedMessage = @()
get-exception {[AESThenHMAC]::SimpleDecrypt($null,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
}
It 'throws on null, empty, and wrong size cryptKey' {
[byte[]]$cryptKey = @()
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$null,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.cryptKey
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.cryptKey
[byte[]]$cryptKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) - 1)
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.cryptKey
[byte[]]$cryptKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) + 1)
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.cryptKey
}
It 'throws on null, empty, and wrong size authKey' {
[byte[]]$authKey = @()
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$null,$nonSecretPayloadLength)} | should be $ExceptionText.authKey
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.authKey
[byte[]]$authKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) - 1)
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.authKey
[byte[]]$authKey = @(0) * (([AESThenHMAC]::KeyBitSize / 8) + 1)
get-exception {[AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayloadLength)} | should be $ExceptionText.authKey
}
It 'decrypts encryptedMessage with nonSecretPayloadLength' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
[string]$encryptedMessage = [AESThenHMAC]::SimpleEncrypt($ogMessage,$cryptKey,$authKey,$nonSecretPayload)
[byte[]]$encryptedMessage = [System.Convert]::FromBase64String($encryptedMessage)
$AsBytes = [AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,$nonSecretPayload.Length)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
It 'decrypts encryptedMessage without nonSecretPayloadLength' {
[string]$encryptedMessage = [AESThenHMAC]::SimpleEncrypt($ogMessage,$cryptKey,$authKey,$null)
[byte[]]$encryptedMessage = [System.Convert]::FromBase64String($encryptedMessage)
$AsBytes = [AESThenHMAC]::SimpleDecrypt($encryptedMessage,$cryptKey,$authKey,0)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
}
Context 'When using the SimpleEncryptWithPassword(string,string,byte[]) method' {
[string]$secretMessage = $ogMessage
It 'throws on null and empty SecretMessage' {
[string]$secretMessage = ''
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($null,$password,$nonSecretPayload)} | should be $ExceptionText.secretMessage
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$nonSecretPayload)} | should be $ExceptionText.secretMessage
}
It 'encrypts secretMessage with nonSecretPayload' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
$locked = [AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$nonSecretPayload)
[AESThenHMAC]::SimpleDecryptWithPassword($locked,$password,$nonSecretPayload.Length) | should be $ogMessage
}
It 'encrypts secretMessage without nonSecretPayload' {
$locked = [AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$null)
[AESThenHMAC]::SimpleDecryptWithPassword($locked,$password,0) | should be $ogMessage
}
}
Context 'When using the SimpleEncryptWithPassword(byte[],string,byte[]) method' {
[byte[]]$secretMessage = [char[]]$ogMessage
It 'throws on null and empty SecretMessage' {
[byte[]]$secretMessage = @()
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($null,$password,$nonSecretPayload)} | should be $ExceptionText.secretMessage
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$nonSecretPayload)} | should be $ExceptionText.secretMessage
}
It 'throws on null, empty, and short password' {
[string]$password = ''
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$null,$nonSecretPayload)} | should be $ExceptionText.password
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$nonSecretPayload)} | should be $ExceptionText.password
[string]$password = 'a' * ([AESThenHMAC]::MinPasswordLength - 1)
get-exception {[AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$nonSecretPayload)} | should be $ExceptionText.password
}
It 'encrypts secretMessage with nonSecretPayload' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
$locked = [AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$nonSecretPayload)
$AsBytes = [AESThenHMAC]::SimpleDecryptWithPassword($locked,$password,$nonSecretPayload.Length)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
It 'encrypts secretMessage without nonSecretPayload' {
$locked = [AESThenHMAC]::SimpleEncryptWithPassword($secretMessage,$password,$null)
$AsBytes = [AESThenHMAC]::SimpleDecryptWithPassword($locked,$password,0)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
}
Context 'When using the SimpleDecryptWithPassword(string,string,int) method' {
[string]$encryptedMessage = 'Good Base64 String'
It 'throws on null and empty encryptedMessage' {
[string]$encryptedMessage = ''
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($null,$password,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
}
It 'decrypts encryptedMessage with nonSecretPayloadLength' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
[string]$encryptedMessage = [AESThenHMAC]::SimpleEncryptWithPassword($ogMessage,$password,$nonSecretPayload)
[AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,$nonSecretPayload.Length) | should be $ogMessage
}
It 'decrypts encryptedMessage without nonSecretPayloadLength' {
[string]$encryptedMessage = [AESThenHMAC]::SimpleEncryptWithPassword($ogMessage,$password,$null)
[AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,0) | should be $ogMessage
}
}
Context 'When using the SimpleDecryptWithPassword(byte[],string,int) method' {
[byte[]]$encryptedMessage = [System.Convert]::FromBase64String('Good Base64 String')
It 'throws on null and empty encryptedMessage' {
[byte[]]$encryptedMessage = @()
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($null,$password,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,$nonSecretPayloadLength)} | should be $ExceptionText.encryptedMessage
}
It 'throws on null, empty, and short password' {
[string]$password = ''
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($null,$null,$nonSecretPayloadLength)} | should be $ExceptionText.password
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,$nonSecretPayloadLength)} | should be $ExceptionText.password
[string]$password = 'a' * ([AESThenHMAC]::MinPasswordLength - 1)
get-exception {[AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,$nonSecretPayloadLength)} | should be $ExceptionText.password
}
It 'decrypts encryptedMessage with nonSecretPayloadLength' {
[byte[]]$nonSecretPayload = [char[]]$ogNonSecretPayload
$encryptedMessage = [AESThenHMAC]::SimpleEncryptWithPassword(([byte[]][char[]]$ogMessage),$password,$nonSecretPayload)
$AsBytes = [AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,$nonSecretPayload.Length)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
It 'decrypts encryptedMessage without nonSecretPayloadLength' {
$encryptedMessage = [AESThenHMAC]::SimpleEncryptWithPassword(([byte[]][char[]]$ogMessage),$password,$null)
$AsBytes = [AESThenHMAC]::SimpleDecryptWithPassword($encryptedMessage,$password,0)
[System.Text.Encoding]::UTF8.GetString($AsBytes) | should be $ogMessage
}
}
}
#################################################################
Describe "$ProjectName Integration Tests" -Tag 'Integration','Automatic' {
It 'should test something' {}
}
#################################################################
Describe "$ProjectName Acceptance Tests" -Tag 'Acceptance' {
It 'should test something' {}
}
$DebugPreference = 'SilentlyContinue'
remove-variable ProjectName
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment