From: Schmidt on

"GS" <GS(a)discussions.microsoft.com> schrieb im Newsbeitrag
news:%236fwHvJ8KHA.3880(a)TK2MSFTNGP04.phx.gbl...

> So your Example1 in the previous post is a VB6
> implementation of HMAC_SHA1, then?

Actually the examples 1 to 3 are all HMAC_SHA1
generating ones - they differ only in their msg-content (which
is "Sample #1", "Sample #2", "Sample #3") and also use different
Test-Keys (64, 20 and 100 Bytes long, with different content) -
the expected output of these three SHA1-HMACs (for the given
Msg- and Key-Input-Params) is listed also in the download-
link to the PDF-file which I've placed in one of the comments.

The "example 0" at the top of the Form_Load() procedure
on the other hand just shows a simple SHA1-Hashing of
a "normal Message" (without any HMAC-Key) for the
string "abc".

> Are you saying that this will generate the 4 keys the OP requires
> to create his hash? (assuming it must be 64byte)
I don't have any clue, why the author of the SHA1-routines (under
the link the OP has posted: http://vb.wikia.com/wiki/SHA-1.bas) -
was offering the ability, to change the four "K-Values" of an
SHA1-implementation, which normally are fixed-wired ones,
which contribute to the algorithms security.
Please look at the pseudo-code at http://en.wikipedia.org/wiki/SHA-1
where in a correct algo-impl. these four K-Values are placed.
A normal SHA-1 function only takes one Input-Param
(a ByteStream or a ByteArray) and delivers 20 Bytes
(160Bits) as the result - that this result is delivered
sometimes hex-encoded, sometimes as a Byte- or
Char-Array of length20, is only a small implementation-
detail.

In either case these K-Values - (in the code of the *.bas-module
from vb.wikia.com these are Function-Params, named Key1,
Key2, Key3, Key4) - are definitely in no way related to the
Key, a real SHA1-HMAC-implementation expects.

In my opinion the Author should have attributed only *one*
of his *.bas-module-functions Public - and that's:
Function HexDefaultSHA1(Message() As Byte) As String

> How does this compare to Larry's solution in terms of his
> end result being HMAC_SHA1 compliant?
Larry probably just tried to put the OPs focus on another
"common mistake" one can make whilst dealing with such
functions, which rely on correct binary- or Hex-input, especially
when also VBs (wide) BSTRs are involved and allowed as
possible Input-Params.

Olaf


From: GS on
Schmidt explained on 5/10/2010 :
> "GS" <GS(a)discussions.microsoft.com> schrieb im Newsbeitrag
> news:%236fwHvJ8KHA.3880(a)TK2MSFTNGP04.phx.gbl...
>
>> So your Example1 in the previous post is a VB6
>> implementation of HMAC_SHA1, then?
>
> Actually the examples 1 to 3 are all HMAC_SHA1
> generating ones - they differ only in their msg-content (which
> is "Sample #1", "Sample #2", "Sample #3") and also use different
> Test-Keys (64, 20 and 100 Bytes long, with different content) -
> the expected output of these three SHA1-HMACs (for the given
> Msg- and Key-Input-Params) is listed also in the download-
> link to the PDF-file which I've placed in one of the comments.
>
> The "example 0" at the top of the Form_Load() procedure
> on the other hand just shows a simple SHA1-Hashing of
> a "normal Message" (without any HMAC-Key) for the
> string "abc".
>
>> Are you saying that this will generate the 4 keys the OP requires
>> to create his hash? (assuming it must be 64byte)
> I don't have any clue, why the author of the SHA1-routines (under
> the link the OP has posted: http://vb.wikia.com/wiki/SHA-1.bas) -
> was offering the ability, to change the four "K-Values" of an
> SHA1-implementation, which normally are fixed-wired ones,
> which contribute to the algorithms security.
> Please look at the pseudo-code at http://en.wikipedia.org/wiki/SHA-1
> where in a correct algo-impl. these four K-Values are placed.
> A normal SHA-1 function only takes one Input-Param
> (a ByteStream or a ByteArray) and delivers 20 Bytes
> (160Bits) as the result - that this result is delivered
> sometimes hex-encoded, sometimes as a Byte- or
> Char-Array of length20, is only a small implementation-
> detail.

Someone should tell the OP that, but more importantly tell the website
he's using this for. I don't see why Example0 won't do!

>
> In either case these K-Values - (in the code of the *.bas-module
> from vb.wikia.com these are Function-Params, named Key1,
> Key2, Key3, Key4) - are definitely in no way related to the
> Key, a real SHA1-HMAC-implementation expects.
>
> In my opinion the Author should have attributed only *one*
> of his *.bas-module-functions Public - and that's:
> Function HexDefaultSHA1(Message() As Byte) As String

