we have to calculate a presigned URL to access S3 and con not use external libs (like Chilkat) or the AWS SDK for .NET with Visual Basic. Hence, we have to do the signature calculation on my own.
Some things I already validated:
- I validated the functions "get_HASH_SHA256", "ConvToHexString" and "HmacSHA256" are working as expected with external 3rd party tools.
- I calculated the presigned URL with Postman and compared the required query parameters with mine. Everything seems to be fine here. When I use the signature from postman, the request works as expected.
My code:
' src: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
CanonicalRequest = "GET" & vbLf
CanonicalRequest = CanonicalRequest & "/reports/XXXXXXX" & vbLf
CanonicalRequest = CanonicalRequest & "X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=MYACCESSKEY/20221109/eu-west-1/s3/aws4_request&X-Amz-Date=20221109T075928Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host" & vbLf
CanonicalRequest = CanonicalRequest & "host:mybucket.s3.eu-west-1.amazonaws.com" & vbLf & vbLf
CanonicalRequest = CanonicalRequest & "host" & vbLf & "UNSIGNED-PAYLOAD"
Debug.Print "CanonicalRequest:"
Debug.Print CanonicalRequest
stringToSign = "AWS4-HMAC-SHA256" & vbLf
stringToSign = stringToSign & "20221109T075928Z" & vbLf
stringToSign = stringToSign & "20221109/eu-west-1/s3/aws4_request" & vbLf
stringToSign = stringToSign & get_HASH_SHA256(CanonicalRequest)
Debug.Print "StringToSign:"
Debug.Print stringToSign
SigningKey = HmacSHA256(HmacSHA256(HmacSHA256(HmacSHA256("AWS4" & SecretKey, "20221109"), "eu-west-1"), "s3"), "aws4_request")
Debug.Print "SigningKey:"
Debug.Print SigningKey
' Signature = (HmacSHA256(SigningKey, stringToSign)) tried w/o hex conversion
Signature = ConvToHexString(HmacSHA256(SigningKey, stringToSign))
' Result should be ****003a740
' Result is ***6e9502
Any VB expert here, who can confirm the stringToSign and CanonicalRequest are calculated correctly?
CodePudding user response:
It's working now. The calculated signing key was wrong.
How did I resolve this?
What helped me resolving this was the section "Deriving a signing key using other languages" of this aws help page. Here they provided actual samples. I used the secret and access key provided there and compared the results with the expected results. The first hash value (in the sample kDate) was correct, but the second hash was a different one (in the sample kRegion).
The issue with my code above was, that i converted the signature to hex, before I calculated the next hash.
But as written on the help page: Note that these are hex-encoded representations of the binary data; the key itself and the intermediate values should be in binary format.
So I changed the logic to use the binary results:
Public Function getSigningKey(ByVal key As String, dateStamp As String, regionName As String, serviceName As String) As String
Dim asc As Object
Set asc = CreateObject("System.Text.UTF8Encoding")
Dim keyAsByte() As Byte
Dim kdate() As Byte
Dim kregion() As Byte
Dim kservice() As Byte
Dim ksigning() As Byte
keyAsByte = asc.GetBytes_4(key)
kdate = HmacSHA256(keyAsByte, dateStamp)
kregion = HmacSHA256(kdate, regionName)
kservice = HmacSHA256(kregion, serviceName)
getSigningKey = HmacSHA256(kservice, "aws4_request")
End Function
Public Function HmacSHA256(ByRef sSharedSecretKey() As Byte, ByVal sTextToHash As String) As String
Dim asc As Object, enc As Object
Dim TextToHash() As Byte
Dim SharedSecretKey() As Byte
Set asc = CreateObject("System.Text.UTF8Encoding")
Set enc = CreateObject("System.Security.Cryptography.HMACSHA256")
TextToHash = asc.GetBytes_4(sTextToHash)
enc.key = sSharedSecretKey
Dim bytes() As Byte
HmacSHA256 = enc.ComputeHash_2((TextToHash))
Set asc = Nothing
Set enc = Nothing
End Function