Certificate Public key to decrypt encrypted signature

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.

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

$encryptedSignatureBytes  = [System.Convert]::FromBase64String($Json.signature)

@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."
    }

Ray, that’s great news - glad you got it working :slight_smile:

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

The cert/signature verification was the only thing holding me back.
https://www.amazon.com/IIOS-Movie-Wizard/dp/B01MZ91Z2B/

Let me know what you think.

Looks good :slight_smile:

Are you thinking of doing a write-up?

Andy

A write up did cross my mind, but I’m going to wait to see how well it’s received and address any issues first.
I’ll keep this post updated or you could https://visualping.io/?url=http://b.iios.co