VBA Sign Cryptographic Key

iliauk

Board Regular
Joined
Jun 3, 2014
Messages
163
Hi All,

I've been using VBA to interface with Google Maps. I think the newest (v3) API sends a Web Service URL which needs to be signed using a cryptographic key.

E.g. sign path + query of web service url, decode the private key, create a sig using private key and URL using HMAC SHA1 then encode the binary signature into base64 to get a return url to sign.

However, I am not how to do this in VBA/XML and appreciate some pointers
 

Excel Facts

Spell Check in Excel
Press F7 to start spell check in Excel. Be careful, by default, Excel does not check Capitalized Werds (whoops)
I guess I wasn't very informative in my post.

Here is my main geo-code function:
Code:
Function GeoCodeAddr(ByVal Addr As String, Optional ByVal Country As String)
Dim Request As XMLHTTP60
Dim DOMdoc As DOMDocument60
Dim gAddr As IXMLDOMNode
Dim urlString As String


Const clientid As String = "XXX"
Const channelid As String = "XXX"
Const keyString As String = "XXX"


Addr = URLEncode(Addr)
urlString = "http://maps.googleapis.com/maps/api/geocode/xml?address=" & Addr _
    & "&client=" & clientid & "&channel=" & channelid
'Possible extension: & "&components=|country:" & Country
Debug.Print urlString
Set Request = New XMLHTTP60
With Request
.Open "GET", Base64_HMACSHA1(urlString, keyString)
.send
End With


Set DOMdoc = New DOMDocument60
DOMdoc.LoadXML Request.responseText
'Get formatted_address, latitude & longitude
Set gAddr = DOMdoc.SelectSingleNode("GeocodeResponse/result//formatted_address")
Set latNode = myDomDoc.SelectSingleNode("//result/geometry/location/lat")
Set lngNode = myDomDoc.SelectSingleNode("//result/geometry/location/lng")
'At the moment only focus on formatted_address
If gAddr Is Nothing Then
    GeoCodeAddr = "Not Found"
Else
    GeoCodeAddr = gAddr.Text
End If
End Function

Then these two functions to sign the key:
Code:
Public Function Base64_HMACSHA1(ByVal sTextToHash As String, ByVal sSharedSecretKey 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.HMACSHA1")


TextToHash = asc.Getbytes_4(sTextToHash)
SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)
enc.Key = SharedSecretKey


Dim bytes() As Byte
bytes = enc.ComputeHash_2((TextToHash))
Base64_HMACSHA1 = EncodeBase64(bytes)
Set asc = Nothing
Set enc = Nothing
End Function


Private Function EncodeBase64(ByRef arrData() As Byte) As String
Dim objXML As MSXML2.DOMDocument
Dim objNode As MSXML2.IXMLDOMElement


Set objXML = New MSXML2.DOMDocument


' byte array to base64
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.nodeTypedValue = arrData
EncodeBase64 = objNode.Text


Set objNode = Nothing
Set objXML = Nothing
End Function

I error when I send ".Open "GET", Base64_HMACSHA1(urlString, keyString)" however I am not sure if that is because of the way I am sending it or because the signing functions are wrong.

I have found this which I will try to incorporate:
http://gmaps-samples.googlecode.com/svn/trunk/urlsigning/urlSigner.vb


 
Upvote 0
Hi Kyle, thank you for your reply. I noticed an error in my code above (the encoding does work as can be seen in the debug.print)

Rich (BB code):
Function GeoCodeAddr(ByVal Addr As String, Optional ByVal Country As String)
Dim Request As XMLHTTP60
Dim DOMdoc As DOMDocument60
Dim gAddr As IXMLDOMNode
Dim urlString As String
Dim signedKey As String
 
Const clientid As String = "x"
Const channelid As String = "x"
'Get dynamically from txt as python script?
Const keyString As String = "x"
 
Addr = URLEncode(Addr)
urlString = "http://maps.googleapis.com/maps/api/geocode/xml?address=" & Addr _
    & "&client=" & clientid & "&channel=" & channelid
'Possible extension: & "&components=|country:" & Country
Debug.Print urlString
 
Debug.Print Base64_HMACSHA1("abc", "123")
signedKey = Base64_HMACSHA1(urlString, keyString)
Debug.Print signedKey
 
