Author Posts

January 29, 2017 at 8:42 am

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.

January 30, 2017 at 7:34 pm

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

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

January 31, 2017 at 4:27 am

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

February 4, 2017 at 12:02 am

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

February 4, 2017 at 12:27 am

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.

February 4, 2017 at 8:49 am

Looks good 🙂

Are you thinking of doing a write-up?

Andy

February 4, 2017 at 10:58 am

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