katerina-p
asked on
Calculating a keyed hmac sha256 in vba
Hi All,
Last week I posted a question on how to calculate a SHA256 HMAC (https://www.experts-exchange.com/questions/27831058/Calculating-an-hmac-sha256-in-vba.html), which was helpfully answered by a link from ryanmccauley
However, I actually just realised that I have to use my 'secret key' also to generate this HMAC and I am again absolutely stumped!
Please advise!
It's for Amazon MWS - see http://docs.amazonwebservices.com/AWSMechTurk/latest/AWSMechanicalTurkRequester/MakingRequests_RequestAuthenticationArticle.html "Calculating Request Signatures"
http://en.wikipedia.org/wiki/HMAC#External_links has examples of the keyed results
e.g. (as far as I understand):
Simple SHA256 of "The quick brown fox jumps over the lazy dog" is:
0x d7a8fbb307d7809469ca9abcb0 082e4f8d56 51e46d3cdb 762d02d0bf 37c9e592
Using a key of "key" it is:
0x f7bc83f430538424b13298e6aa 6fb143ef4d 59a1494617 5997479dbc 2d1a3cd8
Using a key of "MyKey" it is:
0x 206304502da490dd9a5e01d500 561e9fae18 c75e08d08f de440d1927 71d35535
etc
This example can be seen using https://quickhash.com/, selecting Algorithm:SHA-256, and either having (Use HMAC Method? = True + HMAC Key: = [the key] ) or not.
Many thanks!
K.
Last week I posted a question on how to calculate a SHA256 HMAC (https://www.experts-exchange.com/questions/27831058/Calculating-an-hmac-sha256-in-vba.html), which was helpfully answered by a link from ryanmccauley
However, I actually just realised that I have to use my 'secret key' also to generate this HMAC and I am again absolutely stumped!
Please advise!
It's for Amazon MWS - see http://docs.amazonwebservices.com/AWSMechTurk/latest/AWSMechanicalTurkRequester/MakingRequests_RequestAuthenticationArticle.html "Calculating Request Signatures"
http://en.wikipedia.org/wiki/HMAC#External_links has examples of the keyed results
e.g. (as far as I understand):
Simple SHA256 of "The quick brown fox jumps over the lazy dog" is:
0x d7a8fbb307d7809469ca9abcb0
Using a key of "key" it is:
0x f7bc83f430538424b13298e6aa
Using a key of "MyKey" it is:
0x 206304502da490dd9a5e01d500
etc
This example can be seen using https://quickhash.com/, selecting Algorithm:SHA-256, and either having (Use HMAC Method? = True + HMAC Key: = [the key] ) or not.
Many thanks!
K.
ASKER
Hi, thanks for the response. Sorry if I wasn't clear - yes I do have the key, I just don't know how to manipulate the HMAC with it!
I just skimmed through your prior question and it's not obvious to me if you have your SHA256 and HMAC functions working or not. Are you able to reproduce the output of the examples you posted?
Can you attach your project to your next reply so that I can see what you're doing?
Can you attach your project to your next reply so that I can see what you're doing?
according to the documentation, you concatenate your 20 byte secret key with the message signature and the timestamp (in UTC format) and then calculate that hash and convert it into a Base64 string.
ASKER
tdlewis, yes I have it working - see attached.
Database37.zip
Database37.zip
ASKER
Calculating Request Signatures
A request signature, an HMAC, is calculated by concatenating the values of the Service, Operation, and Timestamp parameters, in that order, and then calculating an RFC 2104-compliant HMAC, using the Secret Access Key as the "key."
As you can see from the previously attached db, I've got the basic HMAC SHA-256 fine - I just don't know how to get one using a key.
A request signature, an HMAC, is calculated by concatenating the values of the Service, Operation, and Timestamp parameters, in that order, and then calculating an RFC 2104-compliant HMAC, using the Secret Access Key as the "key."
As you can see from the previously attached db, I've got the basic HMAC SHA-256 fine - I just don't know how to get one using a key.
You have the code to calculate SHA-256, but not HMAC. Let me see if I can find an HMAC implementation that you can add to your project.
ASKER
Ah! Thank you...
According to the requirements document, you will need to XOR the bytes of your secret key with an array of x36 bytes and x5C bytes (ipad and opad). One of these is used as the key to an HMAC function that does a keyed hash with the text of your 'message'. The result of the first HMAC function is used as the 'text' in the second HMAC iteration with the other key. The key for each iteration is concatenated to the text value for that iteration.
The Ken Ives code I referenced in the prior thread only performs simple hashing, so you would concatenate the XORed key values with that iteration's text value.
You can also evaluate this VB library. It does some of the XOR and concatenate operations for you.
http://www.vbforums.com/showthread.php?635398-VB6-HMAC-SHA-256-HMAC-SHA-1-Using-Crypto-API
http://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Definition_.28from_RFC_2104.29
The Ken Ives code I referenced in the prior thread only performs simple hashing, so you would concatenate the XORed key values with that iteration's text value.
You can also evaluate this VB library. It does some of the XOR and concatenate operations for you.
http://www.vbforums.com/showthread.php?635398-VB6-HMAC-SHA-256-HMAC-SHA-1-Using-Crypto-API
http://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Definition_.28from_RFC_2104.29
@katerina-p
Have you used StrConv() function or byte arrays?
Have you used StrConv() function or byte arrays?
Here is an example of an HMAC calculation of the string "Now is the time for all", using a secret key of "0PN5J17HBGZHT7JJ3X82". bKey1 is the ipad and bKey2 is the opad.
Dim bKey1() As Byte
Dim bKey2() As Byte
Dim bSHA() As Byte
Dim lngLoop As Long
bKey1 = StrConv("0PN5J17HBGZHT7JJ3X82", vbFromUnicode)
bKey2 = StrConv("0PN5J17HBGZHT7JJ3X82", vbFromUnicode)
For lngLoop = 0 To UBound(bKey1)
bKey1(lngLoop) = bKey1(lngLoop) Xor &H36
Next
For lngLoop = 0 To UBound(bKey2)
bKey2(lngLoop) = bKey2(lngLoop) Xor &H5C
Next
bSHA = SHA_routine(StrConv(bKey2, vbUnicode) & StrConv(SHA_routine(StrConv(bKey1, vbUnicode) & "Now is the time for all")))
'bSHA needs to be rendered as a Base64 string
@katerina-p, is the example from aikimark sufficient for you to get your code working?
Note: there is a missing ", vbUnicode" parameter on the right side StrConv function invocation.
ASKER
Hi,
Thanks for your help guys. The code is 'working', but I'm not getting the expected results.
With a key of "0PN5J17HBGZHT7JJ3X82" on string "Now is the time for all", I'm getting B3C1795F3B7CC03C8DA04D279A 86EE765328 B3C26B5A90 2E1E2857E6 AE86BFC2 - is this what you expected? Because I cannot replicate the examples from my OP.
K.
Thanks for your help guys. The code is 'working', but I'm not getting the expected results.
With a key of "0PN5J17HBGZHT7JJ3X82" on string "Now is the time for all", I'm getting B3C1795F3B7CC03C8DA04D279A
K.
You have not rendered a Base64 string
ASKER
String = Now is the time for all
Key = 0PN5J17HBGZHT7JJ3X82
HMAC = B3C1795F3B7CC03C8DA04D279A 86EE765328 B3C26B5A90 2E1E2857E6 AE86BFC2
Base64 = QjNDMTc5NUYzQjdDQzAzQzhEQT A0RDI3OUE4 NkVFNzY1Mz I4QjNDMjZC NUE5MDJFMU UyODU3RTZB RTg2QkZDMg ==
Is this as you expect?
Key = 0PN5J17HBGZHT7JJ3X82
HMAC = B3C1795F3B7CC03C8DA04D279A
Base64 = QjNDMTc5NUYzQjdDQzAzQzhEQT
Is this as you expect?
According to the quickhash.com page, the keyed HMAC would be (lower/upper case hex):
3559f19379d18bb08393694239 40c9801093 570d
3559F19379D18BB08393694239 40C9801093 570D
And rendered as Base64 as:
NVnxk3nRi7CDk2lCOUDJgBCTVw 0=
3559f19379d18bb08393694239
3559F19379D18BB08393694239
And rendered as Base64 as:
NVnxk3nRi7CDk2lCOUDJgBCTVw
ASKER
I modified my code snippet to instantiate a couple of objects from the .Net namespace for testing purposes (see below).
When I run this, the hex values in the opad array are:
EC7275667641E47953D876D970 3E2A2797DA 5ACD
This is a different hex string than that computed by quickhash.com web site engine.
When I run this, the hex values in the opad array are:
EC7275667641E47953D876D970
This is a different hex string than that computed by quickhash.com web site engine.
Dim bKey1() As Byte
Dim bKey2() As Byte
Dim bSHA() As Byte
Dim lngLoop As Long
Dim lngPosn As Long
bKey1 = StrConv("0PN5J17HBGZHT7JJ3X82", vbFromUnicode)
bKey2 = StrConv("0PN5J17HBGZHT7JJ3X82", vbFromUnicode)
For lngLoop = 0 To UBound(bKey1)
bKey1(lngLoop) = bKey1(lngLoop) Xor &H36
Next
For lngLoop = 0 To UBound(bKey2)
bKey2(lngLoop) = bKey2(lngLoop) Xor &H5C
Next
Dim oUTF, oEnc
Dim ipad() As Byte, opad() As Byte
Dim strText As String
Dim strTemp As String
strText = "Now is the time for all"
'Borrow some objects from .NET (supported from 1.1 onwards)
Set oUTF = CreateObject("System.Text.UTF8Encoding")
Set oEnc = CreateObject("System.Security.Cryptography.SHA1CryptoServiceProvider")
'Convert the string to a byte array and hash it
ipad = oEnc.ComputeHash_2(oUTF.GetBytes_4(StrConv(bKey1, vbUnicode) & strText))
opad = oEnc.ComputeHash_2(oUTF.GetBytes_4(StrConv(bKey2, vbUnicode) & StrConv(ipad, vbUnicode)))
'Convert the byte array to a hex string
For lngPosn = 0 To UBound(opad)
strTemp = strTemp & UCase(Right("0" & Hex(opad(lngPosn)), 2))
Next
please post your code. I can't open your database.
ASKER
Module0 (Behind Form):
HMAC Module :
Base64 Module:
public Sub ABC(s as string, Optional k as string)
Dim sHMAC as string
dim sBase64 as string
If IsNull(k) Then
sHMAC = Hashing.SHA(s)
Else
sHMAC = Hashing.HMAC(s, k)
End If
sBase64 = Base64EncodeString(sHMAC )
End Sub
HMAC Module :
Option Compare Database
Option Explicit
Public Function SHA(ByVal sMessage) As String
Dim i, result(32), Temp(8) As Double, fraccubeprimes, hashValues
Dim done512, index512, words(64) As Double, index32, mask(4)
Dim s0, s1, t1, t2, maj, ch, strLen
mask(0) = 4294967296#
mask(1) = 16777216
mask(2) = 65536
mask(3) = 256
hashValues = Array( _
1779033703, 3144134277#, 1013904242, 2773480762#, _
1359893119, 2600822924#, 528734635, 1541459225)
fraccubeprimes = Array( _
1116352408, 1899447441, 3049323471#, 3921009573#, 961987163, 1508970993, 2453635748#, 2870763221#, _
3624381080#, 310598401, 607225278, 1426881987, 1925078388, 2162078206#, 2614888103#, 3248222580#, _
3835390401#, 4022224774#, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, _
2554220882#, 2821834349#, 2952996808#, 3210313671#, 3336571891#, 3584528711#, 113926993, 338241895, _
666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350#, 2456956037#, _
2730485921#, 2820302411#, 3259730800#, 3345764771#, 3516065817#, 3600352804#, 4094571909#, 275423344, _
430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, _
1955562222, 2024104815, 2227730452#, 2361852424#, 2428436474#, 2756734187#, 3204031479#, 3329325298#)
sMessage = Nz(sMessage, "")
strLen = Len(sMessage) * 8
sMessage = sMessage & Chr(128)
done512 = False
index512 = 0
If (Len(sMessage) Mod 60) <> 0 Then
For i = (Len(sMessage) Mod 60) To 59
sMessage = sMessage & Chr(0)
Next
End If
sMessage = sMessage & Chr(Int((strLen / mask(0) - Int(strLen / mask(0))) * 256))
sMessage = sMessage & Chr(Int((strLen / mask(1) - Int(strLen / mask(1))) * 256))
sMessage = sMessage & Chr(Int((strLen / mask(2) - Int(strLen / mask(2))) * 256))
sMessage = sMessage & Chr(Int((strLen / mask(3) - Int(strLen / mask(3))) * 256))
Do Until done512
For i = 0 To 15
words(i) = Asc(Mid(sMessage, i * 4 + 1, 1)) * mask(1) + Asc(Mid(sMessage, i * 4 + 2, 1)) * mask(2) + Asc(Mid(sMessage, i * 4 + 3, 1)) * mask(3) + Asc(Mid(sMessage, i * 4 + 4, 1))
Next
For i = 16 To 63
s0 = largeXor(largeXor(rightRotate(words(i - 15), 7, 32), rightRotate(words(i - 15), 18, 32), 32), Int(words(i - 15) / 8), 32)
s1 = largeXor(largeXor(rightRotate(words(i - 2), 17, 32), rightRotate(words(i - 2), 19, 32), 32), Int(words(i - 2) / 1024), 32)
words(i) = Mod32Bit(words(i - 16) + s0 + words(i - 7) + s1)
Next
For i = 0 To 7
Temp(i) = hashValues(i)
Next
For i = 0 To 63
s0 = largeXor(largeXor(rightRotate(Temp(0), 2, 32), rightRotate(Temp(0), 13, 32), 32), rightRotate(Temp(0), 22, 32), 32)
maj = largeXor(largeXor(largeAnd(Temp(0), Temp(1), 32), largeAnd(Temp(0), Temp(2), 32), 32), largeAnd(Temp(1), Temp(2), 32), 32)
t2 = Mod32Bit(s0 + maj)
s1 = largeXor(largeXor(rightRotate(Temp(4), 6, 32), rightRotate(Temp(4), 11, 32), 32), rightRotate(Temp(4), 25, 32), 32)
ch = largeXor(largeAnd(Temp(4), Temp(5), 32), largeAnd(largeNot(Temp(4), 32), Temp(6), 32), 32)
t1 = Mod32Bit(Temp(7) + s1 + ch + fraccubeprimes(i) + words(i))
Temp(7) = Temp(6)
Temp(6) = Temp(5)
Temp(5) = Temp(4)
Temp(4) = Mod32Bit(Temp(3) + t1)
Temp(3) = Temp(2)
Temp(2) = Temp(1)
Temp(1) = Temp(0)
Temp(0) = Mod32Bit(t1 + t2)
Next
For i = 0 To 7
hashValues(i) = Mod32Bit(hashValues(i) + Temp(i))
Next
If (index512 + 1) * 64 >= Len(sMessage) Then done512 = True
index512 = index512 + 1
Loop
For i = 0 To 31
result(i) = Int((hashValues(i \ 4) / mask(i Mod 4) - Int(hashValues(i \ 4) / mask(i Mod 4))) * 256)
' Debug.Print result(i);
Next
Debug.Print vbCrLf
For i = 0 To 31
' Debug.Print Hex(result(i));
SHA = SHA & Hex(result(i))
Next
End Function
Function Mod32Bit(value)
Mod32Bit = Int((value / 4294967296# - Int(value / 4294967296#)) * 4294967296#)
End Function
Function rightRotate(value, amount, totalBits)
'To leftRotate, make amount = totalBits - amount
Dim i
rightRotate = 0
For i = 0 To (totalBits - 1)
If i >= amount Then
rightRotate = rightRotate + (Int((value / (2 ^ (i + 1)) - Int(value / (2 ^ (i + 1)))) * 2)) * 2 ^ (i - amount)
Else
rightRotate = rightRotate + (Int((value / (2 ^ (i + 1)) - Int(value / (2 ^ (i + 1)))) * 2)) * 2 ^ (totalBits - amount + i)
End If
Next
End Function
Function largeXor(value, xorValue, totalBits)
Dim i, a, b
largeXor = 0
For i = 0 To (totalBits - 1)
a = (Int((value / (2 ^ (i + 1)) - Int(value / (2 ^ (i + 1)))) * 2))
b = (Int((xorValue / (2 ^ (i + 1)) - Int(xorValue / (2 ^ (i + 1)))) * 2))
If a <> b Then
largeXor = largeXor + 2 ^ i
End If
Next
End Function
Function largeNot(value, totalBits)
Dim i, a
largeNot = 0
For i = 0 To (totalBits - 1)
a = Int((value / (2 ^ (i + 1)) - Int(value / (2 ^ (i + 1)))) * 2)
If a = 0 Then
largeNot = largeNot + 2 ^ i
End If
Next
End Function
Function largeAnd(value, andValue, totalBits)
Dim i, a, b
largeAnd = 0
For i = 0 To (totalBits - 1)
a = Int((value / (2 ^ (i + 1)) - Int(value / (2 ^ (i + 1)))) * 2)
b = (Int((andValue / (2 ^ (i + 1)) - Int(andValue / (2 ^ (i + 1)))) * 2))
If a = 1 And b = 1 Then
largeAnd = largeAnd + 2 ^ i
End If
Next
End Function
Public Function HMAC(s As String, k As String) As String
Dim i As Integer
Dim bKey1() As Byte
Dim bKey2() As Byte
Dim bSHA() As Byte
Dim lngLoop As Long
'bKey1 = StrConv("0PN5J17HBGZHT7JJ3X82", vbFromUnicode)
'bKey2 = StrConv("0PN5J17HBGZHT7JJ3X82", vbFromUnicode)
bKey1 = StrConv(k, vbFromUnicode)
bKey2 = StrConv(k, vbFromUnicode)
For lngLoop = 0 To UBound(bKey1)
bKey1(lngLoop) = bKey1(lngLoop) Xor &H36
Next
For lngLoop = 0 To UBound(bKey2)
bKey2(lngLoop) = bKey2(lngLoop) Xor &H5C
Next
HMAC = SHA(StrConv(bKey2, vbUnicode) & StrConv(SHA(StrConv(bKey1, vbUnicode) & s), vbUnicode))
'bSHA needs to be rendered as a Base64 string
End Function
Base64 Module:
Option Compare Database
Option Explicit
' A Base64 Encoder/Decoder.
'
' This module is used to encode and decode data in Base64 format as described in RFC 1521.
'
' Home page: www.source-code.biz.
' License: GNU/LGPL (www.gnu.org/licenses/lgpl.html).
' Copyright 2007: Christian d'Heureuse, Inventec Informatik AG, Switzerland.
' This module is provided "as is" without warranty of any kind.
Private InitDone As Boolean
Private Map1(0 To 63) As Byte
Private Map2(0 To 127) As Byte
' Encodes a string into Base64 format.
' No blanks or line breaks are inserted.
' Parameters:
' S a String to be encoded.
' Returns: a String with the Base64 encoded data.
Public Function Base64EncodeString(ByVal s As String) As String
Base64EncodeString = Base64Encode(ConvertStringToBytes(s))
End Function
' Encodes a byte array into Base64 format.
' No blanks or line breaks are inserted.
' Parameters:
' InData an array containing the data bytes to be encoded.
' Returns: a string with the Base64 encoded data.
Public Function Base64Encode(InData() As Byte)
Base64Encode = Base64Encode2(InData, UBound(InData) - LBound(InData) + 1)
End Function
' Encodes a byte array into Base64 format.
' No blanks or line breaks are inserted.
' Parameters:
' InData an array containing the data bytes to be encoded.
' InLen number of bytes to process in InData.
' Returns: a string with the Base64 encoded data.
Public Function Base64Encode2(InData() As Byte, ByVal InLen As Long) As String
If Not InitDone Then Init
If InLen = 0 Then Base64Encode2 = "": Exit Function
Dim ODataLen As Long: ODataLen = (InLen * 4 + 2) \ 3 ' output length without padding
Dim OLen As Long: OLen = ((InLen + 2) \ 3) * 4 ' output length including padding
Dim Out() As Byte
ReDim Out(0 To OLen - 1) As Byte
Dim ip0 As Long: ip0 = LBound(InData)
Dim ip As Long
Dim op As Long
Do While ip < InLen
Dim i0 As Byte: i0 = InData(ip0 + ip): ip = ip + 1
Dim i1 As Byte: If ip < InLen Then i1 = InData(ip0 + ip): ip = ip + 1 Else i1 = 0
Dim i2 As Byte: If ip < InLen Then i2 = InData(ip0 + ip): ip = ip + 1 Else i2 = 0
Dim o0 As Byte: o0 = i0 \ 4
Dim o1 As Byte: o1 = ((i0 And 3) * &H10) Or (i1 \ &H10)
Dim o2 As Byte: o2 = ((i1 And &HF) * 4) Or (i2 \ &H40)
Dim o3 As Byte: o3 = i2 And &H3F
Out(op) = Map1(o0): op = op + 1
Out(op) = Map1(o1): op = op + 1
Out(op) = IIf(op < ODataLen, Map1(o2), Asc("=")): op = op + 1
Out(op) = IIf(op < ODataLen, Map1(o3), Asc("=")): op = op + 1
Loop
Base64Encode2 = ConvertBytesToString(Out)
End Function
' Decodes a string from Base64 format.
' Parameters:
' s a Base64 String to be decoded.
' Returns a String containing the decoded data.
Public Function Base64DecodeString(ByVal s As String) As String
If s = "" Then Base64DecodeString = "": Exit Function
Base64DecodeString = ConvertBytesToString(Base64Decode(s))
End Function
' Decodes a byte array from Base64 format.
' Parameters
' s a Base64 String to be decoded.
' Returns: an array containing the decoded data bytes.
Public Function Base64Decode(ByVal s As String) As Byte()
If Not InitDone Then Init
Dim iBuf() As Byte: iBuf = ConvertStringToBytes(s)
Dim iLen As Long: iLen = UBound(iBuf) + 1
If iLen Mod 4 <> 0 Then err.Raise vbObjectError, , "Length of Base64 encoded input string is not a multiple of 4."
Do While iLen > 0
If iBuf(iLen - 1) <> Asc("=") Then Exit Do
iLen = iLen - 1
Loop
Dim OLen As Long: OLen = (iLen * 3) \ 4
Dim Out() As Byte
ReDim Out(0 To OLen - 1) As Byte
Dim ip As Long
Dim op As Long
Do While ip < iLen
Dim i0 As Byte: i0 = iBuf(ip): ip = ip + 1
Dim i1 As Byte: i1 = iBuf(ip): ip = ip + 1
Dim i2 As Byte: If ip < iLen Then i2 = iBuf(ip): ip = ip + 1 Else i2 = Asc("A")
Dim i3 As Byte: If ip < iLen Then i3 = iBuf(ip): ip = ip + 1 Else i3 = Asc("A")
If i0 > 127 Or i1 > 127 Or i2 > 127 Or i3 > 127 Then _
err.Raise vbObjectError, , "Illegal character in Base64 encoded data."
Dim b0 As Byte: b0 = Map2(i0)
Dim b1 As Byte: b1 = Map2(i1)
Dim b2 As Byte: b2 = Map2(i2)
Dim b3 As Byte: b3 = Map2(i3)
If b0 > 63 Or b1 > 63 Or b2 > 63 Or b3 > 63 Then _
err.Raise vbObjectError, , "Illegal character in Base64 encoded data."
Dim o0 As Byte: o0 = (b0 * 4) Or (b1 \ &H10)
Dim o1 As Byte: o1 = ((b1 And &HF) * &H10) Or (b2 \ 4)
Dim o2 As Byte: o2 = ((b2 And 3) * &H40) Or b3
Out(op) = o0: op = op + 1
If op < OLen Then Out(op) = o1: op = op + 1
If op < OLen Then Out(op) = o2: op = op + 1
Loop
Base64Decode = Out
End Function
Private Sub Init()
Dim c As Integer, i As Integer
' set Map1
i = 0
For c = Asc("A") To Asc("Z"): Map1(i) = c: i = i + 1: Next
For c = Asc("a") To Asc("z"): Map1(i) = c: i = i + 1: Next
For c = Asc("0") To Asc("9"): Map1(i) = c: i = i + 1: Next
Map1(i) = Asc("+"): i = i + 1
Map1(i) = Asc("/"): i = i + 1
' set Map2
For i = 0 To 127: Map2(i) = 255: Next
For i = 0 To 63: Map2(Map1(i)) = i: Next
InitDone = True
End Sub
Private Function ConvertStringToBytes(ByVal s As String) As Byte()
Dim b1() As Byte: b1 = s
Dim l As Long: l = (UBound(b1) + 1) \ 2
If l = 0 Then ConvertStringToBytes = b1: Exit Function
Dim b2() As Byte
ReDim b2(0 To l - 1) As Byte
Dim p As Long
For p = 0 To l - 1
Dim c As Long: c = b1(2 * p) + 256 * CLng(b1(2 * p + 1))
If c >= 256 Then c = Asc("?")
b2(p) = c
Next
ConvertStringToBytes = b2
End Function
Private Function ConvertBytesToString(b() As Byte) As String
Dim l As Long: l = UBound(b) - LBound(b) + 1
Dim b2() As Byte
ReDim b2(0 To (2 * l) - 1) As Byte
Dim p0 As Long: p0 = LBound(b)
Dim p As Long
For p = 0 To l - 1: b2(2 * p) = b(p0 + p): Next
Dim s As String: s = b2
ConvertBytesToString = s
End Function
Function UTF8_Decode(ByVal sStr As String)
Dim l As Long, sUTF8 As String, iChar As Integer, iChar2 As Integer
For l = 1 To Len(sStr)
iChar = Asc(Mid(sStr, l, 1))
If iChar > 127 Then
If Not iChar And 32 Then ' 2 chars
iChar2 = Asc(Mid(sStr, l + 1, 1))
sUTF8 = sUTF8 & ChrW$(((31 And iChar) * 64 + (63 And iChar2)))
l = l + 1
Else
Dim iChar3 As Integer
iChar2 = Asc(Mid(sStr, l + 1, 1))
iChar3 = Asc(Mid(sStr, l + 2, 1))
sUTF8 = sUTF8 & ChrW$(((iChar And 15) * 16 * 256) + ((iChar2 And 63) * 64) + (iChar3 And 63))
l = l + 2
End If
Else
sUTF8 = sUTF8 & Chr$(iChar)
End If
Next l
UTF8_Decode = sUTF8
End Function
You are returning your SHA output as a hex string.
ASKER
I do apologise if I'm being dense, but for "Now is the time for all" and a Key of "0PN5J17HBGZHT7JJ3X82" I'm getting:
SHA256: 12925223125244341065713011 4292553332 1471016158 1986888134 1756208812 4957193245 64171
Which in Hex is: 81FCE7FC2C226A3982721DFF21 2093AA13AC 6445886AF6 D051F939C1 F540AB
An Hmac of: 62108235246182152771931861 9226194151 2005119723 8931052122 8421401491 1124421419 5168137249 109
Which in Hex is: B3C1795F3B7CC03C8DA04D279A 86EE765328 B3C26B5A90 2E1E2857E6 AE86BFC2
Which in Base64 is: QjNDMTc5NUYzQjdDQzAzQzhEQT A0RDI3OUE4 NkVFNzY1Mz I4QjNDMjZC NUE5MDJFMU UyODU3RTZB RTg2QkZDMg ==
From https://quickhash.com/ it looks like the Hex HMAC should be 289433633C7673A3E153BF19AD 4EF2E9E4C1 A415ED2D27 4F918629EB AF93369A
Your code in post 38355049 returns EC7275667641E47953D876D970 3E2A2797DA 5ACD
I'm well and truly lost!
Your .NET code refers to SHA1, is this correct? Can we use http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha256.aspx somehow?
Thank you very much.
K.
SHA256: 12925223125244341065713011
Which in Hex is: 81FCE7FC2C226A3982721DFF21
An Hmac of: 62108235246182152771931861
Which in Hex is: B3C1795F3B7CC03C8DA04D279A
Which in Base64 is: QjNDMTc5NUYzQjdDQzAzQzhEQT
From https://quickhash.com/ it looks like the Hex HMAC should be 289433633C7673A3E153BF19AD
Your code in post 38355049 returns EC7275667641E47953D876D970
I'm well and truly lost!
Your .NET code refers to SHA1, is this correct? Can we use http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha256.aspx somehow?
Thank you very much.
K.
according to the HMAC specification you posted, SHA1 should be used, not SHA256
ASKER
Although that doc references SHA1, they prefer SHA256. Everywhere else is SHA256.
Can we use http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha256.aspx somehow?
Can we use http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha256.aspx somehow?
please point me to the part of the Amazon document that indicates anything other than SHA1.
ASKER
https://images-na.ssl-images-amazon.com/images/G/02/mwsportal/doc/en_US/bde/MWSDeveloperGuide._V148508187_.pdf
p.15 Calculate an RFC 2104-compliant HMAC with the string you just created, using your Secret Key as the key.
Both HmacSHA256 and HmacSHA1 are supported hash algorithms, but Amazon recommends using
HmacSHA256
p.15 Calculate an RFC 2104-compliant HMAC with the string you just created, using your Secret Key as the key.
Both HmacSHA256 and HmacSHA1 are supported hash algorithms, but Amazon recommends using
HmacSHA256
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Sorry for the late reply - thank you - I was hoping we could use that.
Once that HMAC gets your message through to Amazon, then I guess it passes muster and you can close the question.
ASKER
The code generates correctly, so I will close. However, I still can't replicate what Amazon want! However, that's (perhaps, unless I can fix) a topic for a different question, as the HMAC 256 keyed hash method in the .Net framework is obviously fine!
In other words, Amazon has to give you the key.