Creating correct SHA256 hash in Powershell - powershell

Good evening everybody. I have a problem with sha256 Hash.
I have this example string from the amazon pages:
GET
/
Action=ListUsers&Version=2010-05-08
content-type:application/x-www-form-urlencoded; charset=utf-8
host:iam.amazonaws.com
x-amz-date:20150830T123600Z
content-type;host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Amazon shows the hash result of this example string
as the following:
**f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59**
The description is: this one: The hashed canonical request must be represented as a string of lowercase hexadecimal characters. The following example shows the result of using SHA-256 to hash the example canonical request.
Example Hashed canonical request
No matter what i do, i receive this hash:
B51325A14138B31939381CB391819CE8A5F09DEEA778721C4360F0DAC1FAB79C
Here are 3 example codes:
function hash($request) {
$sha256 = new-object -TypeName System.Security.Cryptography.SHA256Managed
$utf8 = new-object -TypeName System.Text.UTF8Encoding
$hash = [System.BitConverter]::ToString($sha256.ComputeHash($utf8.GetBytes($request)))
return $hash.replace('-','').toLower()
}
function hash2($request){
$mystream = [IO.MemoryStream]::new([byte[]][char[]]$request)
$hash = Get-FileHash -InputStream $mystream -Algorithm SHA256
$hash = $hash.Hash
return $hash.toLower()
}
function hash3($request)
{
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
$hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($request))
$hashString = [System.BitConverter]::ToString($hash)
$hash = $hashString.Replace('-', '')
return $hash.toLower()
}
$string = "GET
/
Action=ListUsers&Version=2010-05-08
content-type:application/x-www-form-urlencoded; charset=utf-8
host:iam.amazonaws.com
x-amz-date:20150830T123600Z
content-type;host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
hash $string
hash2 $string
hash3 $string
The only online calculator i found which calculates the same hash as amazon was this one: https://xorbin.com/tools/sha256-hash-calculator
Here is the original conent from amazon: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
Can anyone help, please?
Best regards
Patrick

At first I couldn't reproduce this behavior by copy-pasting your code. Then I pasted it into an editor configured to save all linebreaks as CRLF - at which point I also got B51325A14138B31939381CB391819CE8A5F09DEEA778721C4360F0DAC1FAB79C.
So the likely explanation is that you wrote your script in an editor that saves all files with Windows-style line breaks.
You can work around this by replacing all Windows style linebreaks in the resulting string value with a single newline character at runtime:
hash $string.Replace("`r`n", "`n")

To complement Mathias R. Jessen's helpful answer:
It is the newline format (Windows CRLF vs. Unix LF) of the enclosing script file (.ps1) that determines the newline format of multiline string literals contained in the script (including here-string literals).
An alternative to explicitly replacing the CRLF sequences with LFs, as shown in Mathias' answer, is to re-save your .ps1 file with LF newlines (PowerShell won't mind).
For better cross-platform compatibility, consider configuring your editor to create LF-format PowerShell scripts by default.

Related

Can Powershell return complete interpolated values using convertfrom-stringdata