I'm inclined to agree because this returns the same result as the
Example0 (or standard SHA1).

>
>> How does this compare to Larry's solution in terms of his
>> end result being HMAC_SHA1 compliant?
> Larry probably just tried to put the OPs focus on another
> "common mistake" one can make whilst dealing with such
> functions, which rely on correct binary- or Hex-input, especially
> when also VBs (wide) BSTRs are involved and allowed as
> possible Input-Params.
>
> Olaf

Again, as I stated in a previous post, I only use SHA256 for my stuff,
and only if I don't use MD5. Otherwise, I use a random generator where
I can pass the bit size to OR my GUID generator if it doesn't require
any parameters. (The latter is just for creating actual GUIDs for my
app versions)

It's always good to know a little bit more about the stuff I use in my
work. I appreciate the time you take with making your replies rich with
good info (even if a lot of it is still 'over my head'; I'll catch up
eventually<g>) So thanks, eh!
Garry


From: Steve on
Thanks for all the help...I think I am starting to get somewhere. I
did as Olaf suggested and modified his example to use the SHA1
function I have. This does produce a result which is of the correct
format (is the same number of chars as the expected result). However
as a last step in the process the C# function encodes the hash to
Base64. I have a function to do the Base64 encoding but using it
produces results which are not even close (wrong number of characters)
to what is expected.

Here is the full C# code I am trying to replicate

byte[] sharedSecretBytes;
string stringToHash;

// Check the hash
ASCIIEncoding encoding = new ASCIIEncoding();

this.Token = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E";
sharedSecretBytes =
encoding.GetBytes("SharedSecretKeyStoredInConfig");
stringToHash = this.Plan + this.Claim + this.Csr + this.Token +
this.Date;

HMACSHA1 hasher = new HMACSHA1(sharedSecretBytes);
byte[] bytesToHash = encoding.GetBytes(stringToHash);
hasher.ComputeHash(bytesToHash);
string computedHash = Convert.ToBase64String(hasher.Hash);
hasher.Clear();


Here is what I have currently:

Option Explicit

Private Declare Sub RtlMoveMemory Lib "KERNEL32" (Dst As Any, Src As
Any, ByVal LenBytes As Long)

Private Sub Form_Load()

' Example using no key value
txtKey = ""
txtToken = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E"
txtPlan = "15847812"
txtClaim = "3270278"
txtCSR = "DA3"
txtDate = "5/5/2010 13:54"

' Result of C# HMACSHA1 class = "1QI77EFgZ+P0KEvHDtBCQi4Jw7A="

' Example using test key value
' txtKey = "SharedSecretKeyStoredInConfig"
' txtToken = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E"
' txtPlan = "16263392"
' txtClaim = "3278053"
' txtCSR = "DA3"
' txtDate = "5/5/2010 13:54"
'
' Result of C# HMACSHA1 class = "W8z0Ad5gLsIOYeGz3YnP1XQMapU="

End Sub

Private Sub cmdHash_Click()
Dim stringToHash As String
Dim arrBytes() As Byte
Dim strTemp As String

stringToHash = txtPlan.Text & txtClaim.Text & txtCSR.Text &
txtToken.Text & txtDate.Text

strTemp = HMAC_SHA1(stringToHash, txtKey.Text)
arrBytes = StrConv(strTemp, vbFromUnicode)

txtHash = EncodeBase64(arrBytes)

End Sub

'if you pass ByteArrays directly, then ensure they have an LBound at
Zero
Function HMAC_SHA1(Msg, Key)
Dim i As Long
Dim M() As Byte
Dim K() As Byte
Dim LenKey As Long
Dim oPAD() As Byte
Dim iPad() As Byte
Dim IntermediateSHA1() As Byte

If VarType(Msg) = vbString Then
M = StrConv(Msg, vbFromUnicode)
Else 'we assume a byte-array now, and produce an error, if it
isn't one
M = Msg
End If

If VarType(Key) = vbString Then
K = StrConv(Key, vbFromUnicode)
Else 'we assume a byte-array now, and produce an error, if it
isn't one
K = Key
End If
LenKey = UBound(K) + 1

ReDim oPAD(0 To 63 + 20) 'make oPad 20Bytes longer for
IntermediateSHA1
ReDim iPad(0 To 63 + UBound(M) + 1) 'same here, but for the Msg-
Content M

If LenKey > 64 Then 'Keys, longer than 64Bytes are shortened per
SHA1
K = HexDefaultSHA1(K)
LenKey = 20
End If

