Search code examples
powershellopenssldigital-signature

Powershell equivalent of 'openssl dgst -sha512 -sign'


For API access, I need to sign a JSON file with 'openssl dgst -sha512 -sign'. I need to run this in a Powershell script.

Currently, I am using the following method:

  • Write the file to a temp file, and re-read it to be certain that there is no conversion problem
  • Invoke openssl to sign the file
  • Read the signature file
  • Call the API
$body = @{
    "login" = "customer"
    "nonce" = Get-Random -Minimum ([int]([math]::pow(10,8))) -Maximum ([int]([math]::pow(10,9)-1))
    "read_only" = "true"
    "expiration_time" = "30 seconds"
    "label" = "Test"
    "global_key" = "true"
} | ConvertTo-Json

Remove-Item -Force "D:\temp\body.tmp" -ErrorAction Continue
Remove-Item -Force "D:\temp\body.dgst" -ErrorAction Continue

$body | Out-File -FilePath "D:\temp\body.tmp" -Encoding ascii

# Re-read data from the file after it's been re-encoded to ascii (as thats what we signed)
$body = [System.IO.File]::ReadAllBytes("D:\temp\body.tmp")

# Sign with the private key of the signing certificate
& D:\apps\openssl\bin\openssl.exe dgst -sha512 -sign "D:\powershell\TransIP\sign.txt" -out "D:\temp\body.dgst" "D:\temp\body.tmp"

$headers = @{
    Signature = ([Convert]::ToBase64String([System.IO.File]::ReadAllBytes("D:\temp\body.dgst")))
    "Content-Type" = "application/json"
}

I've been searching for a native Powershell/.NET method for SHA512 digest signing, but I can't seem to find anything in the Security class to do this.

Does anyone know a native Powershell method (thus eliminating the dependency of an external openssl installation), or is the above method the only method for signing?

Documentation of the API that I'm trying to use: https://api.transip.nl/rest/docs.html (section 'Authentication'). I've already asked TransIP for support, but they don't support Powershell.

Documentation of 'openssl dgst': https://www.openssl.org/docs/man1.1.1/man1/dgst.html


Solution

  • Stumbled upon this question on another (Dutch) forum so I wrote a simple solution for this

      <#
            Login voor TransIP.
            This only works in core editions of PS
            (PS for Windows doesn't have the ImportFromPem method)
        #>
        
        # 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)
        
        # read the PEM file
        $PEMContent = Get-Content -Path 'C:\test\transip\test1PK.pem' -Raw
        
        # import de PEMFile
        $RSA = [System.Security.Cryptography.RSA]::Create()
        $RSA.ImportFromPem($PEMContent)
        
        # sign the data, SHA512 en Pkcs1
        $signature = $RSA.SignData($BodyBytes,'SHA512',[System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
        
        # Base64 encode the signature
        $B64Sig = [System.Convert]::ToBase64String($signature)
        
        # Http header
        $header = @{
            Signature = $B64Sig
            }
        
        $authurl = 'https://api.transip.nl/v6/auth'
        
        # make the request
        $Response = Invoke-WebRequest -Uri $authurl -Headers $header -Body $Body -Method Post -ContentType application/json