Шифрование URL-адресов HMAC-SHA1 в VBA приводит к неправильному выводу

Для запросов к Google Maps Business API мне нужно поставить цифровую подпись для каждого запроса с помощью HMAC-SHA1. Мы используем файл Excel с макросом VBA для отправки запросов и анализа вывода, поэтому я хотел бы создать подпись в VBA. Я нашел этот вопрос + ответ: Base64 HMAC SHA1 String в VBA
Однако подпись строки этим кодом недействительна, когда запрос отправляется в Google API.

Google предоставляет несколько примеров скриптов. Я протестировал образец скрипта Python с идентичным вводом, который использовал чтобы проверить приведенный выше код VBA, и код Python действительно вернул действительную подпись. Таким образом, похоже, что предоставленный код VBA не создает правильную подпись HMAC-SHA1, но я не могу найти проблему (у меня нет опыта работы с шифрованием и есть только базовые знания VBA).

Я создал ключ HMAC-SHA1 для целей тестирования: 1412SxPev45oMMRQSXazwQp789yM=
При запуске с «abc» в качестве строкового ввода я получаю следующие результаты:

Код VBA: Fsu0z3i6Ma5HCrP3eXucrdssJLc=
Код Python: IFxkS7B_ePtZrvU8sGmiaipTHio=

Есть ли у кого-нибудь идеи, как вычислить правильный HMAC-SHA1 в VBA, который соответствует выходным данным Python?

Редактировать 04.03.2014:
По предложению Алекса К. я обязательно декодировал SharedSecretKey в Base64, используя код из http://thydzik.com. Я добавил функцию DecodeBase64 к приведенному ниже коду VBA.
Поскольку этот вывод был правильным, но еще не был безопасным для URL (поэтому не идентичен выводу Python), я использовал функцию VBA Replace() для замены + на - и / with _
Эти решения вместе дают правильный результат, который принимается серверами Google.

Используемый скрипт VBA:

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

Добавлен код для декодирования в 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:

#!/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)

person user3351744    schedule 26.02.2014    source источник


Ответы (1)


Здесь вы получаете ключ из входной строки:

SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)

Но здесь вы получаете if из Base64, декодирующего входную строку:

decodedKey = base64.urlsafe_b64decode(privateKey)

.Net Getbytes не будет декодировать Base64, поэтому входные данные очень разные.

Если вы декодируете SharedSecretKey в массив байтов, вы получите правильный результат:

IFxkS7B/ePtZrvU8sGmiaipTHio=

Хотя обратите внимание на различную семантику перекодирования Base64 из-за urlsafe_b64encode.

(Если вы декодируете в .net через Converter, вам нужно будет потерять завершающее дополнение = из ключа)

person Alex K.    schedule 26.02.2014