HMAC SHA256 Powershell convert - powershell

Why does the following powershell script:
$privateKey = "843c1f887b"
$requestData = "1543448572|d.lastname#firm.com|Firstname Lastname"
function signRequest {
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($privateKey)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($requestData))
$signature = [Convert]::ToBase64String($signature)
$outi = $signature
return $signature
}
convert to hash:
FipK51tOtzb2m2yFQAf5IK6BNthClnqE24luMzYMPuo=
and other online hmac sha256 generators with the same input to:
162a4ae75b4eb736f69b6c854007f920ae8136d842967a84db896e33360c3eea
any suggestions what I'm doing wrong in the script?
Thanks!

Your code produces the correct HMAC, you're just base64-encoding it instead of output a hex string like all the other tools.
Change this line
$signature = [Convert]::ToBase64String($signature)
to
$signature = [System.BitConverter]::ToString($signature).Replace('-','').ToLower()
Explanation:
[BitConverter]::ToString($signature) produces a hexadecimal string (16-2A-4A-E7...)
String.Replace('-','') removes the - (162A4AE7...)
String.ToLower() lowercases the final string (162a4ae7...)

Related

How to decrypt the content of a DLC container file via Powershell?

How can I decode the body of a jdownloader *.DLC container file with Powershell?
I have managed to write a small Powershell snippet to decrypt a DLC container file based on the PyLoad code reference.
It prompts for a given file, decrypts the content and puts the URLs into the clipboard.
For the archives here the working sample code:
# script for decoding a DLC-file:
Remove-Variable * -ea 0
$ErrorActionPreference = 'stop'
$utf8 = [System.Text.Encoding]::UTF8
# file selector:
Add-Type -AssemblyName 'System.Windows.Forms'
$browser = [System.Windows.Forms.OpenFileDialog]::new()
$browser.Filter = 'DLC files (*.dlc)|*.dlc'
$browser.InitialDirectory = "$env:USERPROFILE\Downloads"
$null = $browser.ShowDialog()
$fileName = $browser.FileName
if (![System.IO.File]::Exists($fileName)) {break}
$dlc = [System.IO.File]::ReadAllText($fileName)
$len = $dlc.Length
$key = $dlc.Substring($len-88)
$data = $dlc.Substring(0,$len-88)
$bytes = [System.Convert]::FromBase64String($data)
$aesKey = 'cb99b5cbc24db398'
$aesIV = '9bc24cb995cb8db3'
$url = "http://service.jdownloader.org/dlcrypt/service.php?srcType=dlc&destType=pylo&data=$key"
$result = Invoke-WebRequest $url
$rc64 = ([xml]$result.Content).rc
$rc = [System.Convert]::FromBase64String($rc64)
$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Key = $utf8.GetBytes($aeskey)
$aes.IV = $utf8.GetBytes($aesIV)
$aes.Padding = [System.Security.Cryptography.PaddingMode]::None
$dec = $aes.CreateDecryptor()
$result = $dec.TransformFinalBlock($rc, 0, $rc.Length)
$dec.Dispose()
$aes.key = $result
$aes.IV = $result
$dec = $aes.CreateDecryptor()
$enc = $dec.TransformFinalBlock($bytes, 0, $bytes.Length)
$dec.Dispose()
$b64 = $utf8.GetString($enc).Trim([char]0)
$byte = [System.Convert]::FromBase64String($b64)
$xml = [xml]$utf8.GetString($byte)
$urlList = foreach($url64 in $xml.dlc.content.package.file.url) {
$urlb = [System.Convert]::FromBase64String($url64)
$utf8.GetString($urlb)
}
cls
$urlList | Set-Clipboard
$urlList
Here is also a short demo how to encode any text into a DLC-format:
# DLC-encryption:
# get a random encryption key (RCP):
$bytes = [System.Security.Cryptography.Rfc2898DeriveBytes]::new($null,8)
$hexbin = [System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary]::new($bytes.Salt)
$rcp = $hexbin.ToString().ToLower()
# let jdownloader generate an RC-value for this key:
$url = "http://service.jdownloader.org/dlcrypt/service.php?jd=1&srcType=plain&data=$rcp"
$result = Invoke-WebRequest $url
$rc = ([xml]"<xml>$($result.Content)</xml>").xml.rc
# if we store the rcp/rc-pair, then we could decode a DLC in offline mode
# encode any information with our initial key:
$data = 'something to encode'
$bytes = $utf8.GetBytes($data)
$aes = [System.Security.Cryptography.Aes]::Create()
$rcb = $utf8.GetBytes($rcp)
$aes.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
$enc = $aes.CreateEncryptor($rcb, $rcb)
$out = $enc.TransformFinalBlock($bytes, 0, $bytes.Length)
$enc.Dispose()
# the DLC-content is a concatenation of the base64-string of the encrypted data
# plus the base64-string of the RC which corresponds to our initial RCP-key.
$data = [System.Convert]::ToBase64String($out)
write-host "$data$rc"
And here a correct XML-format of a decrypted DLC container. All(!) shown values here (strings/numbers/dates) must be in base64-format. I just decoded them all to make it a bit easier to understand them. Some elements or values might be optional, some may be subject of change. I have not tested that in details. It is just a readable format of a single DLC-file I created with JDownloader:
<dlc>
<header>
<generator>
<app>JDownloader</app>
<version>43307</version>
<url>http://jdownloader.org</url>
</generator>
<tribute/>
<dlcxmlversion>20_02_2008</dlcxmlversion>
</header>
<content>
<package category="various" comment="" name="Packagename">
<file>
<url>http://appwork.org/projects/DLCAPI/dlcapi_v1.0.rar</url>
<filename>dlcapi_v1.0.rar</filename>
<size>5838</size>
</file>
</package>
</content>
</dlc>

