I was able to AES encrypt files successfully using this script here, using Windows 10, PowerShell version 5.1.
When I tried running it on Windows 7, PowerShell v2.0, I get an error:
New-CryptographyKey : You cannot call a method on a null-valued expression.
At C:\Users\IEUser\Desktop\enc.ps1:399 char:27
+ $key = New-CryptographyKey <<<< -AsPlainText
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,New-CryptographyKey
Protect-File : Cannot bind argument to parameter 'KeyAsPlainText' because
it is an empty string.
At C:\Users\IEUser\Desktop\enc.ps1:401 char:77
+ Protect-File -FileName "$env:userprofile/Desktop/secret.txt" -KeyAsPlainText <<<< $key
+ CategoryInfo : InvalidData: (:) [Protect-File], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Protect-File
How do I make it work? Or is there another cross-compatible solution for AES file encryption using Powershell?
EDIT:
I might've found a solution with openSSL, but I still tried @Mike Twc's solution, got this output:
PS C:\Users\IEUser\Desktop> .\bouncy.ps1
TEST:
message: Some secret message
key: 9JODwRWWHp6+uACUiydFXNXPmWDHbcObhgqR/cvZ9zg=
IV (base64): U29tZV9QYXNzd29yZA==
IV (utf8): Some_Password
message bytes: 83 111 109 101 32 115 101 99 114 101 116 32 109 101 115 115 97 10
3 101
encrypted message bytes: 178 172 14 98 228 38 129 136 217 25 129 96 46 177 75 62
50 5 190 46 51 108 81 38 90 74 197 166 44 96 120 252
encrypted message: sqwOYuQmgYjZGYFgLrFLPjIFvi4zbFEmWkrFpixgePw=
decrypted bytes: 83 111 109 101 32 115 101 99 114 101 116 32 109 101 115 115 97
103 101 0 0 0 0 0 0 0 0 0 0 0 0 0
decrypted message: Some secret message
Based on the source information for the code you linked to that you say you are using, it was not designed with PowerShell v2 in mind. So, the fact that it is failing, should be expected, because if memory serves, Export-ModuleMember was not introduced until PowerShellv3.
Get-Command -Name Export-moduleMember
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Export-ModuleMember 3.0.0.0 Microsoft.PowerShell.Core
I have no PowerShellv2 anywhere in my environment to saintly check though.
So, as for this..
How do I make it work?
.. upgrade your PowerShell version to 3 - 5x.
As for this...
another cross-compatible solution for AES file encryption using
Powershell?
The only cross platform version of even PowerShell, is PowerShell Core (PowerShell v6).
If you mean a cross platform version of this module, that is up to the author to deliver or you to write it.
If you are asking for come generic cross platform AES tool (even the link you point to is Windows only - so if you needed cross platform Win/OSX/Linux then this would not work anyway), that really not a PowerShell question but a software recommendation and there is a separate board for those questions. Software Recommendations StackExchange, yet you could look to PGP when using PowerShell.
If you are saying a version of AES file encryption, that works across all versions of Windows PowerShell, you need to use the .Net namespace for that. Specifically, the NET's FileStream and CryptoStream classes to encrypt an entire file with AES as demo'd via this script download.
PowerShell Encryption Examples
5 examples of different techniques that can be used to securely encrypt (and in most cases, share) secret data using PowerShell.
Specifically Example 3
Or using this module.
Share encrypted data between users and computers with PowerShell
The attached zip file contains a module which makes it easy to encrypt data using PowerShell, in such a way that it can be decrypted by other authorized users on any computer. It does this by leveraging digital certificates.
The module you're using requires at least PowerShell v3, otherwise the statement
$Crypto = [System.Security.Cryptography.SymmetricAlgorithm]::Create($Algorithm)
in the function you're trying to invoke will not create the algorithm object, which in turn will cause
$Crypto.GenerateKey()
to fail with the error you observed.
Upgrade your Windows 7 system to PowerShell v3 or newer.
You may try to use BouncyCastle library. Below is the AES encryption/decryption implementation with that library. It worked on my end in version 2 mode.
Download latest compiled assembly (BouncyCastle.Crypto.dll) from here:
https://www.bouncycastle.org/csharp/index.html
Extract that dll to any folder (say C:\temp), right click on it, and check "Unblock"
Run this code:
Add-Type -path "C:\stack\BouncyCastle.Crypto.dll"
$secRandom = new-object Org.BouncyCastle.Security.SecureRandom
$message = "Some secret message"
$messageBytes = [System.Text.Encoding]::UTF8.GetBytes($message)
# if using files do this:
# $messageBytes = [System.IO.File]::ReadAllBytes("C:\stack\out.txt")
#==== Key generation =====#
$keyBytes = New-Object byte[] 32
$secRandom.NextBytes($keyBytes)
#$generator = [Org.BouncyCastle.Security.GeneratorUtilities]::GetKeyGenerator("AES")
$generator = New-Object Org.BouncyCastle.Crypto.CipherKeyGenerator
$keyGenParam = new-object Org.BouncyCastle.Crypto.KeyGenerationParameters $keyBytes, 256
$generator.Init($keyGenParam)
$key = $generator.GenerateKey()
#or retreive from base64 string:
$key = [System.Convert]::FromBase64String("9JODwRWWHp6+uACUiydFXNXPmWDHbcObhgqR/cvZ9zg=")
#==== initialization vector (optional) =====#
#IV is a byte array, should be same as AES block size. By default 128 bit or 16 bytes (or less)
$IV = New-Object byte[] 16
# below are some random IVs to play around, if IV parameter is not provided by user just keep it is array of 0s
$secRandom.NextBytes($IV) | Out-Null #random generated 16 bytes
$IV = [System.Text.Encoding]::UTF8.GetBytes("Some_Password") #or use some random phrase
#==== Cipher set up =====#
#specify cipher type (typically CFB or CBC) and padding (use NOPADDING to skip). Check all possible values:
#https://github.com/neoeinstein/bouncycastle/blob/master/crypto/src/security/CipherUtilities.cs
$cipher = [Org.BouncyCastle.Security.CipherUtilities]::GetCipher("AES/CFB/PKCS7")
$aesKeyParam = [Org.BouncyCastle.Security.ParameterUtilities]::CreateKeyParameter("AES", $key)
$keyAndIVparam = New-Object Org.BouncyCastle.Crypto.Parameters.ParametersWithIV $aesKeyParam, $IV
#==== Encrypt =====#
#$cipher.Init($true,$aesKeyParam)
$cipher.Init($true,$keyAndIVparam)
$dataSize = $cipher.GetOutputSize($messageBytes.Length)
$encMessageBytes = New-Object byte[] $dataSize
$len = $cipher.ProcessBytes($messageBytes , 0, $messageBytes.Length, $encMessageBytes, 0)
$cipher.DoFinal($encMessageBytes, $len) | Out-Null
$encMessage = [System.Convert]::ToBase64String($encMessageBytes)
#if using files
#[System.IO.File]::WriteAllText("C:\stack\out.txt.aes", $encMessage)
#$encMessageBytes = [System.Convert]::FromBase64String([System.IO.File]::ReadAllText("C:\stack\out.txt.aes"))
#==== Decrypt =====#
#$cipher.Init($false,$aesKeyParam)
$cipher.Init($false,$keyAndIVparam)
$dataSize = $cipher.GetOutputSize($encMessageBytes.Length)
$decMessageBytes = New-Object byte[] $dataSize
$len = $cipher.ProcessBytes($encMessageBytes , 0, $encMessageBytes.Length, $decMessageBytes, 0)
$cipher.DoFinal($decMessageBytes, $len) | Out-Null
$decMessage = [System.Text.Encoding]::UTF8.GetString($decMessageBytes).Trim([char]0)
#==== TEST =====#
Write-Host "`nTEST:`n"
Write-Host "message: $message"
Write-Host "key: $([System.Convert]::ToBase64String($key))"
Write-Host "IV (base64): $([System.Convert]::ToBase64String($IV))"
Write-Host "IV (utf8): $([System.Text.Encoding]::UTF8.GetString($IV))"
Write-Host "message bytes: $messageBytes"
Write-Host "encrypted message bytes: $encMessageBytes"
Write-Host "encrypted message: $encMessage"
Write-Host "decrypted bytes: $decMessageBytes"
Write-Host "decrypted message: $decMessage"