For i = 0 To 63 'ensure proper XORing on the first 64Bytes in oPad
+iPad
oPAD(i) = &H5C
iPad(i) = &H36
If i < LenKey Then
oPAD(i) = oPAD(i) Xor K(i)
iPad(i) = iPad(i) Xor K(i)
End If
Next i

RtlMoveMemory iPad(64), M(0), UBound(M) + 1 'append Bytes of M to
iPad...
IntermediateSHA1 = HexDefaultSHA1(iPad) '... and calculate
IntermediateSHA1

RtlMoveMemory oPAD(64), IntermediateSHA1(0), 20 'append the result
to oPad

HMAC_SHA1 = HexDefaultSHA1(oPAD)

End Function

This code is basically just using Olafs code but substituting calls to
his SHA1 function with calls to the one I have. I think I probably
need to do something a little different with the return from the
HexDefaultSHA1 function before passing it to the EncodeBase 64
function but I have no idea what.


Here is some code I found to do the Base64 encoding

Public Function EncodeBase64(ByRef arrData() As Byte) As String
Dim objXML As MSXML2.DOMDocument
Dim objNode As MSXML2.IXMLDOMElement

' help from MSXML
Set objXML = New MSXML2.DOMDocument

' byte array to base64
Set objNode = objXML.createElement("b64")
objNode.dataType = "bin.base64"
objNode.nodeTypedValue = arrData
EncodeBase64 = objNode.Text

' thanks, bye
Set objNode = Nothing
Set objXML = Nothing

End Function

As the code above shows I have the results from the C# code for two
different sets of data (one using a key and one without). I am trying
to get the results of my efforts to match those results.