Set Request = New XMLHTTP60
With Request
.Open "GET", urlString & "&key=" & signedKey
.send
End With
 
Set DOMdoc = New DOMDocument60
DOMdoc.LoadXML Request.responseText
'Get formatted_address, latitude & longitude
Set gAddr = DOMdoc.SelectSingleNode("GeocodeResponse/result//formatted_address")
Set latNode = myDomDoc.SelectSingleNode("GeocodeResponse/result/geometry/location/lat")
Set lngNode = myDomDoc.SelectSingleNode("GeocodeResponse/result/geometry/location/lng")
'At the moment only focus on formatted_address
If gAddr Is Nothing Then
    GeoCodeAddr = "Not Found"
Else
    GeoCodeAddr = gAddr.Text
End If
End Function

The error I get is: "Unable to authenticate the request. Missing the 'signature' parameter. Learn more: https://developers.google.com/maps/documentation/business/webservices/auth"

Which appears to be the link you sent me so I will investigate -thanks again!
 
Upvote 0
Ah I see, I was sending the wrong parameter ... however now I get a different error:

“"Unable to authenticate the request. Provided 'signature' is not valid for the provided client ID, or the provided 'client' is not valid.
The signature was checked against the URL..."”

Rich (BB code):
Addr = URLEncode(Addr)
urlString = "https://maps.googleapis.com/maps/api/geocode/xml?address=" & Addr & "&client=" & clientid
'Possible extension: & "&components=|country:" & Country
Debug.Print urlString
urlString_cut = Replace(urlString, "https://maps.googleapis.com", "")
Debug.Print urlString_cut
signedKey = Base64_HMACSHA1(urlString_cut, keyString)
Debug.Print signedKey
 
Set Request = New XMLHTTP60
With Request
.Open "GET", urlString & "&signature=" & signedKey
.send
End With

But I think with a bit of fiddling it should work. Thanks for your help!
 
Upvote 0
Hm, I was wrong with the above.

I think the signature is not being calculated correctly.

With the google maps debugger tool: https://m4b-url-signer.appspot.com/

Using: https://maps.googleapis.com/maps/api/geocode/xml?address=New York&client=MYID

I get:
  • Signature : ClxsvtrVtwc2f0_pG6G-eKSF6ZA=
Whereas the calculated signature in excel is:
g4I682HantGCISH3festgyVKvAs=

And the url I encode is: "/maps/api/geocode/xml?address=New%20York&client=MYID"

This is strange - surely if the signature is not being calculated correctly then it would be completely off or give me an error - the fact that it generates some signature (which is wrong) may mean I am encoding the wrong address, however I read the user-guide and they say to use the "/maps/api" chunk ... I also tried the full address and with no luck.
 
Upvote 0
You've missed a step, you've need to decode the base64 private key before getting getting the bytes, the following code returns the correct signature:
PHP:
Public Function Base64_HMACSHA1(ByVal sTextToHash As String, ByVal sSharedSecretKey As String)


    Dim asc As Object
    Dim enc As Object
    Dim TextToHash() As Byte
    Dim SharedSecretKey() As Byte
    Dim bytes() As Byte
    
    Set asc = CreateObject("System.Text.UTF8Encoding")
    Set enc = CreateObject("System.Security.Cryptography.HMACSHA1")
    
    ''Replace illegal Characters and decode base64 string'
    sSharedSecretKey = Replace(Replace(sSharedSecretKey, "-", "+"), "_", "/")
    SharedSecretKey = Base64Decode(sSharedSecretKey)
    enc.Key = SharedSecretKey
    
    TextToHash = asc.Getbytes_4(sTextToHash)
    
    bytes = enc.ComputeHash_2((TextToHash))
    Base64_HMACSHA1 = Base64Encode(bytes)


End Function

I've used the base 64 encode/decode module from here: http://www.source-code.biz/snippets/vbasic/Base64Coder.bas.txt

Running:
PHP:
Base64_HMACSHA1("/maps/api/geocode/json?address=New+York&client=clientID","vNIXE0xscrmjlyV-12Nj_BvUPaw=")
Returns: chaRF2hTJKOScPr+RQCEhZbSzIE=
 
Last edited:
Upvote 0

Forum statistics

Threads
1,216,095
Messages
6,128,792
Members
449,468
Latest member
AGreen17

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top