Powershell SHA-1 and base64 encode

Try to generate sha1 base64 hash of an empty string in powershell
$enc = [system.Text.Encoding]::UTF8
$string = ""
$data=$enc.GetBytes($string)
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$ResultHash = $sha1.ComputeHash($data)
$str_out = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($ResultHash))
write-host $str_out
result is
MjE4IDU3IDE2MyAyMzggOTQgMTA3IDc1IDEzIDUwIDg1IDE5MSAyMzkgMTQ5IDk2IDI0IDE0NCAxNzUgMjE2IDcgOQ==
and I should have received
2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Please could someone advice?
The output from ComputeHash is already a byte array, not a string - [Text.Encoding]::UTF8.GetBytes($ResultHash) makes no sense here.
Remove that part and it'll work as expected:
$enc = [system.Text.Encoding]::UTF8
$string = ""
$data=$enc.GetBytes($string)
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$ResultHash = $sha1.ComputeHash($data)
$str_out = [Convert]::ToBase64String($ResultHash)
write-host $str_out
Your expected encoded base64 string is not UTF-8 encoded.
If you want to get 2jmj7l5rSw0yVb/vlWAYkK/YBwk= you have to replace :
$str_out = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($ResultHash))
by
$str_out = [Convert]::ToBase64String($ResultHash)

Generate HMAC SHA256 signature Powershell

For 3commas I tried to generate a HMAC SHA256 signature in Powershell with the example parameters from the documentation:
$secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'
$message = '/public/api/ver1/accounts/new?type=binance&name=binance_account&api_key=XXXXXX&secret=YYYYYY'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
$signature
It generates "MPZ4oVcjApDgBHXP/8y8kq42WdlMFFosDp0Poo9BwRo="
As described in the documentation it should generate "30f678a157230290e00475cfffccbc92ae3659d94c145a2c0e9d0fa28f41c11a"
[linux]$ echo -n "/public/api/ver1/accounts/new?type=binance&name=binance_account&api_key=XXXXXX&secret=YYYYYY" | openssl dgst -sha256 -hmac "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
(stdin)= 30f678a157230290e00475cfffccbc92ae3659d94c145a2c0e9d0fa28f41c11a
Can anyone help me out?
Use the BitConverter class.
$secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'
$message = '/public/api/ver1/accounts/new?type=binance&name=binance_account&api_key=XXXXXX&secret=YYYYYY'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature1 = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
#$signature2 = [Convert]::ToBase64String($signature1)
[System.BitConverter]::ToString($signature1) -replace '-', ''

