Making a HASH of things... Powershell Style

Grumpy Admin, had to send a Excel file external yesterday. And as he is all for information assurance I decided that I would include a HASH with it, so that people know it was the file they were expect and not some raging office file infected with a macro type STD! Where is condom.msi when you need it!!!

Well lucky for me I have a great little plug-in for Windows Explorer called “hash tab” – Which you can see is very useful and generates various hash’s of the file. Really nice and quick. Job done! This is what I use, quite often day in and day out, right click, hit the tab and see the hash. Very good for ensuring firmware and other downloads are good. File integrity is part of Information Assurance and can affect availability.

I know a lot people have out there written hash generating PowerShell modules. So I thought why not try and write a PowerShell Module myself. These people figured out how to do it! Why can’t I, figure it out and get it done!

Hopefully this will be as close to a clean room PowerShell implementation, it might work it might not let’s have a go!

The first thing is to do some Googling. Documentation is the key here.  So I hit this MSDN site right away. I bet other people used the documentation. After all that what it is there for! It the making the leap from reading and understanding the documentation to solving the problem that I really enjoy! Wish I was smart enough to become a programmer rather than just an Admin! My life path makes me grumpy some days!

So on the MSDN site I quickly find the HashAlgorithm Class….

https://msdn.microsoft.com/en-us/library/System.Security.Cryptography.HashAlgorithm_methods(v=vs.110).aspx

Looking at it and we can see there is a create hash method, which allows us to create an crypto object that will use the either of the following Algorithms. This is good! I am not smart enough to implement the maths required to actually generate the hash. Grumpy admin is lazy, if the code is built into .Net  already might as well use it! So we can create a hash object of the following types!

MD5
SHA1
RIPEMD160
SHA256
SHA384
SHA512

I already know that I want to use SHA256…. we also already know how to call .net functions from PowerShell, [class]::method. so I can create a line like this to start with.

$newhashalgo = [System.Security.Cryptography.HashAlgorithm]::Create(“SHA256”)

Now I can see from the documentation the methods, but I want to check in PowerShell… so let’s run this create the object and do a get-member on it just to have a look at what member methods the object has.

Right, as you can see there is the HASH method and there is a ComputeHash method…

 

I want to compute a hash so I think that might be the bad boy I want in this instance… wow everything is going well so far!

So let’s have a look at this object

$newhashalgo.computehash

This object accepts a System.io.stream,  byte[] buffer, and byte[] buffer with offset and count.  Right so I am going to be dealing with a byte[] data class either way. That simple, there quite a few method of reading file as byte built right in to .Net.

let’s us now have a look at some file handling, back to the good old MSDN

https://msdn.microsoft.com/en-us/library/system.io.file%28v=vs.110%29.aspx

Once again Google and TechNet come to the rescue.  Have a look under the methods for [system.io.file] there is a method called readallbytes. So I could do this to the file, let’s give that a try

$filebytes=[system.io.file]::ReadAllBytes(“c:\test\hash\tapes.xlsx”)

But first I’m am going to need to define the byte field. This is where I will store the file in byte form for the file. At this stage let’s hope I’m not going sha254 a huge mega ISO file! As that could umm get nasty and we could run out of memory. This doesn’t look like a good way of doing things but this is a first proof of concept! And we might be able to address this issue later if it is an issue at the level I am working at. The main thing is to understand what we are doing, copying the file in to memory. Eating up our available memory.

Let’s create the variable and now put the content of file in to it using this

[Byte]$filebytes=””

$filebytes=[system.io.file]::ReadAllBytes(“c:\test\hash\tapes.xlsx”)

Grrr – something went wrong… looking at the error message, it is clear that I did something wrong. From the looks of it, I forgot a couple of [ ]  on $filebytes variable. This means it isn’t an array of byte. Hence the type error. So let’s modify the first like to this

[byte[]]$filebytes=””

Re-Run that code- returns no errors excellent

Now let’s see if we merge the two things together and solve the problem. Can we do that computehash on the file now it is in memory as bytes?

$hash=$newhashalgo.ComputeHash($filebytes)

Yes we can, it works. However, the $hash is in byte[] format still – as you can see from the MSDN we can confirm the return type is System.byte[]

So we need to print this out as a Hex string, which is the normal presentation of hashes. As you might be aware you can use the ToString() features, for example here is a link to the MSDN that shows the standard numeric format strings. These are great things to have in the back of your mind when doing scripts.

For example, tostring(“p”) is percent and “X” is hex! Now as we know the $hash is a byte array, we will need to cycle throw the array and convert each byte – the best way to do this is to use the pipeline so I can do something like this

$hash | %{ $hashhex += $_.ToString(“X”) }

So our code now looks something like this – I always like to blank the variables I use prior. Think this extends from my old BASIC days.

[Byte[]]$filebytes=””
$hash=””
$hashenglish=””
$hashhex=””

$newhashalgo = [System.Security.Cryptography.HashAlgorithm]::Create(“SHA256”)
$filebytes=[system.io.file]::ReadAllBytes(“c:\test\hash\tapes.xlsx”)
$hash=$newhashalgo.ComputeHash($filebytes)
$hash | %{ $hashhex += $_.ToString(“X”) }
$hashhex

Excellent, job done…. or is it!

Let’s just compare the two hashes to confirm as you know Grumpy Admin like to confirm everything he does – yes that worked as you can see…. but this is only good if I want the SHA256 of tapes.xlsx.


The next step is making this in a useful function…. So I invite you to join me again, as we run with this basic concept and start to build a comprehensive function. I will try to include all the best practice and tips that I can think off and we will over the next few blog posts see these four lines of code that we wrote become a useful fully featured PowerShell cmdlet.

Hazzy