Thanks,
Steve
From: GS on
After serious thinking Steve wrote :
> Thanks for all the help...I think I am starting to get somewhere. I
> did as Olaf suggested and modified his example to use the SHA1
> function I have. This does produce a result which is of the correct
> format (is the same number of chars as the expected result). However
> as a last step in the process the C# function encodes the hash to
> Base64. I have a function to do the Base64 encoding but using it
> produces results which are not even close (wrong number of characters)
> to what is expected.
>
> Here is the full C# code I am trying to replicate
>
> byte[] sharedSecretBytes;
> string stringToHash;
>
> // Check the hash
> ASCIIEncoding encoding = new ASCIIEncoding();
>
> this.Token = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E";
> sharedSecretBytes =
> encoding.GetBytes("SharedSecretKeyStoredInConfig");
> stringToHash = this.Plan + this.Claim + this.Csr + this.Token +
> this.Date;
>
> HMACSHA1 hasher = new HMACSHA1(sharedSecretBytes);
> byte[] bytesToHash = encoding.GetBytes(stringToHash);
> hasher.ComputeHash(bytesToHash);
> string computedHash = Convert.ToBase64String(hasher.Hash);
> hasher.Clear();
>
>
> Here is what I have currently:
>
> Option Explicit
>
> Private Declare Sub RtlMoveMemory Lib "KERNEL32" (Dst As Any, Src As
> Any, ByVal LenBytes As Long)
>
> Private Sub Form_Load()
>
> ' Example using no key value
> txtKey = ""
> txtToken = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E"
> txtPlan = "15847812"
> txtClaim = "3270278"
> txtCSR = "DA3"
> txtDate = "5/5/2010 13:54"
>
> ' Result of C# HMACSHA1 class = "1QI77EFgZ+P0KEvHDtBCQi4Jw7A="
>
> ' Example using test key value
> ' txtKey = "SharedSecretKeyStoredInConfig"
> ' txtToken = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E"
> ' txtPlan = "16263392"
> ' txtClaim = "3278053"
> ' txtCSR = "DA3"
> ' txtDate = "5/5/2010 13:54"
> '
> ' Result of C# HMACSHA1 class = "W8z0Ad5gLsIOYeGz3YnP1XQMapU="
>
> End Sub
>
> Private Sub cmdHash_Click()
> Dim stringToHash As String
> Dim arrBytes() As Byte
> Dim strTemp As String
>
> stringToHash = txtPlan.Text & txtClaim.Text & txtCSR.Text &
> txtToken.Text & txtDate.Text
>
> strTemp = HMAC_SHA1(stringToHash, txtKey.Text)
> arrBytes = StrConv(strTemp, vbFromUnicode)
>
> txtHash = EncodeBase64(arrBytes)
>
> End Sub
>
> 'if you pass ByteArrays directly, then ensure they have an LBound at
> Zero
> Function HMAC_SHA1(Msg, Key)
> Dim i As Long
> Dim M() As Byte
> Dim K() As Byte
> Dim LenKey As Long
> Dim oPAD() As Byte
> Dim iPad() As Byte
> Dim IntermediateSHA1() As Byte
>
> If VarType(Msg) = vbString Then
> M = StrConv(Msg, vbFromUnicode)
> Else 'we assume a byte-array now, and produce an error, if it
> isn't one
> M = Msg
> End If
>
> If VarType(Key) = vbString Then
> K = StrConv(Key, vbFromUnicode)
> Else 'we assume a byte-array now, and produce an error, if it
> isn't one
> K = Key
> End If
> LenKey = UBound(K) + 1
>
> ReDim oPAD(0 To 63 + 20) 'make oPad 20Bytes longer for
> IntermediateSHA1
> ReDim iPad(0 To 63 + UBound(M) + 1) 'same here, but for the Msg-
> Content M
>
> If LenKey > 64 Then 'Keys, longer than 64Bytes are shortened per
> SHA1
> K = HexDefaultSHA1(K)
> LenKey = 20
> End If
>
> For i = 0 To 63 'ensure proper XORing on the first 64Bytes in oPad
> +iPad
> oPAD(i) = &H5C
> iPad(i) = &H36
> If i < LenKey Then
> oPAD(i) = oPAD(i) Xor K(i)
> iPad(i) = iPad(i) Xor K(i)
> End If
> Next i
>
> RtlMoveMemory iPad(64), M(0), UBound(M) + 1 'append Bytes of M to
> iPad...
> IntermediateSHA1 = HexDefaultSHA1(iPad) '... and calculate
> IntermediateSHA1
>
> RtlMoveMemory oPAD(64), IntermediateSHA1(0), 20 'append the result
> to oPad
>
> HMAC_SHA1 = HexDefaultSHA1(oPAD)
>
> End Function
>
> This code is basically just using Olafs code but substituting calls to
> his SHA1 function with calls to the one I have. I think I probably
> need to do something a little different with the return from the
> HexDefaultSHA1 function before passing it to the EncodeBase 64
> function but I have no idea what.
>
>
> Here is some code I found to do the Base64 encoding
>
> Public Function EncodeBase64(ByRef arrData() As Byte) As String
> Dim objXML As MSXML2.DOMDocument
> Dim objNode As MSXML2.IXMLDOMElement
>
> ' help from MSXML
> Set objXML = New MSXML2.DOMDocument
>
> ' byte array to base64
> Set objNode = objXML.createElement("b64")
> objNode.dataType = "bin.base64"
> objNode.nodeTypedValue = arrData
> EncodeBase64 = objNode.Text
>
> ' thanks, bye
> Set objNode = Nothing
> Set objXML = Nothing
>
> End Function
>
> As the code above shows I have the results from the C# code for two
> different sets of data (one using a key and one without). I am trying
> to get the results of my efforts to match those results.
>
> Thanks,
> Steve

Steve,
First thing, I want to apologize for leading you in the wrong direction
with my previous post example. It only occurred to me afterwards, after
reading Olaf's reply, what you were actually attempting to do. I'm
sorry about that!

Base64 encoding doesn't alter what you get from the SHA1 function. It
just puts the text into an email-friendly format that can be decoded at
the other end. There's no magic; it's a standard e-format used
universally by many expressly for this purpose. So, if you pass the
result back to MSXML to decode it you'll get the original string back
again.

What I suspect is that they just want your SHA1 serial key 'on file' so
they can authenticate/validate your submissions to them. It doesn't
matter what message string you use to create this serial key, and so
the reason I posted the gibberish about embedding parts of your
personal info so that it truly was unique to you. Otherwise, the
message string you pass to the SHA1 function could have been "rumple
stiltskin" for all intents and purposes.

HTH
Garry


From: Ulrich Korndoerfer on
Hi,

Steve schrieb:

> Thanks for all the help...I think I am starting to get somewhere. I
> did as Olaf suggested and modified his example to use the SHA1
> function I have. This does produce a result which is of the correct
> format (is the same number of chars as the expected result). However
> as a last step in the process the C# function encodes the hash to
> Base64. I have a function to do the Base64 encoding but using it
> produces results which are not even close (wrong number of characters)
> to what is expected.
> ...

If you are interested, I have an all VB Base64 converter, encapsulated
in a class called CBase64. This class is embedded in the archive
Cryptography.zip, available here:

http://www.prosource.de/Downloads/VB_Quickies/Cryptography.zip

And AFAIR Olafs RichClient.dll has a base64 converter too.

--
Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.proSource.de/Downloads/