使用 VBA 对 CoinBase Pro 进行身份验证,签名无效

时间:2021-07-01 02:43:48

标签: excel vba signature coinbase-api

我正在尝试调用 Coinbase Pro API,但一直收到无效签名。我遵循了 CoinBase Pro 上的说明,在这里阅读了大量相关文章,但没有任何内容真正指出问题。我试过对时间戳 + 方法 + fullURL 进行哈希处理,我只试过文档所述的 API 端点。我已经验证了散列和 base64 函数得到了正确的结果。我曾尝试按照 CoinBase 上的文档所述解码秘密,但这会产生不可读的字符。所以我尝试使用在线工具对秘密进行 base64 解码,但这会产生不可解码的错误消息。有一篇文章提到把参数改成小写,所以我尝试了各种组合,还是不行。

需要注意的是,秘密已经是 64 字节了。文档说解码后的秘密应该是 64 字节。所以我尝试了解码和未解码的秘密。文档说对 SHA256 哈希的结果进行 base64 编码,但我使用的函数已经这样做了。所以我尝试了编码和非编码只是为了后代,但仍然产生无效签名错误消息。

有一个调用 /time 端点的 getEpochTime 函数。这是我获得 HMAC_SHA256 代码的站点,尽管我必须将 MSXML2.DOMDocument 的引用更改为 MSXML2.DOMDocument60。 https://www.excelhowto.com/macros/excel-vba-base64-hmac-sha256-and-sha1-encryption/

以下是我用来验证散列和加密的网站: https://devpal.co/base64-decode/ https://www.devglan.com/online-tools/hmac-sha256-online#/google_vignette

我目前将 api 密钥、秘密和密码存储在 Excel 工作表中,以便于测试。在创建api key时,我从屏幕上复制了数据并粘贴到Excel工作表中,以避免人为错误。我还验证了 api 密钥具有查看/交易/转移权限。

任何建设性的帮助将不胜感激。

这是我的代码。

Sub Test()

    Dim oXmlHttp As MSXML2.XMLHTTP60
    Set oXmlHttp = New MSXML2.XMLHTTP60

    Dim URL As String
    Dim appKey As String
    Dim Signature As String
    Dim Passphrase As String
    Dim TimeStamp As String
    Dim Secret As String
    Dim HashText As String
    Dim Hash As String
    Dim API As String
    Dim sBody As String
    
    API = "/v2/accounts"
    TimeStamp = GetEpochTime
    URL = Sheets("Configuration").Cells(3, 2) & API
    appKey = Sheets("Configuration").Cells(6, 2).Value
    Secret = Sheets("Configuration").Cells(7, 2)                        'Base64DecodeString( )
    Passphrase = Sheets("Configuration").Cells(8, 2)

    HashText = TimeStamp & "GET" & URL
    Signature = Base64_HMACSHA256(HashText, Secret)
        
    oXmlHttp.Open "GET", URL, False                     ', "", ""
    oXmlHttp.setRequestHeader "CB-ACCESS-KEY", appKey
    oXmlHttp.setRequestHeader "CB-ACCESS-TIMESTAMP", TimeStamp
    oXmlHttp.setRequestHeader "CB-ACCESS-PASSPHRASE", Passphrase
    oXmlHttp.setRequestHeader "CB-ACCESS-SIGN", Signature
    oXmlHttp.setRequestHeader "Content-Type", "application/json"
    oXmlHttp.send
    
    While oXmlHttp.readyState <> 4
        DoEvents
    Wend
    sBody = oXmlHttp.responseText

    MsgBox sBody
End Sub

Function GetEpochTime() As Double
    
    Dim oXmlHttp As MSXML2.XMLHTTP60
    Set oXmlHttp = New MSXML2.XMLHTTP60
    Dim URL As String
    URL = Sheets("Configuration").Cells(3, 2) & "/time"
    oXmlHttp.Open "GET", URL, False
    oXmlHttp.setRequestHeader "Content-Type", "application/json"
    oXmlHttp.send
    GetEpochTime = GetJSON_Key(oXmlHttp.responseText, "epoch")
    
End Function