Encoding AWS Affiliate API String with PS gives wrong hash

From the following guide in AWS I need to generate an HMAC SHA256 Signature:
http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
My code is as follows:
$message = 'GET
webservices.amazon.com
/onca/xml
AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=2014-08-18T12%3A00%3A00Z&Version=2013-08-01'
$secret = '1234567890'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
echo $signature
# Do we get the expected signature?
echo ($signature -eq 'j7bZM0LXZ9eXeZruTqWm2DIvDYVUU3wxPPpp+iXxzQc=')
Unfortunately I do not get the same hash as AWS does in it's example. What did I miss?
I got it eventually.
It had something to do with the line breaks:
$message = "GET`nwebservices.amazon.com`n/onca/xml`nAWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=2014-08-18T12%3A00%3A00Z&Version=2013-08-01"

Why does this new JObject strangely change my string when adding to it?

I have a PowerShell script, whose objective is to convert an incoming JSON object into a different sort of JSON object. (The "why" falls outside of the scope of this question.) The script (so far) is below (URL is obfuscated and will not work):
function Map-TempStudents {
param($uffStudent) # JObject containing UFF-formatted student
[String]$districtCode = $uffStudent.Item("DistrictCode").ToString()
Write-Host "districtCode = " $districtCode
$tempStudent = New-Object -TypeName Newtonsoft.Json.Linq.JObject
$tempStudent.Add("DistrictNum", $uffStudent.Item("DistrictCode").ToString())
Write-Host "tempStudent(DistrictNum) = " $tempStudent.Item("DistrictNum").ToString()
}
$currentPath = Split-Path -parent $MyInvocation.MyCommand.Definition
$jsonNetPath = $currentPath + '\Newtonsoft.Json.dll'
Add-Type -Path $jsonNetPath
$wc = New-Object system.Net.WebClient;
$studentPersonal = $wc.downloadString("http://test.foo.org/StudentPersonal")
$json = [Newtonsoft.Json.Linq.JObject]::Parse($studentPersonal)
$studentPersonal | Out-File "test.txt" # DEBUG
$studentBases = $json.Item("Data").Item("AssignTeacher")
Map-TempStudents -uffStudent $studentBases[0]
Running this script gives the following output:
districtCode = 0745
tempStudent(DistrictNum) = 485
To be clear, "0745" is the correct value, and "485" is the unexpected value.
I would expect tempStudent(DistrictNum) to be "0745" as well.
Why would this value change like this?
I was able to reproduce your issue with the following script (assuming Newtonsoft.Json.dll is already loaded into PowerShell):
$jo = New-Object -TypeName Newtonsoft.Json.Linq.JObject
$jo.Add("foo", "0745")
Write-Host $jo.Item("foo").ToString()
The Add method on JObject accepts an object as its second argument. If you pass a numeric string with a leading zero (and all the digits are less than 8), it is interpreted as an octal number. Hence "0745" gets converted into "485". This must be a PowerShell thing, because the equivalent code in C# works correctly:
JObject jo = new JObject();
jo.Add("foo", "0745");
Console.WriteLine(jo["foo"].ToString());
To prevent the unwanted conversion in PowerShell, wrap your string in a JValue before passing it to JObject.Add(), e.g.:
$jval = New-Object -TypeName Newtonsoft.Json.Linq.JValue -ArgumentList "0745"
$jo.Add("foo", $jval)
Here is the corrected Map-TempStudents function:
function Map-TempStudents {
param($uffStudent) # JObject containing UFF-formatted student
$districtCode = New-Object -TypeName Newtonsoft.Json.Linq.JValue -ArgumentList $uffStudent.Item("DistrictCode").ToString()
Write-Host "districtCode = " $districtCode.ToString()
$tempStudent = New-Object -TypeName Newtonsoft.Json.Linq.JObject
$tempStudent.Add("DistrictNum", $districtCode)
Write-Host "tempStudent(DistrictNum) = " $tempStudent.Item("DistrictNum").ToString()
}