Encrypting HMAC-SHA1 URL in VBA generates invalid output

For Google Maps Business API requests, I need to sign each request using HMAC-SHA1. We use an Excel file with a VBA macro to send requests and analyze the output, so I would like to create a signature in VBA. I found this question + answer: Base64 HMAC SHA1 String in VBA
However, the string signature of this code is not valid when sending a request to the Google API.

Google provides some sample scripts. I tested a Python script sample with the same input that I used to test the VBA code above, and the Python codereturn a valid signature. Therefore, it seems that the VBA code provided does not create the correct HMAC-SHA1 signature, but I can not find the problem (I have no encryption experience and only basic VBA knowledge).

I created the HMAC-SHA1 key for testing: 1412SxPev45oMMRQSXazwQp789yM=
When I start with " abc" as a string input, I get the following returns:

VBA code: Fsu0z3i6Ma5HCrP3eXucrdssJLc=
Python code: IFxkS7B_ePtZrvU8sGmiaipTHio=

Does anyone know how to calculate the correct HMAC-SHA1 in VBA that equals Python output?

Edit 04/03/2014:
At the suggestion of Alex K., I made sure to decrypt the SharedSecretKey for Base64 using the code fromhttp://thydzik.com . I have added a function DecodeBase64to the VBA code below.
Since this output was correct, but not yet safe for the URL (so it was not the same Python output), I used the VBA function Replace()to replace +with -and /with. _
These decisions together create the correct output that is accepted by Google servers.

Used VBA script:

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

Added code for decoding in Base64:

Private Function decodeBase64(ByVal strData As String) As Byte()
Dim objXML As MSXML2.DOMDocument
Dim objNode As MSXML2.IXMLDOMElement

Set objXML = New MSXML2.DOMDocument
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.Text = strData
decodeBase64 = objNode.nodeTypedValue


Set objNode = Nothing
Set objXML = Nothing
End Function

Python script used:

#!/usr/bin/python
# coding: utf8

import sys
import hashlib
import urllib
import hmac
import base64
import urlparse

print("")
print("URL Signer 1.0")
print("")

# Convert the URL string to a URL, which we can parse
# using the urlparse() function into path and query
# Note that this URL should already be URL-encoded
url = urlparse.urlparse("YOUR_URL_TO_SIGN")

privateKey = "YOUR_PRIVATE_KEY"

# We only need to sign the path+query part of the string
urlToSign = url.path + "?" + url.query

# Decode the private key into its binary format
decodedKey = base64.urlsafe_b64decode(privateKey)

# Create a signature using the private key and the URL-encoded
# string using HMAC SHA1. This signature will be binary.
signature = hmac.new(decodedKey, urlToSign, hashlib.sha1)

# Encode the binary signature into base64 for use within a URL
encodedSignature = base64.urlsafe_b64encode(signature.digest())
originalUrl = url.scheme + "://" + url.netloc + url.path + "?" + url.query
print("Full URL: " + originalUrl + "&signature=" + encodedSignature)
+3
source share
1 answer

Here you get the key from the input line:

SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)

But here you get if Base64 decodes the input string:

decodedKey = base64.urlsafe_b64decode(privateKey)

.Net Getbyteswill not decode Base64, so the inputs are very different.

SharedSecretKey , :

IFxkS7B/ePtZrvU8sGmiaipTHio=

Base64 - urlsafe_b64encode.

( .net Converter, = )

+3

All Articles