Function Base64_HMACSHA256(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.HMACSHA256")
 
    TextToHash = asc.Getbytes_4(sTextToHash)
    SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)
    enc.Key = SharedSecretKey
 
    Dim bytes() As Byte
    bytes = enc.ComputeHash_2((TextToHash))
    Base64_HMACSHA256 = Base64EncodeFromBytes(bytes)
    
    Set asc = Nothing
    Set enc = Nothing
    
End Function
 
Function Base64EncodeString(ByVal sText As String) As String
    
    Dim byt() As Byte
    
    byt = VBA.StrConv(sText, VbStrConv.vbFromUnicode, 1033)
    
    Base64EncodeString = Base64EncodeFromBytes(byt)
    
End Function

Function Base64EncodeFromBytes(ByRef byt() As Byte) As String

    Dim oXML  As MSXML2.DOMDocument60
    Set oXML = New MSXML2.DOMDocument60
    
    Dim oNode As MSXML2.IXMLDOMNode

    Set oNode = oXML.createElement("base64")
    oNode.DataType = "bin.base64"
    
    oNode.nodeTypedValue = byt
    Base64EncodeFromBytes = oNode.Text
    
    Debug.Assert TypeName(Base64EncodeFromBytes) = "String"
    Set oNode = Nothing
    Set oXML = Nothing
    
End Function

Function Base64DecodeString(ByVal sText As String) As String

    Dim byt() As Byte
    byt = Base64DecodeToBytes(sText)
    
    Base64DecodeString = VBA.StrConv(byt(), VbStrConv.vbUnicode)

End Function

Function Base64DecodeToBytes(ByVal sEncoded As String) As Byte()
    
    Debug.Assert TypeName(sEncoded) = "String"
    
    Dim oXML  As MSXML2.DOMDocument60
    Set oXML = New MSXML2.DOMDocument60
    
    Dim oNode As MSXML2.IXMLDOMNode
    Set oNode = oXML.createElement("base64")
    
    oNode.DataType = "bin.base64"
    oNode.Text = sEncoded
    
    Base64DecodeToBytes = oNode.nodeTypedValue
    
    Set oNode = Nothing
    Set oXML = Nothing
    
End Function

1 个答案:

答案 0 :(得分:0)

我终于弄清楚问题出在哪里了,仅仅描述我如何让它工作就需要一整页的时间。相反,这是代码。将其复制/粘贴到 Excel 工作簿中的新模块中并运行 TestAPIConnection 子例程。 Coinbase Pro 凭据位于名为“配置”的工作表中,并在名为 CBPro_Private_API 的函数中引用。还有一个公共 API 函数可用于未经身份验证的请求。希望你觉得这有用。

记得添加对“Microsoft XML, v6.0”和“Microsoft Scripting Runtime”的引用。

Configuration Sheet

Option Explicit

Sub TestAPIConnection()
    
    Dim sMethod As String
    Dim API As String
    Dim sBody As String
    Dim sResult As String
    
    API = "/accounts"
    sMethod = "GET"
    sBody = ""
    sResult = CBPro_Private_API(sMethod, API, sBody)        
    'You will need to parse the resulting JSON string       
    MsgBox sResult

End Sub

Function CBPro_Public_API(sMethod As String, API As String, sBody As String) As String
    
    Dim oXmlHttp As MSXML2.XMLHTTP60
    Set oXmlHttp = New MSXML2.XMLHTTP60

    Dim URL As String
    URL = Sheets("Configuration").Cells(3, 2) & API
    
    oXmlHttp.Open sMethod, URL, False                     ', "", ""
    oXmlHttp.setRequestHeader "Content-Type", "application/json"
    oXmlHttp.send sBody
    
    'This is used when the ASync parameter on the .Open call is set to true
    While oXmlHttp.readyState <> 4
        DoEvents
    Wend
    
    CBPro_Public_API = oXmlHttp.responseText
    
End Function