I have a .properties file with the following properties in them:
repository.host=hostname.com/nexus
repository.api.url=https://${repository.host}/service/rest/v1
repository.url=https://${repository.host}/repository
I am able to return the values using the following powershell function:
static [string] getProperty( [string] $property ){
$properties = "../resources/vars/$([jenkins]::PROPERTIES_FILE)"
$properties = get-content $properties | convertfrom-stringdata
return $properties.$property
}
When attempting to return the property repository.url powershell return this string: https://${repository.host}/repository/
My question is: Is it possible through features that already exist in powershell for the returned string to be https://hostname.com/nexus/repository/?
By design, for security reasons, ConvertFrom-StringData does not perform string expansion (interpolation) on its input.
Assuming you trust the input string[1], you can perform the expansion on demand, after having read the values from the file.
Note that use of ConvertFrom-StringData is problematic, as you've discovered, because the hashtable it creates invariably has unordered keys; that is, the order of the entries does not reflect the order in which the properties are defined in the file.
Therefore, processing the hashtable entries can make the on-demand expansion fail, if an out-of-order entry is processed before another entry whose value it needs for the expansion.
The solution is to roll your own ConvertFrom-StringData variant[2] that reads the properties into an ordered hashtable.
This additionally allows you to combine the read-from-file and expansion-on-demand tasks:
# Create a sample properties file.
#'
repository.host=hostname.com/nexus
repository.api.url=https://${repository.host}/service/rest/v1
repository.url=https://${repository.host}/repository
'# > sample.properties
# Parse the file and build an *ordered* hashtable from it.
$orderedHash = [ordered] #{}
switch -Regex -File sample.properties {
'^\s*#|^\s*$' { continue } # skip comment and blank lines.
default {
# Determine the key and value...
$key, $value = $_ -split '=', 2
# ... and create the entry while expanding ${...} references to previous
# entries.
$orderedHash[$key.Trim()] = $ExecutionContext.InvokeCommand.ExpandString((
$value.Trim() -replace '\$\{([^}]+)\}', '$$($$orderedHash[''$1''])'
))
}
}
# Output the result.
$orderedHash
Note the use of method $ExecutionContext.InvokeCommand.ExpandString to perform on-demand string expansion (interpolation); since this method isn't easy to discover, GitHub issue #11693 proposes that this functionality be surfaced as a proper, easily discoverable cmdlet named something like Expand-String or Expand-Template.
Note: In order to be able to use $ExecutionContext from the method of a PS custom class, you must explicitly reference it in the global scope via $global:ExecutionContext.
For more information about the regex-based -replace operator, see this answer.
The above yields (note that the input order was maintained):
Name Value
---- -----
repository.host hostname.com/nexus
repository.api.url https://hostname.com/nexus/service/rest/v1
repository.url https://hostname.com/nexus/repository
[1] Via $(), the subexpression operator, it is possible to embed arbitrary commands in the input strings.
[2] The code below does not replicate all features of ConvertFrom-String data, but it works with the sample input. While it does support skipping comment lines (those whose first non-whitespace character is a #) and blank lines, treating \ as escape characters and supporting escape sequences such as \n for a newline is not implemented.
The original solution provided by #mklement0 was very useful, and has guided me towards a more complete solution. This solution accomplishes/corrects a couple of things:
The ability to create the hashtable from a file source.
The ability to access the $ExecutionContext variable from within a class method, using the $global: scope.
The ability to thoroughly parse all keys within the hashtable.
static [string] getProperties ( [string] $file, [string] $property ){
$properties = get-content $file -raw | convertfrom-stringdata
while ( $properties.values -match '\$\{([^}]+)\}' ){
foreach ($key in #($properties.Keys)) {
$properties[$key] = $global:ExecutionContext.InvokeCommand.ExpandString( ($properties[$key] -replace '\$\{([^}]+)\}', '$$($$properties[''$1''])') )
}
}
return $properties[$property]
}
Note: When the while loop is not present and searching matches of ${*}, any given returned value may not be completely interpolated or expanded. As an example without the while loop present output from a file may look like this:
/nexus
${nexus.protocol}://${nexus.hostname}:${nexus.port}${nexus.context}
${nexus.protocol}://${nexus.hostname}:${nexus.port}${nexus.context}/repository/installers/com/amazon/java/8.0.252/java-1.8.0-amazon-corretto-devel-1.8.0_252.b09-1.x86_64.rpm
${nexus.protocol}://${nexus.hostname}:${nexus.port}${nexus.context}
${nexus.protocol}://${nexus.hostname}:${nexus.port}${nexus.context}/repository/installers/com/oracle/tuxedo/12.1.3.0.0/p30596495_121300_Linux-x86-64.zip
443
https://hostname.com:443/nexus
https://hostname.com:443/nexus/repository/installers/com/oracle/java/jdk/8u251/jdk-8u251-linux-x64.rpm
https://hostname.com:443/nexus/repository/installers/com/oracle/weblogic/12.2.1.3.0/p30965714_122130_Generic.zip
hostname.com
https
https://hostname.com:443/nexus/repository/installers/com/oracle/weblogic/12.2.1.3.0/p30965714_122130_Generic.zip
And if you were to run the same script again (still without the while loop) would look like this:
hostname.com
https://hostname.com:443/nexus
/nexus
https://hostname.com:443/nexus
https://hostname.com:443/nexus
https://hostname.com:443/nexus/repository/installers/com/oracle/weblogic/12.2.1.3.0/p30965714_122130_Generic.zip
https://${nexus.hostname}:443/nexus/repository/installers/com/oracle/java/jdk/8u251/jdk-8u251-linux-x64.rpm
https://hostname.com:443/nexus/repository/installers/com/oracle/tuxedo/12.1.3.0.0/p30596495_121300_Linux-x86-64.zip
https://hostname.com:443/nexus/repository/installers/com/amazon/java/8.0.252/java-1.8.0-amazon-corretto-devel-1.8.0_252.b09-1.x86_64.rpm
443
https
https://${nexus.hostname}:443/nexus/repository/installers/com/oracle/weblogic/12.2.1.3.0/p30965714_122130_Generic.zip
The reason for the sometimes incompletely interpolated/expanded strings is because hashtables are naturally unordered. With the introduction of the while loop, results will not be returned until all interpolated/expanded strings are resolved.
The official output would look as such:
hostname.com
https://hostname.com:443/nexus
/nexus
https://hostname.com:443/nexus
https://hostname.com:443/nexus
https://hostname.com:443/nexus/repository/installers/com/oracle/weblogic/12.2.1.3.0/p30965714_122130_Generic.zip
https://hostname.com:443/nexus/repository/installers/com/oracle/java/jdk/8u251/jdk-8u251-linux-x64.rpm
https://hostname.com:443/nexus/repository/installers/com/oracle/tuxedo/12.1.3.0.0/p30596495_121300_Linux-x86-64.zip
https://hostname.com:443/nexus/repository/installers/com/amazon/java/8.0.252/java-1.8.0-amazon-corretto-devel-1.8.0_252.b09-1.x86_64.rpm
443
https
https://hostname.com:443/nexus/repository/installers/com/oracle/weblogic/12.2.1.3.0/p30965714_122130_Generic.zip

How to cut specific string?

I have a string with different length. I want to cut a specific word in my string.
Please help, I am new to PowerShell.
I tried this code, it's still not what I need.
$String = "C:\Users\XX\Documents\Data.txt"
$Cut = $String.Substring(22,0)
$Cut
My expectation is that I can return the word Data.
Assuming the string is always the same format (i.e. a path ending in a filename), then there are quite a few ways to do this, such as using regular expressions. Here is a slightly less conventional method:
# Define the path
$filepath = "C:\Users\XX\Documents\Data.txt"
# Create a dummy fileinfo object
$fileInfo = [System.IO.FileInfo]$filePath
# Get the file name property
$fileInfo.BaseName
Of course, you could do all of this in one step:
([System.IO.FileInfo]"C:\Users\XX\Documents\Data.txt").BaseName
If the path is an existing one, you could use
(Get-Item $String).BaseName
Otherwise
(Split-Path $String -Leaf) -Replace '\.[^\.]*$'
While in that specific example the simplest way is to use Substring(startPosition,length) to extract file name you'd probably want to use something like this:
(("C:\Users\XX\Documents\Data.txt".split("\\"))[-1].Split("."))[0]
Explanation:
("C:\Users\XX\Documents\Data.txt".split("\\"))[-1]
that part split the path by \ and returns last item (escaping it seems to be not mandatory by the way so you can use .split("\") instead of .split("\\")). From it you receive Data.txt so you have to separate name and extension. You can do this by splitting by . and choosing first element returned
There are number of ways of doing it depending upon your input -
Method 1 - Hard-coding using the sub-string function.
$String = "C:\Users\XX\Documents\Data.txt"
$Cut = $String.Substring(22,4)
$Cut
The above approach will work for a single input but will become difficult to manage for multiple inputs of different lengths.
Method 2 - Using the split method
$String = "C:\Users\XX\Documents\Data.txt"
$cut = $String.Split("\")[-1].split(".")[0]
$cut
Split method will split string into substring. The index [-1] will return the last value returned by the split method.
The second split is to return the word Data from the word Data.txt.
Method 3 - If the input is a file path
$string = Get-ChildItem $env:USERPROFILE\Desktop -File | select -First 1
$Cut = $String.BaseName
More about method 3 here.
If you can use Powershell 6 - SplitPath
#Requires -Version 6.0
Split-Path $String -LeafBase

In PowerShell, how do I copy the last alphabet characters from a string which also has numbers in it to create a variable?

For example if the string is blahblah02baboon - I need to get the "baboon" seperated from the rest and the variable would countain only the characters "baboon". Every string i need to do this with has alphabet characters first then 2 numbers then more alphabet characters, so it should be the same process everytime.
Any advice would be greatly appreciated.
My advice is to learn about regular expressions.
'blahblah02baboon' -replace '\D*\d*(\w*)', '$1'
Or use regex
$MyString = "01baaab01blah02baboon"
# Match any character which is not a digit
$Result = [regex]::matches($MyString, "\D+")
# Take the last result
$LastResult = $Result[$Result.Count-1].Value
# Output
Write-Output "My last result = $LastResult"

Remove first and last three character of a word with powershell

I have a list of users in a text file who's names are in the following format: xn-tsai-01.
How do I script to remove the xn- KEEP THIS -01 so the output is like: tsai
I know how to do this in bash but not too familiar with powershell.
Thanks in advance!
Why not use Substring method. If you will always trim the first three characters, you can do the following assuming the variable is a string type.
$string = xn-tsai-01
$string.Substring(3)
Here is a quick way to do it using regex:
'xn-tsai-01' -replace '.*?-(.*)-.*','$1'
Example with a list:
(Get-Content list.txt) -Replace '.*?-(.*)-.*','$1'
You can use the .NET string method IndexOf("-") to find the first, and LastIndexOf("-") to find the last occurrence of "-" within the string.
Use these indexes with Substring() to remove the unnecessary parts:
function Clean-Username {
param($Name)
$FirstDash = $Name.IndexOf("-") + 1
$LastDash = $Name.LastIndexOf("-")
return $Name.Substring( $f, $l - $f )
}
PS C:\> Clean-UserName -Name "xn-tsai-01"
tsai
Boe's example is probably going to be the most efficient.
Another way is to use the split() method if they're in a uniform format.
Get-Content .\list.txt | % { ($_.Split('-'))[1] }
% is an alias for ForEach

how do I replace a string with a dollar sign in it in powershell

In Powershell given the following string
$string = "this is a sample of 'my' text $PSP.what do you think"
how do I use the -replace function to convert the string to
this is a sample of 'my' text Hello.what do you think
I obviously need to escape the string somehow, Also $PSP is not a declared variable in my script
I need to change all mentions of $PSP for some other string
Use the backtick character (above the tab key):
$string = "this is a sample of 'my' text `$PSP.what do you think"
To replace the dollar sign using the -replace operator, escape it with backslash:
"this is a sample of 'my' text `$PSP.what do you think" -replace '\$PSP', 'hello'
Or use the string.replace method:
$string = "this is a sample of 'my' text `$PSP.what do you think"
$string.Replace('$PSP','Hello)'
this is a sample of 'my' text Hello.what do you think
Unless you modify your original string (e.g. by escaping the $), this is isn't (really) possible.
Your $string doesn't really contain a $PSP, as it is replaced by nothing in the assignment statement.
$string = "this is a sample of 'my' text $PSP.what do you think"
$string -eq "this is a sample of 'my' text .what do you think"
evaluates to:
True
This comes up as the first answer in google even though it is really old, so I will add my slight variation.
In my case I was reading in a file and replacing a string with $s in it.
The short version of my file is:
<version>$version$<version>
In the case where one is actiong on a (file) stream, variables are not autoreplaced so there is no need to escape the $ in the file.
In the replacement pattern you can avoid the interpretation of the variable using ' instead of ".
My final command looked like:
(gc $fileName) | % { $_.replace('$version$', "$BuildNumber") } | sc $fileName
This is a file read(get-content) piped through the replace and back in to the file with a set-content.
You should try
$string = $string.Replace("\$PSP", "Hello")
or
$string = $string.Replace("\$PSP", $the_new_value)
or to be more generic use Regex
$string = [regex]::Replace($string, "\$\w+", "Hello")