From: GS on
Steve wrote :
> On May 10, 1:29�pm, GS <G...(a)discussions.microsoft.com> wrote:
>> Steve laid this down on his screen :
>>
>>
>>
>>
>>
>>> On May 10, 11:54�am, Steve <sredm...(a)rfcorp.com> wrote:
>>>> I have been tasked with creating a feature in an existing VB6 app that
>>>> will interact with a clients web portal. �The problem I am having is
>>>> that the web interface requires I send the data (this is simply
>>>> context info...no passwords) packed in a SHA1 hash. �My hashing
>>>> function(s) must create the exact same value as theirs does so that
>>>> they can read the data. �I have found several examples online for
>>>> using the CryptoAPI to do SHA1 hashing but I can not figure out how to
>>>> specify the "secret key"
>>
>>>> Here is the C# code the client uses to create the hash:
>>>> byte[] sharedSecretBytes;
>>>> string stringToHash;
>>
>>>> ASCIIEncoding encoding = new ASCIIEncoding();
>>>> this.Token = "56FCEFC9-579C-445E-9FD3-AFFD76C8619E";
>>>> sharedSecretBytes = encoding.GetBytes("SomeSecretKey");
>>>> 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();
>>
>>>> if (computedHash != this.Hash.Replace(" ","+"))
>>>> {
>>>> � � exceptions.Exceptions.Add(new InvalidFieldException("Invalid
>>>> hash.", "Hash"));
>>
>>>> }
>>
>>>> Can anyone help me to create a VB6 version of this same thing.
>>>> Thanks,
>>>> Steve
>>> Thought I might provide a bit more information on what I have actually
>>> tried.
>>
>>> I have tried using the SHA1.bas file (found here
>>> http://vb.wikia.com/wiki/SHA-1.bas) but as stated in the previous message,
>>> I can not figure out how to use the "secret key". �When reading the
>>> documentation on the website for the module mentioned, it looks like I
>>> could call the SHA1 function. Further it looks like the key would be passed
>>> in the args Key1 trhough Key4 and the resulting hash would be returned in
>>> H1 through H4. �If these assumptions are true, how do I get the secret ket
>>> (which is a single string value) into the Key1 through Key4 longs? �Then
>>> how do I get the result (from H1 through H4) into a single string.
>>> Thanks,
>>> Steve
>>
>> Typically, a hash is a one-way deal. You also need a corresponding
>> algorythm designed to unhash, which isn't how hashes work<IMO>. The
>> article you refer to creates a hash based on the values you specify for
>> Hi to H5 and Key1 to Key4. These are just placeholders for values, and
>> can be whatever you want them to be. This is typically how passwords
>> are used, where a user types in their username and password and these
>> are used to create the hash. The hash is then compared to the stored
>> hash for that user. If they match, they're in!
>>
>> The actual code returns a 5 part serial key containing 40 characters.
>> To validate this serial it must be rehashed at the other end using the
>> same input data, meaning both parties have to use the same hash
>> algorythm AND have exactly the same data so that a comparison can be
>> made. -OR- the receiving party must have an exact copy of the
>> "expected" hash stored somewhere in order to do the comparison without
>> having the original data.
>>
>> If you're looking for a way to share (encrypt/decrypt) data using a
>> private key or private/public key pair then you want to use a different
>> function set in the CryptoAPI.dll. The DLL can generate key pairs for
>> you if going that route. In this case, the other people you pass files
>> to/from needs the your public key, or you need theirs. In this case, if
>> you are required to use their key then you're going to have to ask them
>> for it.
>>
>> Try googling "CryptoAPI VB6" to get info on how to use it. Frankly, I
>> don't think you'll get much useful info from MSDN or any MSFT sites,
>> but there's other sources out there that will show up in the search.
>> Another keyword to try is "Cryptography Algorythms"
>>
>> Garry- Hide quoted text -
>>
>> - Show quoted text -
>
> I guess I am not making myself clear...let me try again.
>
> I am not trying to encrypt anything I am trying to hash some data
> using the same algorythms as will be used on the other side. The data
> and the hash is passed as plain text to the website. The site then
> runs it's hash calculation on the provided data and if the hash value
> it comes up with matches the one I passed then it assumes the request
> is from a valid user.

And so is exactly what I stated in my previous post. This is the
correct way to use a hash. My analogy of a username/password was just
another way to explain that usage.

> In order for my hash calculation to produce the same results I need to
> include that same key in the same way that C# class initializer
> does.

And so you must obtain this info from them because both parties must
use the same key[s]. Consult with them about this since it's them who
must validate you (and thus your data) as a valid user. What's
imperitive is that both parties use the same keys. Once you get this
info then simply load it into your variable and create the hash. -OR-
Make up your own keys, create the hash, and send them the resulting
serial key to store as your validation key. (H1:H5, which is what I
think you want)

All that Key1:Key4 do is store individual bits of data that's used by
SHA1() to return the H1:H5 serial key in this format:
00000000 00000000 00000000 00000000 00000000

The Key1:Key4 values can be made up of any amount of source info by
doing something like this:

Sub MakeHashKeys()
Const LetterChars As String = _
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz "
Const str1 As String = "1931162853"
'"John Doe" (1st 10 digits in the letter positions of your name?)
Const str2 As String = "12345678"
'(numerals only of your birthday?)
Const str3 As String = "123456789"
'(numerals only of your Social Security Number?)
Const str4 As String = "1234567890"
'(1st 10 digits of the letter positions of something else?)

Dim sKey1 As String, sKey2 As String, sKey3 As String, sKey4 As
String
Dim lKey1 As Long, lKey2 As Long, lKey3 As Long, lKey4 As Long

sKey1 = Left$(str1, 2) + Right$(str2, 2) + Mid$(str3, 5, 2)
lKey1 = CLng(sKey1)
sKey2 = Left$(str3, 3) + Mid$(str1, 3, 3)
lKey2 = CLng(sKey2)
sKey3 = Right$(str4, 3) + Right$(str3, 2) + Mid$(str2, 2, 3)
lKey3 = CLng(sKey3)
sKey4 = Left$(sKey1, 1) + Right$(sKey2, 1) + Mid$(sKey3, 1)
lKey4 = CLng(sKey4)

Debug.Print lKey1 & vbTab & lKey2 & vbTab & lKey3 & vbTab & lKey4
End Sub

Garry


From: Schmidt on

"Steve" <sredmyer(a)rfcorp.com> schrieb im Newsbeitrag
news:35abbd9d-ac30-4b9a-8547-82db5230405b(a)r9g2000vbk.googlegroups.com...

> The problem I am having is with adding the "secrect key"
> portion. In the C# code (used by the website) the
> "secret key" is integrated into the hash by the line:
> HMACSHA1 hasher = new HMACSHA1(sharedSecretBytes);
> Where "sharedSecretBytes" is a string variable defined earlier.

The above should already focus your attention on:
"How to create an HMAC-SHA1?" ;-)

Please read further on:
http://en.wikipedia.org/wiki/HMAC

....regarding how to create such an HMAC-Value in
conjunction with an underlying "Workhorse-HashFunction".

The above C#-class-type: HMACSHA1
IMO just splits the usual Function-Definition:
Function HMAC_SHA1(MsgBytes() as Byte, Key As StringOrByteArray)

into two parts - the Key already given in the constructor -
and the HMAC-encoding of the message followed later on -
thereby omitting the Key-Param, since it is already known to the
Class internally (by the constructor).


Here's an example, which implements that already in VB6 -
it is using an SHA1-function as the workhorse, which is
built into the cCrpt-Class, which is part of my toolset,
but as you wrote - you seem to already have a well working
"normal SHA1"-function, so just replace all the calls:
Crpt.SHA1 which are used in the Demo with your own function.

Would be good, if you adapt the Params of your
own SHA1-workhorse first, to be fully compatible
with Crpt.SHA1 which has the following Signature:

Function SHA1(Src() As Byte, _
Optional Byval asHexString As Boolean)
'...your implementation-calls
End Function

If the optional Param above is omitted or False, then this
"Variant-returning Function" delivers a ByteArray with the
20 SHA1-Bytes - otherwise the HexByteContent as a String.

As said, the above is only, to adapt your already
existing "normal" SHA1-Function to the one, which
is used in the HMAC-example which now follows:

'***Into a Form

Option Explicit

Private Crpt As New cCrypt '<- this RichClient-Class implements an SHA1

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


Private Sub Form_Load()
Dim i&, Key() As Byte

Debug.Print "Example 0: normal SHA1-HexOutput for a given string: abc"
Debug.Print "a9993e364706816aba3e25717850c26c9cd0d89d"
Debug.Print Crpt.SHA1(StrConv("abc", vbFromUnicode), True); vbCrLf

'the next three examples are covering different inputs as described in:
'http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf

Debug.Print "Example 1: HMAC_SHA1-Output for a Key, 64 Bytes long..."
ReDim Key(0 To 63)
For i = 0 To 63: Key(i) = i: Next
Debug.Print "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a"
Debug.Print HMAC_SHA1("Sample #1", Key); vbCrLf


Debug.Print "Example 2: HMAC_SHA1-Output for a Key, 20 Bytes long..."
Debug.Print "0922d3405faa3d194f82a45830737d5cc6c75d24"
Debug.Print HMAC_SHA1("Sample #2", "0123456789:;<=>?@ABC"); vbCrLf


Debug.Print "Example 3: HMAC_SHA1-Output for a Key, 100 Bytes long..."
ReDim Key(0 To 99)
For i = 0 To 15: Key(&H0 + i) = &H50 + i: Next
For i = 0 To 15: Key(&H10 + i) = &H60 + i: Next
For i = 0 To 15: Key(&H20 + i) = &H70 + i: Next
For i = 0 To 15: Key(&H30 + i) = &H80 + i: Next
For i = 0 To 15: Key(&H40 + i) = &H90 + i: Next
For i = 0 To 15: Key(&H50 + i) = &HA0 + i: Next
For i = 0 To 3: Key(&H60 + i) = &HB0 + i: Next
Debug.Print "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa"
Debug.Print HMAC_SHA1("Sample #3", Key); vbCrLf
End Sub


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

If VarType(Msg) = vbString Then
M = StrConv(Msg, vbFromUnicode)
Else 'we assume a byte-array now, and provoce 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 provoce 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 = Crpt.SHA1(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 = Crpt.SHA1(iPad) '... and calculate IntermediateSHA1

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

HMAC_SHA1 = Crpt.SHA1(oPAD,True) 'and give back the final SHA1HMAC as Hex
End Function


HTH

Olaf


From: GS on
Schmidt pretended :
> "Steve" <sredmyer(a)rfcorp.com> schrieb im Newsbeitrag
> news:35abbd9d-ac30-4b9a-8547-82db5230405b(a)r9g2000vbk.googlegroups.com...
>
>> The problem I am having is with adding the "secrect key"
>> portion. In the C# code (used by the website) the
>> "secret key" is integrated into the hash by the line:
>> HMACSHA1 hasher = new HMACSHA1(sharedSecretBytes);
>> Where "sharedSecretBytes" is a string variable defined earlier.
>
> The above should already focus your attention on:
> "How to create an HMAC-SHA1?" ;-)
>
> Please read further on:
> http://en.wikipedia.org/wiki/HMAC
>
> ...regarding how to create such an HMAC-Value in
> conjunction with an underlying "Workhorse-HashFunction".
>
> The above C#-class-type: HMACSHA1
> IMO just splits the usual Function-Definition:
> Function HMAC_SHA1(MsgBytes() as Byte, Key As StringOrByteArray)
>
> into two parts - the Key already given in the constructor -
> and the HMAC-encoding of the message followed later on -
> thereby omitting the Key-Param, since it is already known to the
> Class internally (by the constructor).
>
>
> Here's an example, which implements that already in VB6 -
> it is using an SHA1-function as the workhorse, which is
> built into the cCrpt-Class, which is part of my toolset,
> but as you wrote - you seem to already have a well working
> "normal SHA1"-function, so just replace all the calls:
> Crpt.SHA1 which are used in the Demo with your own function.
>
> Would be good, if you adapt the Params of your
> own SHA1-workhorse first, to be fully compatible
> with Crpt.SHA1 which has the following Signature:
>
> Function SHA1(Src() As Byte, _
> Optional Byval asHexString As Boolean)
> '...your implementation-calls
> End Function
>
> If the optional Param above is omitted or False, then this
> "Variant-returning Function" delivers a ByteArray with the
> 20 SHA1-Bytes - otherwise the HexByteContent as a String.
>
> As said, the above is only, to adapt your already
> existing "normal" SHA1-Function to the one, which
> is used in the HMAC-example which now follows:
>
> '***Into a Form
>
> Option Explicit
>
> Private Crpt As New cCrypt '<- this RichClient-Class implements an SHA1
>
> Private Declare Sub RtlMoveMemory Lib "kernel32" _
> (Dst As Any, Src As Any, ByVal LenBytes As Long)
>
>
> Private Sub Form_Load()
> Dim i&, Key() As Byte
>
> Debug.Print "Example 0: normal SHA1-HexOutput for a given string: abc"
> Debug.Print "a9993e364706816aba3e25717850c26c9cd0d89d"
> Debug.Print Crpt.SHA1(StrConv("abc", vbFromUnicode), True); vbCrLf
>
> 'the next three examples are covering different inputs as described in:
> 'http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
>
> Debug.Print "Example 1: HMAC_SHA1-Output for a Key, 64 Bytes long..."
> ReDim Key(0 To 63)
> For i = 0 To 63: Key(i) = i: Next
> Debug.Print "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a"
> Debug.Print HMAC_SHA1("Sample #1", Key); vbCrLf
>
>
> Debug.Print "Example 2: HMAC_SHA1-Output for a Key, 20 Bytes long..."
> Debug.Print "0922d3405faa3d194f82a45830737d5cc6c75d24"
> Debug.Print HMAC_SHA1("Sample #2", "0123456789:;<=>?@ABC"); vbCrLf
>
>
> Debug.Print "Example 3: HMAC_SHA1-Output for a Key, 100 Bytes long..."
> ReDim Key(0 To 99)
> For i = 0 To 15: Key(&H0 + i) = &H50 + i: Next
> For i = 0 To 15: Key(&H10 + i) = &H60 + i: Next
> For i = 0 To 15: Key(&H20 + i) = &H70 + i: Next
> For i = 0 To 15: Key(&H30 + i) = &H80 + i: Next
> For i = 0 To 15: Key(&H40 + i) = &H90 + i: Next
> For i = 0 To 15: Key(&H50 + i) = &HA0 + i: Next
> For i = 0 To 3: Key(&H60 + i) = &HB0 + i: Next
> Debug.Print "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa"
> Debug.Print HMAC_SHA1("Sample #3", Key); vbCrLf
> End Sub
>
>
> 'if you pass ByteArrays directly, then ensure they have an LBound at Zero
> Function HMAC_SHA1(Msg, Key)
> Dim i&, M() As Byte, K() As Byte, LenKey&
> Dim oPAD() As Byte, iPad() As Byte, IntermediateSHA1() As Byte
>
> If VarType(Msg) = vbString Then
> M = StrConv(Msg, vbFromUnicode)
> Else 'we assume a byte-array now, and provoce 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 provoce 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 = Crpt.SHA1(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 = Crpt.SHA1(iPad) '... and calculate IntermediateSHA1
>
> RtlMoveMemory oPAD(64),IntermediateSHA1(0), 20 'append the result to oPad
>
> HMAC_SHA1 = Crpt.SHA1(oPAD,True) 'and give back the final SHA1HMAC as Hex
> End Function
>
>
> HTH
>
> Olaf

Ahh! -NOW I see what you're trying to do. The wrapper I have for SHA1
only requires the Message string. It does the rest internally. I was
offering something altogether different! Geez.., so very sorry about
that!

So the formatted hash that I get returned by passing Larry's string
("Is 16 correct???") is:
2B1F8F6E 7A6E0B4C 96826247 452E5B82 60FD2302

The wrapper is a class authored by Peter Girard and David Midkiff
(clsSHA.cls), which has apparently been optimized for VB usage. Can you
confirm if your wrapper returns the same hash as shown here. I don't
use it because I prefer the using clsSHA256.cls that ships with the
same package (vbCrypto). So if it returns the same hash I'll try to
find where I got this from and post if the OP (or anyone else) is
interested to have it.

Garry


From: Schmidt on

"GS" <GS(a)discussions.microsoft.com> schrieb im Newsbeitrag
news:eYQgnHJ8KHA.5808(a)TK2MSFTNGP02.phx.gbl...

[HMACS in conjunction with their underlying HashFunction]

> Ahh! -NOW I see what you're trying to do. The wrapper
> I have for SHA1 only requires the Message string.
Yeah - and if such a Wrapper-Class does not have
some "Properties" as e.g. .SecretKey or .HMACKey,
or offers no chance, to provide them with such a Key at
"construction-time" - then this is (usually) just a "plain Hash-
Implementing Class without additional HMAC-support".


> So the formatted hash that I get returned by passing Larry's string
> ("Is 16 correct???") is:
> 2B1F8F6E 7A6E0B4C 96826247 452E5B82 60FD2302

The same output is generated here as the result of calling
just a plain Crpt.SHA1 method - since the cCrypt-Class of
dhRichClient3 also has neither direct, nor indirect HMAC-
creation-support built-in currently:
Dim MsgBytes() as Byte
MsgBytes = StrConv("Is 16 correct???", vbFromUnicode)
Debug.Print cCrpt.SHA1(MsgBytes, True) '<- True forces HexOutput
2b1f8f6e7a6e0b4c96826247452e5b8260fd2302

Olaf


From: GS on
Schmidt wrote on 5/10/2010 :
> "GS" <GS(a)discussions.microsoft.com> schrieb im Newsbeitrag
> news:eYQgnHJ8KHA.5808(a)TK2MSFTNGP02.phx.gbl...
>
> [HMACS in conjunction with their underlying HashFunction]
>
>> Ahh! -NOW I see what you're trying to do. The wrapper
>> I have for SHA1 only requires the Message string.
> Yeah - and if such a Wrapper-Class does not have
> some "Properties" as e.g. .SecretKey or .HMACKey,
> or offers no chance, to provide them with such a Key at
> "construction-time" - then this is (usually) just a "plain Hash-
> Implementing Class without additional HMAC-support".
>
>
>> So the formatted hash that I get returned by passing Larry's string
>> ("Is 16 correct???") is:
>> 2B1F8F6E 7A6E0B4C 96826247 452E5B82 60FD2302
>
> The same output is generated here as the result of calling
> just a plain Crpt.SHA1 method - since the cCrypt-Class of
> dhRichClient3 also has neither direct, nor indirect HMAC-
> creation-support built-in currently:
> Dim MsgBytes() as Byte
> MsgBytes = StrConv("Is 16 correct???", vbFromUnicode)
> Debug.Print cCrpt.SHA1(MsgBytes, True) '<- True forces HexOutput
> 2b1f8f6e7a6e0b4c96826247452e5b8260fd2302
>
> Olaf

Thanks Olaf!
So your Example1 in the previous post is a VB6 implementation of
HMAC_SHA1, then? Are you saying that this will generate the 4 keys the
OP requires to create his hash? (assuming it must be 64byte) How does
this compare to Larry's solution in terms of his end result being
HMAC_SHA1 compliant?

Thanks for the interest!
Garry