Function CBPro_Private_API(sMethod As String, API As String, sBody As String) As String
    
    Dim oXmlHttp As MSXML2.XMLHTTP60
    Set oXmlHttp = New MSXML2.XMLHTTP60
    
    Dim URL As String
    Dim appKey As String
    Dim sSignature As String
    Dim sPassPhrase As String
    Dim sTimeStamp As String
    Dim sSecret As String
    Dim sHashText As String
    Dim Hash As String
    
    'Get Setup data from the Configuration sheet
    appKey = Sheets("Configuration").Cells(4, 2).Value
    sSecret = Sheets("Configuration").Cells(5, 2)
    sPassPhrase = Sheets("Configuration").Cells(6, 2)
    URL = Sheets("Configuration").Cells(3, 2) & API
    
    'Create the hashed signature for verification by the server
    sTimeStamp = GetEpochTime
    sHashText = sTimeStamp & sMethod & API & sBody
    sSignature = GenerateSignature(sHashText, sSecret)
    
    'Call the API endpoint
    oXmlHttp.Open sMethod, URL, False
    oXmlHttp.setRequestHeader "CB-ACCESS-KEY", appKey
    oXmlHttp.setRequestHeader "CB-ACCESS-SIGN", sSignature
    oXmlHttp.setRequestHeader "CB-ACCESS-TIMESTAMP", sTimeStamp
    oXmlHttp.setRequestHeader "CB-ACCESS-PASSPHRASE", sPassPhrase
    oXmlHttp.send sBody
    
    'Wait for a response
    While oXmlHttp.readyState <> 4
        DoEvents
    Wend
    CBPro_Private_API = oXmlHttp.responseText
    
End Function

Function GenerateSignature(ByVal sTextToHash As String, sSharedSecretKey As String) As String
    
    Dim asc As Object
    Dim enc As Object
    Dim TextToHash() As Byte
    Dim bytes() As Byte
    
    Set asc = CreateObject("System.Text.UTF8Encoding")
    Set enc = CreateObject("System.Security.Cryptography.HMACSHA256")
    
    enc.Key = Base64DecodeToBytes(sSharedSecretKey)
    TextToHash = asc.GetBytes_4(sTextToHash)
    bytes = enc.ComputeHash_2((TextToHash))
    GenerateSignature = Base64EncodeFromBytes(bytes)
    
    Set asc = Nothing
    Set enc = Nothing
    
End Function

Function Base64_HMACSHA256(ByVal sTextToHash As String, sSharedSecretKey As String) 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.HMACSHA256")
    
    SharedSecretKey = asc.GetBytes_4(sSharedSecretKey)
    enc.Key = SharedSecretKey
    TextToHash = asc.GetBytes_4(sTextToHash)
    bytes = enc.ComputeHash_2((TextToHash))
    Base64_HMACSHA256 = Base64EncodeFromBytes(bytes)
    
    Set asc = Nothing
    Set enc = Nothing
    
End Function

Function Base64EncodeFromBytes(ByRef byt() As Byte) As String

    Dim oXML  As MSXML2.DOMDocument60
    Set oXML = New MSXML2.DOMDocument60
    
    Dim oNode As MSXML2.IXMLDOMNode

    Set oNode = oXML.createElement("base64")
    oNode.DataType = "bin.base64"
    
    oNode.nodeTypedValue = byt
    Base64EncodeFromBytes = oNode.Text
    
    Debug.Assert TypeName(Base64EncodeFromBytes) = "String"
    Set oNode = Nothing
    Set oXML = Nothing
    
End Function


Function Base64DecodeToBytes(ByVal sEncoded As String) As Byte()
    
    Dim oXML  As MSXML2.DOMDocument60
    Set oXML = New MSXML2.DOMDocument60
    
    Dim oNode As MSXML2.IXMLDOMNode
    Set oNode = oXML.createElement("base64")
    
    oNode.DataType = "bin.base64"
    oNode.Text = sEncoded
    
    Base64DecodeToBytes = oNode.nodeTypedValue
    
    Set oNode = Nothing
    Set oXML = Nothing
    
End Function

Function GetEpochTime() As Double
    
    'Get Epoch Time from server
    Dim sResponse As String
    sResponse = CBPro_Public_API("GET", "/time", "")
    GetEpochTime = GetJSON_Key(sResponse, "epoch")
    
End Function