python-VBA中的HMAC-SHA1 URL加密产生不正确的输出

对于Google Maps Business API查询,我需要使用HMAC-SHA1对每个查询进行数字签名.我们使用带有VBA宏的Excel文件发送查询并解析输出,因此我想在VBA中创建签名.我找到这个问题的答案:Base64 HMAC SHA1 String in VBA

但是,当查询发送到Google API时,此代码的字符串签名无效.

Google提供了一些示例脚本.我使用用于测试上述VBA代码的相同输入测试了Python sample script,并且Python代码确实返回了有效的签名.因此,似乎提供的VBA代码没有构造正确的HMAC-SHA1签名,但我找不到问题(我没有加密经验,只有VBA基本知识).

我创建了用于测试目的的HMAC-SHA1密钥:1412SxPev45oMMRQSXazwQp789yM =

当使用“ abc”作为字符串输入运行时,我得到以下返回:

VBA代码:Fsu0z3i6Ma5HCrP3eXucrdssJLc =

Python代码:IFxkS7B_ePtZrvU8sGmiaipTHio =

有谁知道如何在VBA中计算与Python输出相等的正确HMAC-SHA1?

编辑03/04/2014:
根据Alex K.的建议,我确保使用http://thydzik.com中的代码将SharedSecretKey解码为Base64.我在下面的VBA代码中添加了功能DecodeBase64.
由于此输出是正确的,但还不是URL安全的(因此与Python输出不同),因此我使用了VBA Replace()函数将-和/替换为_
这些解决方案共同产生正确的输出,并被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)

解决方法:

在这里,您从输入字符串中获取密钥:

SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)

但是在这里,您需要从Base64获取是否解码输入字符串:

decodedKey = base64.urlsafe_b64decode(privateKey)

.Net的Getbytes不会进行Base64解码,因此输入有很大不同.

如果将SharedSecretKey解码为字节数组,则将获得正确的输出:

IFxkS7B/ePtZrvU8sGmiaipTHio=

尽管要注意,由于urlsafe_b64encode,不同的Base64重新编码语义.

(如果通过Converter在.net中进行解码,则您将需要丢失密钥中的尾随填充=)

上一篇:如何在Python 3.3中加密/解密字典?


下一篇:加密地穴-尝试以与Perl相同的方式在PHP中工作