Skip to content

Instantly share code, notes, and snippets.

@pldmgg
Created August 17, 2017 19:02
Show Gist options
  • Save pldmgg/c03bd30431278ef5316784228a9dfe28 to your computer and use it in GitHub Desktop.
Save pldmgg/c03bd30431278ef5316784228a9dfe28 to your computer and use it in GitHub Desktop.
Get-KeccakDigestHex
function Get-KeccakDigestHex {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$PublicKeyThumbPrint
)
##### BEGIN Helper Functions #####
function Unzip-File {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,Position=0)]
[string]$PathToZip,
[Parameter(Mandatory=$true,Position=1)]
[string]$TargetDir,
[Parameter(Mandatory=$false,Position=2)]
[string[]]$SpecificItem
)
if ($PSVersionTable.PSEdition -eq "Core") {
[System.Collections.ArrayList]$AssembliesToCheckFor = @("System.Console","System","System.IO",
"System.IO.Compression","System.IO.Compression.Filesystem","System.IO.Compression.ZipFile"
)
[System.Collections.ArrayList]$NeededAssemblies = @()
foreach ($assembly in $AssembliesToCheckFor) {
try {
[System.Collections.ArrayList]$Failures = @()
try {
$TestLoad = [System.Reflection.Assembly]::LoadWithPartialName($assembly)
if (!$TestLoad) {
throw
}
}
catch {
$null = $Failures.Add("Failed LoadWithPartialName")
}
try {
$null = Invoke-Expression "[$assembly]"
}
catch {
$null = $Failures.Add("Failed TabComplete Check")
}
if ($Failures.Count -gt 1) {
$Failures
throw
}
}
catch {
Write-Host "Downloading $assembly..."
$NewAssemblyDir = "$HOME\Downloads\$assembly"
$NewAssemblyDllPath = "$NewAssemblyDir\$assembly.dll"
if (!$(Test-Path $NewAssemblyDir)) {
New-Item -ItemType Directory -Path $NewAssemblyDir
}
if (Test-Path "$NewAssemblyDir\$assembly*.zip") {
Remove-Item "$NewAssemblyDir\$assembly*.zip" -Force
}
$OutFileBaseNamePrep = Invoke-WebRequest "https://www.nuget.org/api/v2/package/$assembly" -DisableKeepAlive -UseBasicParsing
$OutFileBaseName = $($OutFileBaseNamePrep.BaseResponse.ResponseUri.AbsoluteUri -split "/")[-1] -replace "nupkg","zip"
Invoke-WebRequest -Uri "https://www.nuget.org/api/v2/package/$assembly" -OutFile "$NewAssemblyDir\$OutFileBaseName"
Expand-Archive -Path "$NewAssemblyDir\$OutFileBaseName" -DestinationPath $NewAssemblyDir
$PossibleDLLs = Get-ChildItem -Recurse $NewAssemblyDir | Where-Object {$_.Name -eq "$assembly.dll" -and $_.Parent -notmatch "net[0-9]" -and $_.Parent -match "core|standard"}
if ($PossibleDLLs.Count -gt 1) {
Write-Warning "More than one item within $NewAssemblyDir\$OutFileBaseName matches $assembly.dll"
Write-Host "Matches include the following:"
for ($i=0; $i -lt $PossibleDLLs.Count; $i++){
"$i) $($($PossibleDLLs[$i]).FullName)"
}
$Choice = Read-Host -Prompt "Please enter the number corresponding to the .dll you would like to load [0..$($($PossibleDLLs.Count)-1)]"
if ($(0..$($($PossibleDLLs.Count)-1)) -notcontains $Choice) {
Write-Error "The number indicated does is not a valid choice! Halting!"
$global:FunctionResult = "1"
return
}
if ($PSVersionTable.Platform -eq "Win32NT") {
# Install to GAC
[System.Reflection.Assembly]::LoadWithPartialName("System.EnterpriseServices")
$publish = New-Object System.EnterpriseServices.Internal.Publish
$publish.GacInstall($PossibleDLLs[$Choice].FullName)
}
# Copy it to the root of $NewAssemblyDir\$OutFileBaseName
Copy-Item -Path "$($PossibleDLLs[$Choice].FullName)" -Destination "$NewAssemblyDir\$assembly.dll"
# Remove everything else that was extracted with Expand-Archive
Get-ChildItem -Recurse $NewAssemblyDir | Where-Object {
$_.FullName -ne "$NewAssemblyDir\$assembly.dll" -and
$_.FullName -ne "$NewAssemblyDir\$OutFileBaseName"
} | Remove-Item -Recurse -Force
}
if ($PossibleDLLs.Count -lt 1) {
Write-Error "No matching .dll files were found within $NewAssemblyDir\$OutFileBaseName ! Halting!"
continue
}
if ($PossibleDLLs.Count -eq 1) {
if ($PSVersionTable.Platform -eq "Win32NT") {
# Install to GAC
[System.Reflection.Assembly]::LoadWithPartialName("System.EnterpriseServices")
$publish = New-Object System.EnterpriseServices.Internal.Publish
$publish.GacInstall($PossibleDLLs.FullName)
}
# Copy it to the root of $NewAssemblyDir\$OutFileBaseName
Copy-Item -Path "$($PossibleDLLs[$Choice].FullName)" -Destination "$NewAssemblyDir\$assembly.dll"
# Remove everything else that was extracted with Expand-Archive
Get-ChildItem -Recurse $NewAssemblyDir | Where-Object {
$_.FullName -ne "$NewAssemblyDir\$assembly.dll" -and
$_.FullName -ne "$NewAssemblyDir\$OutFileBaseName"
} | Remove-Item -Recurse -Force
}
}
$AssemblyFullInfo = [System.Reflection.Assembly]::LoadWithPartialName($assembly)
if (!$AssemblyFullInfo) {
$AssemblyFullInfo = [System.Reflection.Assembly]::LoadFile("$NewAssemblyDir\$assembly.dll")
}
if (!$AssemblyFullInfo) {
Write-Error "The assembly $assembly could not be found or otherwise loaded! Halting!"
$global:FunctionResult = "1"
return
}
$null = $NeededAssemblies.Add([pscustomobject]@{
AssemblyName = "$assembly"
Available = if ($AssemblyFullInfo){$true} else {$false}
AssemblyInfo = $AssemblyFullInfo
AssemblyLocation = $AssemblyFullInfo.Location
})
}
if ($NeededAssemblies.Available -contains $false) {
$AssembliesNotFound = $($NeededAssemblies | Where-Object {$_.Available -eq $false}).AssemblyName
Write-Error "The following assemblies cannot be found:`n$AssembliesNotFound`nHalting!"
$global:FunctionResult = "1"
return
}
$Assem = $NeededAssemblies.AssemblyInfo.FullName
$Source = @"
using System;
using System.IO;
using System.IO.Compression;
namespace MyCore.Utils
{
public static class Zip
{
public static void ExtractAll(string sourcepath, string destpath)
{
string zipPath = @sourcepath;
string extractPath = @destpath;
using (ZipArchive archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
{
archive.ExtractToDirectory(extractPath);
}
}
public static void ExtractSpecific(string sourcepath, string destpath, string specificitem)
{
string zipPath = @sourcepath;
string extractPath = @destpath;
string itemout = @specificitem.Replace(@"\","/");
//Console.WriteLine(itemout);
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
//Console.WriteLine(entry.FullName);
//bool satisfied = new bool();
//satisfied = entry.FullName.IndexOf(@itemout, 0, StringComparison.CurrentCultureIgnoreCase) != -1;
//Console.WriteLine(satisfied);
if (entry.FullName.IndexOf(@itemout, 0, StringComparison.CurrentCultureIgnoreCase) != -1)
{
string finaloutputpath = extractPath + "\\" + entry.Name;
entry.ExtractToFile(finaloutputpath, true);
}
}
}
}
}
}
"@
Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source
if (!$SpecificItem) {
[MyCore.Utils.Zip]::ExtractAll($PathToZip, $TargetDir)
}
else {
[MyCore.Utils.Zip]::ExtractSpecific($PathToZip, $TargetDir, $SpecificItem)
}
}
if ($PSVersionTable.PSEdition -eq "Desktop" -and $($($PSVersionTable.Platform -and $PSVersionTable.Platform -eq "Win32NT") -or !$PSVersionTable.Platform)) {
if ($SpecificItem) {
foreach ($item in $SpecificItem) {
if ($SpecificItem -match "\\") {
$SpecificItem = $SpecificItem -replace "\\","\\"
}
}
}
##### BEGIN Native Helper Functions #####
function Get-ZipChildItems {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false,Position=0)]
[string]$ZipFile = $(Read-Host -Prompt "Please enter the full path to the zip file")
)
$shellapp = new-object -com shell.application
$zipFileComObj = $shellapp.Namespace($ZipFile)
$i = $zipFileComObj.Items()
Get-ZipChildItems_Recurse $i
}
function Get-ZipChildItems_Recurse {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,Position=0)]
$items
)
foreach($si in $items) {
if($si.getfolder -ne $null) {
# Loop through subfolders
Get-ZipChildItems_Recurse $si.getfolder.items()
}
# Spit out the object
$si
}
}
##### END Native Helper Functions #####
##### BEGIN Variable/Parameter Transforms and PreRun Prep #####
if (!$(Test-Path $PathToZip)) {
Write-Verbose "The path $PathToZip was not found! Halting!"
Write-Error "The path $PathToZip was not found! Halting!"
$global:FunctionResult = "1"
return
}
if ($(Get-ChildItem $PathToZip).Extension -ne ".zip") {
Write-Verbose "The file specified by the -PathToZip parameter does not have a .zip file extension! Halting!"
Write-Error "The file specified by the -PathToZip parameter does not have a .zip file extension! Halting!"
$global:FunctionResult = "1"
return
}
$ZipFileNameWExt = $(Get-ChildItem $PathToZip).Name
##### END Variable/Parameter Transforms and PreRun Prep #####
##### BEGIN Main Body #####
Write-Verbose "NOTE: PowerShell 5.0 uses Expand-Archive cmdlet to unzip files"
if (!$SpecificItem) {
if ($PSVersionTable.PSVersion.Major -ge 5) {
Expand-Archive -Path $PathToZip -DestinationPath $TargetDir
}
if ($PSVersionTable.PSVersion.Major -lt 5) {
# Load System.IO.Compression.Filesystem
[System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
# Unzip file
[System.IO.Compression.ZipFile]::ExtractToDirectory($PathToZip, $TargetDir)
}
}
if ($SpecificItem) {
$ZipSubItems = Get-ZipChildItems -ZipFile $PathToZip
foreach ($searchitem in $SpecificItem) {
[array]$potentialItems = foreach ($item in $ZipSubItems) {
if ($item.Path -match $searchitem) {
$item
}
}
$shell = new-object -com shell.application
if ($potentialItems.Count -eq 1) {
$shell.Namespace($TargetDir).CopyHere($potentialItems[0], 0x14)
}
if ($potentialItems.Count -gt 1) {
Write-Warning "More than one item within $ZipFileNameWExt matches $searchitem."
Write-Host "Matches include the following:"
for ($i=0; $i -lt $potentialItems.Count; $i++){
"$i) $($($potentialItems[$i]).Path)"
}
$Choice = Read-Host -Prompt "Please enter the number corresponding to the item you would like to extract [0..$($($potentialItems.Count)-1)]"
if ($(0..$($($potentialItems.Count)-1)) -notcontains $Choice) {
Write-Warning "The number indicated does is not a valid choice! Skipping $searchitem..."
continue
}
for ($i=0; $i -lt $potentialItems.Count; $i++){
$shell.Namespace($TargetDir).CopyHere($potentialItems[$Choice], 0x14)
}
}
if ($potentialItems.Count -lt 1) {
Write-Warning "No items within $ZipFileNameWExt match $searchitem! Skipping..."
continue
}
}
}
##### END Main Body #####
}
}
##### END Helper Functions #####
$NeededAssemblies = @("Multiformats.Hash","Multiformats.Base","BinaryEncoding")
foreach ($AssemblyName in $NeededAssemblies) {
New-Item -Type Directory -Path "$HOME\Downloads\$AssemblyName"
$OutFileBaseNamePrep = Invoke-WebRequest "https://www.nuget.org/api/v2/package/$AssemblyName" -DisableKeepAlive -UseBasicParsing
$OutFileBaseName = $($OutFileBaseNamePrep.BaseResponse.ResponseUri.AbsoluteUri -split "/")[-1] -replace "nupkg","zip"
Invoke-WebRequest -Uri "https://www.nuget.org/api/v2/package/$AssemblyName" -OutFile "$HOME\Downloads\$AssemblyName\$OutFileBaseName"
Unzip-File -PathToZip "$HOME\Downloads\$AssemblyName\$OutFileBaseName" -TargetDir "$HOME\Downloads\$AssemblyName" -SpecificItem "lib\net461\$AssemblyName.dll"
Add-Type -Path "$HOME\Downloads\$AssemblyName\$AssemblyName.dll"
}
$publickeythumbprint = "03AF098180F9F37EE3C498476684CDEB60128659"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($publickeythumbprint)
# Below $Source is from https://www.codeproject.com/Tips/76650/Base-base-url-base-url-and-z-base-encoding
$Source = @'
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace MhanoHarkness
{
/// <summary>
/// Base32Url is a standard base 32 encoder/decoder except that padding turned
/// off and it is not case sensitive (by default).
///
/// If you turn padding and case sensitivity on it becomes a standard base32
/// encoder/decoder giving you 8 character chunks right padded with equals symbols.
///
/// If you leave padding off and use Base32Url.ZBase32Alphabet you
/// get a z-base-32 compatible encoder/decoder.
///
/// See http://tools.ietf.org/html/rfc4648
/// For more information see http://en.wikipedia.org/wiki/Base32
/// </summary>
public class Base32Url
{
public const char StandardPaddingChar = '=';
public const string Base32StandardAlphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
public const string ZBase32Alphabet =
"ybndrfg8ejkmcpqxot1uwisza345h769";
public char PaddingChar;
public bool UsePadding;
public bool IsCaseSensitive;
public bool IgnoreWhiteSpaceWhenDecoding;
private readonly string _alphabet;
private Dictionary<string, uint> _index;
// alphabets may be used with varying case sensitivity,
// thus index must not ignore case
private static Dictionary<string, Dictionary<string,
uint>> _indexes = new Dictionary<string, Dictionary<string,
uint>>(2, StringComparer.InvariantCulture);
/// <summary>
/// Create case insensitive encoder/decoder
/// using the standard base32 alphabet without padding.
/// White space is not permitted when decoding (not ignored).
/// </summary>
public Base32Url() : this(false, false, false, Base32StandardAlphabet) { }
/// <summary>
/// Create case insensitive encoder/decoder using the standard base32 alphabet.
/// White space is not permitted when decoding (not ignored).
/// </summary>
/// <param name="padding">
/// Require/use padding characters?</param>
public Base32Url(bool padding) :
this(padding, false, false, Base32StandardAlphabet) { }
/// <summary>
/// Create encoder/decoder using the standard base32 alphabet.
/// White space is not permitted when decoding (not ignored).
/// </summary>
/// <param name="padding">
/// Require/use padding characters?</param>
/// <param name="caseSensitive">
/// Be case sensitive when decoding?</param>
public Base32Url(bool padding, bool caseSensitive) :
this(padding, caseSensitive, false, Base32StandardAlphabet) { }
/// <summary>
/// Create encoder/decoder using the standard base32 alphabet.
/// </summary>
/// <param name="padding">
/// Require/use padding characters?</param>
/// <param name="caseSensitive">
/// Be case sensitive when decoding?</param>
/// <param name="ignoreWhiteSpaceWhenDecoding">
/// Ignore / allow white space when decoding?</param>
public Base32Url(bool padding, bool caseSensitive,
bool ignoreWhiteSpaceWhenDecoding) : this(padding, caseSensitive,
ignoreWhiteSpaceWhenDecoding, Base32StandardAlphabet) { }
/// <summary>
/// Create case insensitive encoder/decoder with alternative alphabet and no padding.
/// White space is not permitted when decoding (not ignored).
/// </summary>
/// <param name="alternateAlphabet">
/// Alphabet to use (such as Base32Url.ZBase32Alphabet)</param>
public Base32Url(string alternateAlphabet) :
this(false, false, false, alternateAlphabet) { }
/// <summary>
/// Create the encoder/decoder specifying all options manually.
/// </summary>
/// <param name="padding">Require/use padding characters?</param>
/// <param name="caseSensitive">
/// Be case sensitive when decoding?</param>
/// <param name="ignoreWhiteSpaceWhenDecoding">
/// Ignore / allow white space when decoding?</param>
/// <param name="alternateAlphabet">Alphabet to use
/// (such as Base32Url.ZBase32Alphabet, Base32Url.Base32StandardAlphabet
/// or your own custom 32 character alphabet string)</param>
public Base32Url(bool padding, bool caseSensitive,
bool ignoreWhiteSpaceWhenDecoding, string alternateAlphabet)
{
if (alternateAlphabet.Length != 32)
{
throw new ArgumentException("Alphabet must be exactly 32 characters long for base 32 encoding.");
}
PaddingChar = StandardPaddingChar;
UsePadding = padding;
IsCaseSensitive = caseSensitive;
IgnoreWhiteSpaceWhenDecoding = ignoreWhiteSpaceWhenDecoding;
_alphabet = alternateAlphabet;
}
/// <summary>
/// Decode a base32 string to a byte[] using the default options
/// (case insensitive without padding using the standard base32 alphabet from rfc4648).
/// White space is not permitted (not ignored).
/// Use alternative constructors for more options.
/// </summary>
public static byte[] FromBase32String(string input)
{
return new Base32Url().Decode(input);
}
/// <summary>
/// Encode a base32 string from a byte[] using the default options
/// (case insensitive without padding
/// using the standard base32 alphabet from rfc4648).
/// Use alternative constructors for more options.
/// </summary>
public static string ToBase32String(byte[] data)
{
return new Base32Url().Encode(data);
}
public string Encode(byte[] data)
{
StringBuilder result = new StringBuilder
(Math.Max((int)Math.Ceiling(data.Length * 8 / 5.0), 1));
byte[] emptyBuff = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] buff = new byte[8];
// take input five bytes at a time to chunk it up for encoding
for (int i = 0; i < data.Length; i += 5)
{
int bytes = Math.Min(data.Length - i, 5);
// parse five bytes at a time using an 8 byte ulong
Array.Copy(emptyBuff, buff, emptyBuff.Length);
Array.Copy(data, i, buff, buff.Length - (bytes+1), bytes);
Array.Reverse(buff);
ulong val = BitConverter.ToUInt64(buff, 0);
for (int bitOffset = ((bytes+1) * 8) - 5; bitOffset > 3; bitOffset -= 5)
{
result.Append(_alphabet[(int)((val >> bitOffset) & 0x1f)]);
}
}
if (UsePadding)
{
result.Append(string.Empty.PadRight((result.Length % 8) == 0 ?
0 : (8 - (result.Length % 8)), PaddingChar));
}
return result.ToString();
}
public byte[] Decode(string input)
{
if (IgnoreWhiteSpaceWhenDecoding)
{
input = Regex.Replace(input, "\\s+", "");
}
if (UsePadding)
{
if (input.Length % 8 != 0)
{
throw new ArgumentException
("Invalid length for a base32 string with padding.");
}
input = input.TrimEnd(PaddingChar);
}
// index the alphabet for decoding only when needed
EnsureAlphabetIndexed();
MemoryStream ms = new MemoryStream
(Math.Max((int)Math.Ceiling(input.Length * 5 / 8.0), 1));
// take input eight bytes at a time to chunk it up for encoding
for (int i = 0; i < input.Length; i += 8)
{
int chars = Math.Min(input.Length - i, 8);
ulong val = 0;
int bytes = (int)Math.Floor(chars * (5 / 8.0));
for (int charOffset = 0; charOffset < chars; charOffset++)
{
uint cbyte;
if (!_index.TryGetValue(input.Substring(i + charOffset, 1), out cbyte))
{
throw new ArgumentException
("Invalid character '" +
input.Substring(i + charOffset, 1) +
"' in base32 string, valid characters are: " + _alphabet);
}
val |= (((ulong)cbyte) <<
((((bytes + 1) * 8) - (charOffset * 5)) - 5));
}
byte[] buff = BitConverter.GetBytes(val);
Array.Reverse(buff);
ms.Write(buff, buff.Length - (bytes + 1), bytes);
}
return ms.ToArray();
}
private void EnsureAlphabetIndexed()
{
if (_index == null)
{
Dictionary<string, uint> cidx;
string indexKey = (IsCaseSensitive ? "S" : "I") + _alphabet;
if (!_indexes.TryGetValue(indexKey, out cidx))
{
lock (_indexes)
{
if (!_indexes.TryGetValue(indexKey, out cidx))
{
cidx = new Dictionary<string, uint>
(_alphabet.Length, IsCaseSensitive ?
StringComparer.InvariantCulture :
StringComparer.InvariantCultureIgnoreCase);
for (int i = 0; i < _alphabet.Length; i++)
{
cidx[_alphabet.Substring(i, 1)] = (uint) i;
}
_indexes.Add(indexKey, cidx);
}
}
}
_index = cidx;
}
}
}
}
'@
$ReferencedAssemblies = @(
"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
"System.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
"System.IO, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
"System.Text.RegularExpressions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
)
Add-Type -ReferencedAssemblies $ReferencedAssemblies -TypeDefinition $Source
$bytes = [System.Text.Encoding]::ASCII.GetBytes($PublicKeyThumbPrint)
$PublicKeyThumbPrintBase32 = [MhanoHarkness.Base32Url]::ToBase32String($bytes)
$keccakDigest = $([Multiformats.Hash.Multihash]::Encode($PublicKeyThumbPrintBase32, "KECCAK_256")).Digest
$keccakDigestHex = [System.BitConverter]::ToString($keccakDigest)
$keccakDigestHex
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment