[.NET] TransIP API OpenSSL /Base64 hash aanmaken gaat mis.

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • The-Source
  • Registratie: Augustus 2001
  • Laatst online: 10:55
Mijn vraag
Wanneer ik via powershell openssl.exe aanroep wordt er een binary hash aangemaakt. Maar in de API beschrijving wordt ASN hash benoemd, Als ik binary hash naar base64 encodeer lijkt dat totaal niet op de hex hash die je normaal ziet. En geeft dan ook een invalid input retour

Relevante software en hardware die ik gebruik
Powershell

Wat ik al gevonden of geprobeerd heb
Met de volgende code maak is via een Start-Proces commando een hash file aan (openssl1.1.1 en openSSL3 geven dezelfde output)
code:
1
.\openssl.exe dgst -sha512 -sign priv.pem -out output.txt body.txt

Vervolgens met
code:
1
.\openssl.exe dgst -sha512 -prverify priv.pem -signature output.txt body.txt

Krijgt ik verification OK
Met commando openssl.exe dgst -sha512 -hex kan ik de verify niet uitvoeren maar dat staat ook in de documentatie dat dit niet werkt.
Maar ik voer dus in mijn script volgende uit:
code:
1
.\openssl.exe dgst -hex -sha512 -sign priv.pem -out output.txt body.txt

Output.txt bevat wat additionele tekst als in RSA-SHA2-512(body.txt)= hexkey
Hex key is 512 karakters lang want aan de verwachting voldoet ;)
Maar nu, volgende de transIP-API zou ik deze hexkey naar base64 moeten omzetten.
Dat geeft dan vervolgens een 'string' van 1369 karakters (laatste 2 zijn ==)
Maar het gekke is als ik die van Notepad++ Base64 decode doe dit totaal niet meer lijkt op de originele data.
UTF8 encoding lost dit op.
SHA512 string(begin hexkey): 173211a1d2984b
Base64 origineel(begin):MQA3ADMAMgAxADEAYQAxAGQAMgA5ADgANABiAG
Base64 decode(begin van lange string spaties zijn in n++ NUL vakjes): 1 7 3 2 1 1 a 1 d 2 9 8 4 b opgelost met UTF8
Maar ook in het voorbeeld van TransIP is mijn base64 string ook +/- dubbel in lengte
Code om van SHA512 naar base64 te gaan
code:
1
2
3
4
5
6
7
$signature = Get-Content "output.txt" -Raw
$startchar = $signature.Length -514
$signature = $signature.Substring($startchar,512)
$signature = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($signature))
$authURL = 'https://api.transip.nl/v6/auth'
$Headers = @{ Authorization = $signature  }
$token = Invoke-WebRequest -URI $authURL -Headers $Headers -Body $Authbody -Method Post


Als ik alles uitvoer in visual studio Code dan krijg ik de volgende error:
code:
1
2
3
4
5
6
Invoke-WebRequest: TransIP.ps1:51:14
Line |
  51 |  …   $token = Invoke-WebRequest -Uri $authURL -Headers $Headers -Body $ …
     |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The format of value 'Signature:
     | MwAyADEAMQBhADEAZAADYADQAKAA==' is invalid.


Als ik de invoke-webrequest vanuit los Powershell scherm doet krijg ik een 401 (niet gemachtigd retour), dan weet in ieder geval dat er iets niet klopt in mijn waardes maar hier lijkt er iets anders mis te gaan.

Zie ik iets basaal over het hoofd en zo ja wat ;)

Taal fouten inbegrepen ;)
Mijn AI Art YouTube kanaal

Beste antwoord (via The-Source op 10-08-2023 09:30)


  • Killah_Priest
  • Registratie: Augustus 2001
  • Laatst online: 10:36
Sowieso zou het gehele proces zonder openssl moeten kunnen (de dotnet classes voor oa x509 certificaten maar ook de losse SHA classes voldoen om een hash mee te genereren).
Maar even voor mijn duidelijk: wat voor content komt er in de textfile te staan?

Uit het voorbeeld maak ik op dat het een hex representatie van de data is in een string formaat: dit simpelweg inlezen zonder de data eerst weer om te zetten naar bytes gaat niet werken: je encode dan namelijk de string waarde (omgezet naar bytes) naar base64.
Je zou OF je output binary moeten wegschrijven en dan dmv Get-Content -Path <path> -Encoding Byte moeten doen om de boel gewoon als een byte array in te lezen (welke je vervolgens gewoon zo om kunt zetten naar Base64 zonder [System.Text.Encoding] aan te roepen aangezien het al bytes zijn), OF de hexdata per 2 "string" karakters om moeten zetten naar een byte.


Update: even een simpele sample geschreven in Powershell waarmee ik een token op kan vragen als ik mijn eigen username invul.
Dit werkt wel alleen in PS7 ivm de RSA class die in dotnet 4.x geen ImportFromPem method heeft (en ik geen zin had om de PEM zelf te parsen).

In de body kun je je eigen username invullen, path naar je PEM file aanpassen en klaar. Geen externe libraries oid nodig.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<#
    Login voor TransIP.
    Dit voorbeeld werkt alleen in PSCore edities ivm Dotnet Core
#>

# Request body
$Body = @'
{
    "login": "userName",
    "nonce": "98475920834",
    "read_only": false,
    "expiration_time": "30 minutes",
    "label": "add description",
    "global_key": true
}
'@
$BodyBytes = [System.Text.Encoding]::UTF8.GetBytes($Body)
# lees de PEM file in
$PEMContent = Get-Content -Path 'C:\test\transip\test1PK.pem' -Raw

# importeer de PEMFile
$RSA = [System.Security.Cryptography.RSA]::Create()
$RSA.ImportFromPem($PEMContent)

# sign de data, SHA512 en Pkcs1
$signature = $RSA.SignData($BodyBytes,'SHA512',[System.Security.Cryptography.RSASignaturePadding]::Pkcs1)

# encode de signature naar Base64
$B64Sig = [System.Convert]::ToBase64String($signature)

# Http header
$header = @{
    Signature = $B64Sig
    }

$authurl = 'https://api.transip.nl/v6/auth'

# maak de request
$Response = Invoke-WebRequest -Uri $authurl -Headers $header -Body $Body -Method Post -ContentType application/json

[ Voor 45% gewijzigd door Killah_Priest op 09-08-2023 21:59 ]

Alle reacties


Acties:
  • 0 Henk 'm!

  • OnTracK
  • Registratie: Oktober 2002
  • Laatst online: 18:43
Klinkt alsof je string in UTF-16 (of UCS-2) encoding staat, de standaard encoding van Windows. Waarbij iedere letter (minimaal) 2 bytes inneemt. Kijk eerst met een text-editor zoals Sublime wat deze ziet als encoding.

Aangezien je string alleen uit 0-9a-f bestaat kun je hem denk ik d.m.v. ASCIIEncoding.GetBytes interpreteren als 8-bit tekenset.

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties:
  • 0 Henk 'm!

  • The-Source
  • Registratie: Augustus 2001
  • Laatst online: 10:55
OnTracK schreef op woensdag 9 augustus 2023 @ 16:16:
Klinkt alsof je string in UTF-16 (of UCS-2) encoding staat, de standaard encoding van Windows. Waarbij iedere letter (minimaal) 2 bytes inneemt. Kijk eerst met een text-editor zoals Sublime wat deze ziet als encoding.

Aangezien je string alleen uit 0-9a-f bestaat kun je hem denk ik d.m.v. ASCIIEncoding.GetBytes interpreteren als 8-bit tekenset.
code:
1
$signature = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signature))

Lijkt in ieder geval 1 deel van het probleem op te lossen (de gekke NUL karakters in n++)
De error melding op invoke webrequest blijft ongewijzigd.

Taal fouten inbegrepen ;)
Mijn AI Art YouTube kanaal


Acties:
  • 0 Henk 'm!

  • MatHack
  • Registratie: Oktober 2001
  • Niet online

MatHack

Dev by day, Gamer by night

De error is over 2 regels, kan het zijn dat er een CR/LF staat op een plek wat een single-line string hoort te zijn?

EDIT: Ik neem aan dat de base512 -> base64 code is veranderd nadat je UTF8 hebt toegepast?

[ Voor 32% gewijzigd door MatHack op 09-08-2023 16:54 ]

There's no place like 127.0.0.1


Acties:
  • +1 Henk 'm!

  • OnTracK
  • Registratie: Oktober 2002
  • Laatst online: 18:43
Waarom voeg je eigenlijk die -hex toe aan het openssl commando? Dat zie ik nergens in de documentatie die je linkt. Het is ook niet erg typisch om hex output nog een keer te base64_encoden. Terwijl het wel logisch is binary output te base64_encoden.

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties:
  • 0 Henk 'm!

  • OnTracK
  • Registratie: Oktober 2002
  • Laatst online: 18:43
Ook zegt de documentatie dat je een header
code:
1
Signature: xxx
moet toevoegen. Maar in je voorbeeld doe je een header
code:
1
Authorization: xxx
?

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • Killah_Priest
  • Registratie: Augustus 2001
  • Laatst online: 10:36
Sowieso zou het gehele proces zonder openssl moeten kunnen (de dotnet classes voor oa x509 certificaten maar ook de losse SHA classes voldoen om een hash mee te genereren).
Maar even voor mijn duidelijk: wat voor content komt er in de textfile te staan?

Uit het voorbeeld maak ik op dat het een hex representatie van de data is in een string formaat: dit simpelweg inlezen zonder de data eerst weer om te zetten naar bytes gaat niet werken: je encode dan namelijk de string waarde (omgezet naar bytes) naar base64.
Je zou OF je output binary moeten wegschrijven en dan dmv Get-Content -Path <path> -Encoding Byte moeten doen om de boel gewoon als een byte array in te lezen (welke je vervolgens gewoon zo om kunt zetten naar Base64 zonder [System.Text.Encoding] aan te roepen aangezien het al bytes zijn), OF de hexdata per 2 "string" karakters om moeten zetten naar een byte.


Update: even een simpele sample geschreven in Powershell waarmee ik een token op kan vragen als ik mijn eigen username invul.
Dit werkt wel alleen in PS7 ivm de RSA class die in dotnet 4.x geen ImportFromPem method heeft (en ik geen zin had om de PEM zelf te parsen).

In de body kun je je eigen username invullen, path naar je PEM file aanpassen en klaar. Geen externe libraries oid nodig.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<#
    Login voor TransIP.
    Dit voorbeeld werkt alleen in PSCore edities ivm Dotnet Core
#>

# Request body
$Body = @'
{
    "login": "userName",
    "nonce": "98475920834",
    "read_only": false,
    "expiration_time": "30 minutes",
    "label": "add description",
    "global_key": true
}
'@
$BodyBytes = [System.Text.Encoding]::UTF8.GetBytes($Body)
# lees de PEM file in
$PEMContent = Get-Content -Path 'C:\test\transip\test1PK.pem' -Raw

# importeer de PEMFile
$RSA = [System.Security.Cryptography.RSA]::Create()
$RSA.ImportFromPem($PEMContent)

# sign de data, SHA512 en Pkcs1
$signature = $RSA.SignData($BodyBytes,'SHA512',[System.Security.Cryptography.RSASignaturePadding]::Pkcs1)

# encode de signature naar Base64
$B64Sig = [System.Convert]::ToBase64String($signature)

# Http header
$header = @{
    Signature = $B64Sig
    }

$authurl = 'https://api.transip.nl/v6/auth'

# maak de request
$Response = Invoke-WebRequest -Uri $authurl -Headers $header -Body $Body -Method Post -ContentType application/json

[ Voor 45% gewijzigd door Killah_Priest op 09-08-2023 21:59 ]


Acties:
  • +1 Henk 'm!

  • The-Source
  • Registratie: Augustus 2001
  • Laatst online: 10:55
OnTracK schreef op woensdag 9 augustus 2023 @ 17:42:
Waarom voeg je eigenlijk die -hex toe aan het openssl commando? Dat zie ik nergens in de documentatie die je linkt. Het is ook niet erg typisch om hex output nog een keer te base64_encoden. Terwijl het wel logisch is binary output te base64_encoden.
Ik zet het naar HEX omdat er juist over ASN formaat gesproken wordt.
The signature header should consist of a sha512 asn.1 hash of the full request body, sign using a private key that was generated in the control panel and base64 encode the generated signature
Verwarrende met ASN formaat is dat deze zou moeten beginnen met -----wat voor key-----
multi line hex key
----- end <key>------
Kort gezegd is dat deel voor meerdere interpretaties mogelijk.. Ik ga nog wel extra testen met de Binary optie maar dan zag gistereren ook veel \ tekens in de base64 string komen.
OnTracK schreef op woensdag 9 augustus 2023 @ 17:46:
Ook zegt de documentatie dat je een header
code:
1
Signature: xxx
moet toevoegen. Maar in je voorbeeld doe je een header
code:
1
Authorization: xxx
?
Wat ik nu deed was Authorisation = "Signnature: base64string", maar na het lezen van jouw comment lijkt het erop dat dit anders moet. Weer iets om mee verder te testen
MatHack schreef op woensdag 9 augustus 2023 @ 16:50:
De error is over 2 regels, kan het zijn dat er een CR/LF staat op een plek wat een single-line string hoort te zijn?

EDIT: Ik neem aan dat de base512 -> base64 code is veranderd nadat je UTF8 hebt toegepast?
Ja de encoded string is qua lengte ongeveer gehalveerd. Maar wel gebruik wel Base64, niet base512 >>[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signature))

@Killah_Priest Als de oplossing met PS7 gedaan kan worden dan maakt dat het leven wel makkelijker ;)
Via jouw oplossing hoef ik helemaal geen private-key meer op te slaan wat ik qua veiligheid ook liever niet doe (verwijderen is nooit echt verwijderd ;) ) Huidige script kijk nu of er een secure string is opgeslagen welke deze decodeerd en als pem opslaat maar die stap doe ik liever niet.

Edit: Ik krijg nu een token retour met de oplossing @Killah_Priest
Kan nu weer verder puzzelen :)

Taal fouten inbegrepen ;)
Mijn AI Art YouTube kanaal

Pagina: 1