Certificate Public key to decrypt encrypted signature

This topic contains 6 replies, has 2 voices, and was last updated by Profile photo of Ray Pro Ray Pro 5 months, 2 weeks ago.

  • Author
    Posts
  • #62937
    Profile photo of Ray Pro
    Ray Pro
    Participant

    Howdy.

    This is a bit of a cross post with stackoverflow, no flaming pls.
    I've written an Alexa Skill in PowerShell, but it got rejected because I'm not validating a signature properly.

    Instructions are here: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service?ref_=pe_679090_102923190#checking-the-signature-of-the-request
    I'm good up to:
    6.- Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
    7.- Generate a SHA-1 hash value from the full HTTPS request body to produce the derived hash value
    8.- Compare the asserted hash value and derived hash values to ensure that they match.

    #certUrl =  https://s3.amazonaws.com/echo.api/echo-api-cert-4.pem
    $cert = Get-PfxCertificate -FilePath $dlPath
    # 5.- Base64-decode the Signature header value on the request to obtain the encrypted signature
    $encryptedSignatureBytes  = [System.Convert]::FromBase64String($Json.signature)
    
    # 6.- Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value       
    $publicKey = $cert.GetPublicKey() #returns long System.Byte
    $assertedHash = $cert.PublicKey.Key.Decrypt($encryptedSignatureBytes, $false) #Exception calling "Decrypt" with "2" argument(s): "Key does not exist.
    
    # 7.- Generate a SHA-1 hash value from the full HTTPS request body to produce the derived hash value    
    $requestBodySHA1 = $(Get-StringHash $Json.requestBody)
    
    # 8.- Compare the asserted hash value and derived hash values to ensure that they match    
    if($assertedHash -eq $requestBodySHA1)
    {
        #process
    }
    

    I've tried using $cert.PublicKey.Key.VerifyHash, $cert.PublicKey.Key.VerifyData, $cert.PublicKey.Key.signHash, $cert.PublicKey.Key.SignData, but I'm lost.

    Any help appreciated.

  • #63028
    Profile photo of Andrew Herbert
    Andrew Herbert
    Participant

    Are you able to supply an example for the variable $Json which you reference in:

    $encryptedSignatureBytes  = [System.Convert]::FromBase64String($Json.signature)
  • #63049
    Profile photo of Ray Pro
    Ray Pro
    Participant

    @Andrew thanks for your interest.
    I ended up figuring out the issue once I understood the actual requirement. In order to compare the signature and Amazon post request, all I had to do was get the request as a Byte[] the Signature was already Byte[] from Base64 conversion, then feed it in to the function $cert.PublicKey.Key.VerifyData
    If I change any byte in either the Signature or Request it fails.

    Previously I was hashing the request JSON and trying to compare to whatever I could get from the public key, which was wrong.

        
        # 7.- Generate a SHA-1 hash value from the full HTTPS request body to produce the derived hash value
        $requestBodyBytes = [System.IO.File]::ReadAllBytes($req)
        # 8.- Compare the asserted hash value and derived hash values to ensure that they match
        $sha1Oid = [System.Security.Cryptography.CryptoConfig]::MapNameToOID('SHA1')
        if(!($cert.PublicKey.Key.VerifyData($requestBodyBytes, $sha1Oid, $encryptedSignatureBytes)))
        {
        	$validErr += "`nFailed request hash comparison to signature."
        }
    
  • #63538
    Profile photo of Andrew Herbert
    Andrew Herbert
    Participant

    Ray, that's great news – glad you got it working 🙂

    I'd be really interested to see your end product and how you're hosting it once you're done, as I've got a project on the go I'd love to add an Alexa skill to.

    Andy

You must be logged in to reply to this topic.