On windows, too often, the quickest and easiest way to do something is to download a third .party software to do it, even if you already have the code somewhere in the operating system. Windows does not come with a compiler, it does not come with compiled applications to use all its features, it is not really empowering its users by it self. At least now it has powershell.
So, I made a small powershell script that creates an AES encrypted copy of a file. In the end I will probably not use it because I remembered that 7zip which is already installed on my machine supports encryption, is able to sync a directory in compressed archives and has a command line interface.
Anyways here is the script:
param(
[string]$keyfile=$(throw "Parameter keyfile required."),
[string]$infile=$(throw "Parameter infile required."),
[string]$outfile=$(throw "Parameter outfile required."),
[switch]$decrypt
)
# Encrypt Usage:
# powershell -ExecutionPolicy Unrestricted ./aesfile.ps1 -keyfile key.txt -infile data.txt -outfile data.txt.aes
# Decrypt Usage:
# powershell -ExecutionPolicy Unrestricted ./aesfile.ps1 -keyfile key.txt -infile data.txt.aes -outfile data.dec.txt -decrypt
# Read the key and the iv
# each is on one line and has its byte written in decimal ascii separated by ":"
[byte[]]$key = (Get-Content $keyfile)[0]| foreach {($_ -split ":")}
[byte[]]$iv = (Get-Content $keyfile)[1]| foreach {($_ -split ":")}
[Console]::Error.WriteLine("key=$key")
[Console]::Error.WriteLine("IV=$iv")
[Console]::Error.WriteLine("infile=$infile")
[Console]::Error.WriteLine("outdile=$outfile")
[Console]::Error.WriteLine("decrypt=$decrypt")
# Setup FileStreams
[System.IO.Stream]$instream = new-object System.IO.FileStream $infile, ([System.IO.FileMode]::Open)
[System.IO.Stream]$outstream = new-object System.IO.FileStream $outfile, ([System.IO.FileMode]::Create)
# Setup Encryption
$AesCSP = New-Object System.Security.Cryptography.AesCryptoServiceProvider
$AesCSP.Key = $key
$AesCSP.IV = $IV
if(!$decrypt) {$cryptor=$AesCSP.CreateEncryptor()}
else{$cryptor=$AesCSP.CreateDecryptor()}
$cstream = new-Object Security.Cryptography.CryptoStream $instream,$cryptor,"Read"
# Number of bytes to read with each chunks from the stream.
$BLOCK_BYTE_SIZE = $AesCSP.BlockSize/8
$NB_BLOCKS_READ = 100
$CHUNK_BYTE_SIZE = $BLOCK_BYTE_SIZE * $NB_BLOCKS_READ
#$cstream.CopyTo($outstream, $CHUNK_BYTE_SIZE) Only in .Net 4.0 :(
[byte[]]$buffer = new-object byte[] $CHUNK_BYTE_SIZE
while($byte_read=$cstream.Read($buffer, 0, $buffer.Length))
{
$outstream.Write($buffer, 0, $byte_read)
}
$cstream.Close()
$instream.Close()
$outstream.Close()
Here is a sample key file:
247:74:89:63:153:30:170:243:11:247:227:187:2:177:244:17:154:9:150:12:155:253:168:19:224:241:254:148:213:50:147:184
129:15:216:20:169:11:167:32:75:57:109:137:15:14:92:212
The first line is the key(32 bytes), the second line is an initialization vector(16 bytes).
Bytes are written in decimal and separated by ‘:’.
Notes:
I lost a lot of time trying to support reading binary input on stdin and never found a solution. For something that's called “powershell” I expected better support for stdin. The existing commands/functions only support reading text from the keyboard and the hidden $input.'<>4__this' can only read lines of text. I wanted to use my script with | and > instead of having to open the files myself.