-
2 Attachment(s)
[VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Title
HS256, a class for calculating HMAC-SHA-256 from a Key and Data in VB6.
note:
HS1 (HMAC-SHA-1) also included now. Scroll down to the latest versions of both!
Description
The HS256 class uses Windows Crypto API calls wherever possible to calculate HMACs (Hash-based Message Authentication Codes) based on SHA 256 hashes. The class also provides formatting functions between binary data and Strings (Base64, Hex, and Hex variations) as well as converting Strings to and from UTF8 encoding.
All of these things are useful in creating message authentication strings for many purposes. These HMACs are needed in message authentication for the SOAP and REST APIs provided by many cloud computing services. They are also sometimes used to sign other types of messages (e.g. email).
Feature list
- HMAC-SHA-256 calculation without the use of any external cryptography components, relies on the Windows Crypto API.
- Translation of binary data to and from Base64 strings.
- Translation of binary data to and from Hex strings (several variations such as Hex with address and ASCII).
- Translation of standard "Unicode" (UTF16-LE) String data to and from UTF8 encoding.
Screenshot
Screenshot of the (attached) demo shown below.
Author name
Bob Riemersma
System requirements
Requires Windows XP or later. May require XP SP1 or SP2 (Crypto API documentation is not explicit on this point). Some minor format variations are emulated under Windows XP instead being performed via Crypto API calls, one minor sub-variation is only available in Windows 2003 R2, Vista, or later.
No special processor, disk, or memory requirements. Requires Visual Basic 6.0 development system, preferably Service Pack 6b or later, Standard Edition or better.
License info
This software is released into the Public Domain. It may be used for any purpose as is or in derivative works. No warranty of fitness or merchantability, and no support is offered. This source code is available AS IS.
Usage
Add the class module to your VB6 project. See comments at the head of the source regarding use of the methods and properties provided.
The demonstration project
The HS256 class is posted here as part of a demo program.
This program demonstrates the 7 SHA-256 Test Case vector sets found in RFC 4231:
Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256,
HMAC-SHA-384, and HMAC-SHA-512
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256 Using Crypto API
Update.
Version 2.0 of the HS256 class:
- Cleanup of extraneous comments.
- Revised object model allows more efficient calculation of multiple HMACs using the same key.
- Added MD5 hash function, often needed in programs using HMACs.
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256 Using Crypto API
WSTime
This is a pair of classes meant to be used as an adjunct to the HMAC-SHA-256 class when working with Web Services, primarily REST APIs like those of Azure or AWS.
Caveats, license terms, etc. are the same as spelled out for HS256 above.
These classes are identical in their methods, and format VB6 Date values to/from HTTP (RFC 1123) and ISO 8601 timestamp strings with time zone conversion.
WinHttpTime uses entrypoints in winhttp.dll
WinInetTime uses entrypoints in wininet.dll
A normal program would never use both classes. The idea was to avoid having to load both DLLs (oleaut32.dll and wininet.dll) for a program using WinHttpRequest. However I believe the VB6 runtime always loads wininet.dll and probably both for the process anyway, which probably makes WinHttpTime entirely redundant (i.e. always use WinInetTime).
The classes are declared so that they produce a default instance (PredeclaredId = True). Programs using these classes don't have to create an instance, there will be a global instance named the same as the class.
This is not true of the HS256 class, since you might well need several instances, all initialized to different keys.
The attachment is a trivial demo containing and showing the operation of both classes.
Note: To clarify, these two classes are two ways of doing the same things.
-
2 Attachment(s)
Re: [VB6] HMAC-SHA-256 Using Crypto API
Another update: Version 2.1
Minor cleanup.
Also... due to popular demand an HMAC-SHA-1 implementation created from the most recent HMAC-SHA-256 edition.
The demo incorporates test vectors from RFC 2202:
Test Cases for HMAC-MD5 and HMAC-SHA-1
Please verify these further if you have other known test cases. We'd like to have these cleaned up so people can rely on them. Looking good so far though!
These two Classes are separate since a program normally would only need one or the other, which is also why many auxiliary functions are duplicated between them.
-
Re: [VB6] HMAC-SHA-256 Using Crypto API
This HMAC SHA256 implementation has helped me greatly. Thanks!
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Great! Glad somebody else got some use out of it.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I just read this post and I'm hoping you can help me out. I am a VB6 programmer, but until recently I knew nothing about XML and currently still know nothing about HMAC SHA-256 encryption.
The company I'm working for needs to me to develop an Amazon app to download our order information and Amazon requires a "Signature" parameter to be inserted in their XML queries. This needs to be (forgive me if I state this awkwardly as I barely know what I'm talking about) the result of some parameters encrypted using HMAC SHA-256 and then converted to HMAC Base 64.
From the looks of your sample program, I can see that this may be able to give me the information I need. I've downloaded it and I can run it and see the results, but really what I need is a simple VB6 function to convert a key and data string to SHA-256 and perhaps I just haven't had enough sleep, but I can't figure out where that is in your program.
Could you give a tired, slightly dim programmer a nudge in the right direction? Thanks!
-
2 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I hope this helps.
Going through the AWS SimpleDB documentation for REST Authentication I find the docs are good but not great. They leave out small tidbits and swing between specific and vague on important things like character encoding, what precisely they mean by "newline" and other small things. HS256 itself took some work, but figuring out the AWS "canonicalization" process is a small nightmare. They outline the steps but leaving you hanging here and there on specifics.
They even give an example but don't show what the final Signature should be, making verification of my example here difficult.
In any case, the example attached here is way stripped down but with copious comments. In those comments I have made notes about a few points you may need to get clarification on. Try the AWS developer support forums for answers.
Keep in mind that different Amazon Services have different requirements. Grab all of the docs they offer (old and new) for the Service you need to use.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
That is awesome! Thank you! I'm still not quite there because I can't figure out what string Amazon wants to add to the key (which is presumably my AWS Access Key ID) to arrive at the signature string.
They've provided me with a link to tool called the MWS Scratchpad, and from there, I can see that the signature changes all the time, so I think the timestamp must be included in the string to process somehow? I've sent them a support email request and it's been a couple of days and they haven't answered - they are pretty slow with this generally.
https://mws.amazonservices.com/scratchpad/index.html
Thanks again, this helps me out immensely!
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Yes, a fresh Timestamp is probably one of the headers you need for the Marketplace Web Service (or whatever it is) much like the generalized AWS offerings. That and your Access Key ID header go into building the "string to sign." I'm sure their different services each have their own requirements for additional headers.
Some services may not use the "headers" of the "string to sign" as actual request headers, but instead send them as a parameter string (part of the URL). They may want a User-Agent header though (that does not seem to be part of the signature).
Perhaps the Scratchpad will help you get it all unraveled.
Good luck!
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
So, just in case I can't get any useful information out of Amazon, is there some way I can decode the signature that their MWS Scratchpad app gives me - it was created with (I think) my AWS Access Key ID and some mystery string. The Scratchpad gives me a value for "SHA 256 HMAC" (some big long incoherent string) and "Base64 HMAC" which is the value used for the Signature parameter.
Is there some way to take my AWS Access Key ID and one of the values they give me to decode the original string so I can look at it in text format? If I had that, I think I might be able to finish my app pretty quickly.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
No, it doesn't go backwards. These are one-way hash operations which is sort of the point. At Amazon's end they validate by taking your ID you sent, looking up the "secret key" in their database, and parts from the request contents and then doing the same calculation as you. Then they compare the signature they get with the one you sent.
So everything is critical from character encoding to order of operations, what gets included in the "string to sign" and what gets left out. It almost feels like 90% of the security of this process is how confusing it is to duplicate even based on their documentation. The "good news" is Azure and other services are just as bad about this.
I looked at MWS Scratchpad and the main benefit it might offer you is a way to validate your results without actually having to "hit" the service. You could compare the signature output by your code against the signature created by Scratchpad and tweak your code until you get the same thing.
The details for MWS are described starting at Page 11 of this document:
https://images-na.ssl-images-amazon....159025605_.pdf
You might even want to print out the pages about this topic and get out three colors of pens and 5 colors of highlighting markers and go at it studying hard.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
My primary use of this class is in an Access db with vba. Your class works for me through most of my environments, however..
I have two windows 7 machines and an xp machine. On one of the windows 7 machines the class fails during initialization on this line as a class within the Access db:
Vb Code:
ElseIf CryptAcquireContext(hAdvProvider, _
0&, _
StrPtr(strProvider), _
PROV_RSA_AES, _
CRYPT_VERIFYCONTEXT) = 0 Then
Err.Raise vbObjectError Or &HC368&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI RSA AES context, system error " _
& CStr(Err.LastDllError)
End If
However, your vb6 demo works fine on the same machine.
The class also works within the Access db on the other windows 7 machine and on the xp machine.
So it seems it can create a base provider but not an advanced provider (from within the Access Db):
Vb Code:
If CryptAcquireContext(hBaseProvider, _
0&, _
StrPtr(MS_DEFAULT_PROVIDER), _
PROV_RSA_FULL, _
CRYPT_VERIFYCONTEXT) = 0 Then
Err.Raise vbObjectError Or &HC366&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI Base context, system error " _
& CStr(Err.LastDllError)
ElseIf CryptAcquireContext(hAdvProvider, _
0&, _
StrPtr(strProvider), _
PROV_RSA_AES, _
CRYPT_VERIFYCONTEXT) = 0 Then
Err.Raise vbObjectError Or &HC368&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI RSA AES context, system error " _
& CStr(Err.LastDllError)
End If
Any guesses as to what the cause of this would be? Maybe a missing win7 service pack?
Thanks - and much appreciated!
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
What is unusual about the Windows 7 machine with the problem?
Do you have 64-bit Access installed on it?
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Good question. It's Access 2007 though, just like on the XP system. And actually on the other Win 7 machine I'm using Access 2010 and it works
:eek2:
system error -2146893799
So:
Win 7 Access 2010 -- works
Win 7 Access 2007 -- broken
XP Access 2007 -- works
And your demo I know works on both Win 7 systems.
Thanks...
Maybe it has to do with Administrator settings? I think a while ago I adjusted the (working) Win 7 to accept me as admin default.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Well I still wonder if Access 2007 64-bit might be involved.
Was there an error number (Err.LastDLLError)?
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Yes, the error number was -2146893799
So the only difference is that this is Access 2007 (x86) on Win 7 (x64).
This is not the 64bit version of Access.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Well this error is NTE_KEYSET_NOT_DEF (&H80090019) "The requested provider does not exist."
Very strange.
Are you somehow using Access in a non-interactive session?
Something to try, adding a flag bit. Make these changes:
Near the top
Code:
Private Const PROV_RSA_FULL As Long = 1
Private Const PROV_RSA_AES As Long = 24
Private Const CRYPT_VERIFYCONTEXT As Long = &HF0000000
Private Const CRYPT_MACHINE_KEYSET As Long = 32 <-- new Const
Private Const MS_DEFAULT_PROVIDER As String = _
"Microsoft Base Cryptographic Provider v1.0"
Private Const MS_ENH_RSA_AES_PROV As String = _
"Microsoft Enhanced RSA and AES Cryptographic Provider"
Private Const MS_ENH_RSA_AES_PROV_XP As String = _
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
Inside Class_Initialize
Code:
If CryptAcquireContext(hBaseProvider, _
0&, _
StrPtr(MS_DEFAULT_PROVIDER), _
PROV_RSA_FULL, _
CRYPT_VERIFYCONTEXT Or CRYPT_MACHINE_KEYSET) = 0 Then <-- add flag
Err.Raise vbObjectError Or &HC366&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI Base context, system error " _
& CStr(Err.LastDllError)
ElseIf CryptAcquireContext(hAdvProvider, _
0&, _
StrPtr(strProvider), _
PROV_RSA_AES, _
CRYPT_VERIFYCONTEXT Or CRYPT_MACHINE_KEYSET) = 0 Then <-- add flag
Err.Raise vbObjectError Or &HC368&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI RSA AES context, system error " _
& CStr(Err.LastDllError)
End If
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Sorry. Yes, I tried this. As well as another option:
Vb Code:
Private Const MS_DEF_PROV As String = "Microsoft Base Cryptographic Provider v1.0"
Private Const CRYPT_MACHINE_KEYSET As Long = &H20
None of it worked. I'm going to try using the OpenSSL commandline program from gnuwin32 site.
Thank you for helping me. Maybe at some later time after a service pack or something this will suddenly work.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Um... &H20 is the same as 32.
I've tested this code on a 64-bit Windows machine and it works fine there, and as you pointed out my demo program runs properly on your problem system as well.
Turning UAC off is almost always a poor idea. You seem to be grasping at straws but so am I at this point. Without more information I don't think I can help.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
hello,i want use your project to a vba project for amazon authentication,but i donot know howto include your code to my project .can you help me?
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Good luck with Amazon, that stuff is a bear as most Web Services are when you have to roll your own code.
I am attaching a demo Excel Workbook. It contains basically the same thing as in the VB6 demo. The Userform is shown via a Command Button I put on Sheet1 of the Workbook.
This doesn't try to do anything fancy, it simply shows how to use the Class from Excel. To get it there you just import the VB6 Class from within the VBA Editor IDE.
The Class didn't require any changes, though of course the Form-to-Userform logic required a few. ;)
I hope this helps a little.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Thank you . after several hours to understand how to include your class to vba project, i have attached my aim,thank you ,the hs256 class is very very very useful...
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I am trying to integrate your HS256 class into Access vba for integration into Amazon MWS and coming up with some problems.
I have successfully created a class HS256 using the HS256.cls in v2.1 above.
I have:
Dim hs256 As clsHS256
Dim bytekey() As Byte
hs256 = New clsHS256
bytekey = hs256.ToUTF8("MY-SECRET-KEY-HERE")
hs256.InitHmac (bytekey) ' <----- Error on this line
Erase bytekey
I get an error "Type mismatch: array or user defined type expected".
I get the same if I replace the line with
hs256.InitHmac (bytekey(0))
Any help any of you might be able to offer would be gratefully received. Alternatively does anyone have a working example of MWS integration into Access vba?
Getting MWS to integrate into Access is much harder than I expected and way harder than it should be!!!
Phill
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I worked it out myself.
It should read:
hs256.InitHmac bytekey
If anyone does have a working MWS integration example Access it would still be very much appreciated!
Phill
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Glad you caught the problem!
Sorry, I don't have any MWS code to share.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Glad with this thread dilettante, especially:
Quote:
I hope this helps.
Going through the AWS SimpleDB documentation for REST Authentication I find the docs are good but not great. They leave out small tidbits and swing between specific and vague on important things like character encoding, what precisely they mean by "newline" and other small things. HS256 itself took some work, but figuring out the AWS "canonicalization" process is a small nightmare. They outline the steps but leaving you hanging here and there on specifics.
They even give an example but don't show what the final Signature should be, making verification of my example here difficult.
In any case, the example attached here is way stripped down but with copious comments. In those comments I have made notes about a few points you may need to get clarification on. Try the AWS developer support forums for answers.
Keep in mind that different Amazon Services have different requirements. Grab all of the docs they offer (old and new) for the Service you need to use.
It's very nice,thank you.
Because general principle of OAuth is same (using HMAC-SHA1 or RSA-SHA1), what if made into OAuth Class (clsOAuth.cls) for generate a signature (it will be very useful), so with the signature generated by OAuth class (clsOAuth.cls) we can easily access:
- Amazon API
- Twitter API
- Google API
- Facebook API
- etc ... API with OAuth.
Because it's very hard to find in Google, OAuth Class created with VB6. I've tried to modify the code and make clsOAuth.cls but it always fails and displays the error message:
HTTP/1.1 401 Unauthorized or Invalid Signature and token.
Sorry for my english. Thank you.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I haven't tried working with OAuth. Have you looked at this:
http://developer.yahoo.com/oauth/gui...h-signing.html
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I'm having a (reasonably obscure?) problem with this class. I have it integrated into Access to support integration into Amazon MWS and it is providing the signatures correctly on my development system (Access 2007 on Windows XP running under Parallels on my Mac). When I put the code onto a production environment running the runtime version of Access (32 bit) on windows 2008 server 64 bit a different (incorrect) signature is calculated and so the calls fail.
Are there any diagnostics you could suggest I run to try to track down the problem?
Phill
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I tested the compiled VB6 examples and tested them on Server 2008 R2 64 bit. They work there just as expected. Server 2008 is a slightly different OS (Vista Server basically) but it shouldn't be all that different. The demos work as expected on both 32 and 64 bit Vista.
I'd tend to blame your issues on a divergence between VB6 and VBA in later Office versions, but if it works as expected under Access 2007 32-bit running under XP we can probably ignore that possibility.
So if it isn't at the OS and API level, and it isn't about differences between VB6 and later versions of VBA... we aren't left with many obvious things to suspect.
I'm not sure where to start trying to diagnose this except to log intermediate values at every step of the process, then compare the logged results from both of your run time environments.
The Encode() method may be helpful here for logging the Byte array values in hex & ascii. I'd log things to text files and then open each log in Notepad and tile them side-by-side for comparison.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Thanks, I will do that.
Before I start doing this please could you verify that the following routine (which I use to call your class) is calling it in the right way. In particular the last line.
Code:
Public Function getSignature(stringtosign As String)
Dim bytekey() As Byte
Dim hs256 As clsHS256
Set hs256 = New clsHS256
bytekey = hs256.ToUTF8(SecretKey)
hs256.InitHmac bytekey
Erase bytekey
Dim bytecqs() As Byte
bytecqs = hs256.ToUTF8(stringtosign)
'Create the Signature hash:
Dim byteSignature() As Byte
byteSignature = hs256.HmacSha256(bytecqs)
Erase bytecqs
'Convert the Signature to Base64:
getSignature = hs256.Encode(byteSignature, edfBase64, efNoFolding)
Erase byteSignature
getSignature = Left$(getSignature, Len(getSignature) - 2)
End Function
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
To verify things I stuck your vb RFC 4231 test routines into vba and ran on both XP with Access 2007 and on windows server 2008 64 bit with the access runtime environment. The results were identical and correct so your code works perfectly. I must be doing something wrong in the code in my earlier post.
Phill
My vba version of your test routines is below for completeness.
Code:
Option Compare Database
Option Explicit
'HMAC-SHA-256 Test vectors from RFC 4231:
'
' Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256,
' HMAC-SHA-384, and HMAC-SHA-512
Private Const TEST_KEYS As String = _
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" & "0b0b0b0b|" _
& "4a656665|" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaa|" _
& "0102030405060708090a0b0c0d0e0f10" & "111213141516171819|" _
& "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c" & "0c0c0c0c|" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaa|" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" _
& "aaaaaa"
Private Const TEST_DATA As String = _
"4869205468657265|" _
& "7768617420646f2079612077616e7420" & "666f72206e6f7468696e673f|" _
& "dddddddddddddddddddddddddddddddd" & "dddddddddddddddddddddddddddddddd" _
& "dddddddddddddddddddddddddddddddd" & "dddd|" _
& "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" & "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" _
& "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" & "cdcd|" _
& "546573742057697468205472756e6361" & "74696f6e|" _
& "54657374205573696e67204c61726765" & "72205468616e20426c6f636b2d53697a" _
& "65204b6579202d2048617368204b6579" & "204669727374|" _
& "54686973206973206120746573742075" & "73696e672061206c6172676572207468" _
& "616e20626c6f636b2d73697a65206b65" & "7920616e642061206c61726765722074" _
& "68616e20626c6f636b2d73697a652064" & "6174612e20546865206b6579206e6565" _
& "647320746f2062652068617368656420" & "6265666f7265206265696e6720757365" _
& "642062792074686520484d414320616c" & "676f726974686d2e"
Private Const TEST_EXPECTED As String = _
"b0344c61d8db38535ca8afceaf0bf12b" & "881dc200c9833da726e9376c2e32cff7|" _
& "5bdcc146bf60754e6a042426089575c7" & "5a003f089d2739839dec58b964ec3843|" _
& "773ea91e36800e46854db8ebd09181a7" & "2959098b3ef8c122d9635514ced565fe|" _
& "82558a389a443c0ea4cc819899f2083a" & "85f0faa3e578f8077a2e3ff46729665b|" _
& "a3b6167473100ee06e0c796c2955552b|" _
& "60e431591ee0b67f0d8a26aacbf5b77f" & "8e0bc6213728c5140546040f0ee37f54|" _
& "9b09ffa71b942fcb27635fbcd5b0e944" & "bfdc63644f0713938a7f51535c3a35e2"
Private Const TEST_DESCRIPTIONS As String = _
"Case 1|" _
& "Case 2 - key shorter than the length of the HMAC output|" _
& "Case 3 - combined length of key and data > 64 bytes|" _
& "Case 4 - combined length of key and data > 64 bytes|" _
& "Case 5 - truncation of output to 128 bits|" _
& "Case 6 - key larger than 128 bytes|" _
& "Case 7 - key and data that is larger than 128 bytes"
Private strKeys() As String
Private strData() As String
Private strExpected() As String
Private strDescriptions() As String
Private HS256 As clsHS256
Private Function Fold(ByVal S As String) As String
With HS256
S = .Encode(.Decode(S), edfHexAsciiAddr, efCrLf)
End With
S = vbTab & Replace$(S, vbNewLine, vbNewLine & vbTab)
Fold = Left$(S, Len(S) - 1)
End Function
Public Sub testSHAvectors()
Dim intCase As Integer
Dim bytSig() As Byte
strKeys = Split(TEST_KEYS, "|")
strData = Split(TEST_DATA, "|")
strExpected = Split(TEST_EXPECTED, "|")
strDescriptions = Split(TEST_DESCRIPTIONS, "|")
Set HS256 = New clsHS256
For intCase = 0 To 6 '1 (one) less than RFC 4231 case numbers.
logtofile (strDescriptions(intCase) & " —" & vbNewLine)
logtofile ("Key:" & vbNewLine & Fold(strKeys(intCase)))
logtofile ("Data:" & vbNewLine & Fold(strData(intCase)))
With HS256
.InitHmac .Decode(strKeys(intCase))
bytSig = .HmacSha256(.Decode(strData(intCase)))
If intCase = 4 Then ReDim Preserve bytSig(15) 'Truncate to 128 bits ("Case 5").
logtofile ("HmacSha256 result:" & vbNewLine _
& Fold(.Encode(bytSig)))
End With
logtofile ("Expected (RFC) result:" & vbNewLine & Fold(strExpected(intCase)))
Next
End Sub
Public Sub logtofile(text As String)
Dim bd As String
Dim fn As String
Dim FNum As Integer
FNum = FreeFile
bd = BaseDir()
fn = bd & "/SIGNATURETESTS.txt"
If fIsFileDIR(fn) Then
Open fn For Append Access Write As #FNum
Else
Open fn For Output Access Write As #FNum
End If
Print #FNum, text; vbNewLine
Close #FNum
End Sub
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Your calls look good.
If the code returns the same results then we have good news and bad I guess. Sorry I couldn't be more helpful.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
OK. Have resolved it now.
I don't understand why, but on Windows XP vba the encode method is returning the 2 extra characters CRLF at the end of the string. This is not the case for the exact same code on my copy of windows server 2008 SP2.
I now test to see if the code is running under windows server 2008 or not, deleting the last 2 extra characters only if not and all works fine.
In case anyone else has this pain in the future, code is below. Thanks for your advice earlier.
Code:
Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type
Private Declare Function GetVersionEx Lib "kernel32" _
Alias "GetVersionExA" (lpVersionInformation As _
OSVERSIONINFO) As Long
' returns true if running on windows server2008
Public Function Is2008() As Boolean
Dim oOSInfo As OSVERSIONINFO
oOSInfo.dwOSVersionInfoSize = Len(oOSInfo)
GetVersionEx oOSInfo
If oOSInfo.dwMajorVersion = 6 Then
Is2008 = True
Else
Is2008 = False
End If
End Function
Public Function getSignature(stringtosign As String) As String
Dim bytekey() As Byte
Dim signaturecalculated As String
Set HS256 = New clsHS256
bytekey = HS256.ToUTF8(SecretKey)
HS256.InitHmac bytekey
Erase bytekey
Dim bytecqs() As Byte
bytecqs = HS256.ToUTF8(stringtosign)
'Create the Signature hash:
Dim byteSignature() As Byte
byteSignature = HS256.HmacSha256(bytecqs)
Erase bytecqs
'Convert the Signature to Base64:
signaturecalculated = HS256.Encode(byteSignature, edfBase64, efNoFolding)
Erase byteSignature
If Not Is2008 Then
getSignature = Left$(signaturecalculated, Len(signaturecalculated) - 2)
Else
getSignature = signaturecalculated
End If
End Function
-
2 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Ok, I think that helps explain what was going wrong. The problem was in encoding the result to Base64 with no "folding."
There are a number of things that differ between OS versions. XP uses an earlier name for the Enhanced RSA and AES Cryptographic Provider (yet at least late Server 2003 does not, could this be service packs or the R2 release?) and both XP and Server 2003 have some formatting limitations in their CryptBinaryToString() flags. The latter is why you saw a trailing CRLF when you encoded to Base64.
Your fix will work for you, but it isn't really a general fix since Encode() can work on longer Byte arrays where you'd get CRLFs within the Base64 string as well as at the end.
What I've done is modify the OS version sniffing logic and added a second version Boolean. Along with the new blnIsWin5_1 I've also added the kludge-code needed to accomodate these older OSs. I did the same for my HS1 class as well to head off problems for anyone using that code.
Everything tests out good here, including a separate test program to specifically look for the problem you had found.
The new HS256 package also includes the Excel demo, with the same update (a separate .ZIP file within the main .ZIP file). This .XLS is the large item that makes the HS256 package so big compared to the HS1 package.
I believe these updates address the issue, but feedback is always welcome.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I'm running Windows 7 Ultimate
When I run this code in VB6, I get an error "Failed to obtain CryptoAPI RSA AES context, system error -2146893799"
This error occurs in the Class_Initialize function. GetVersionEx is returning the following values:
dwBuildNumber = 2600
dwMajorVersion = 5
dwMinorVersion = 1
dwOSVersionInfoSize = 156
dwPlatformId = 2
szCSDVersion = "Service Pack 3"
wProductType = 1
wReserved = 0
wServicePackMajor = 3
wServicePackMinor = 0
wSuiteMask = 256
Control Panel -> System and Security -> System returns the following information:
Windows Edition: Windows 7 Ultimate, Service Pack 1
64-bit Operating System
I don't understand why the API would return incorrect information. Do you have any suggestions for me?
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Nevermind.
I was running this code in the IDE, and I had configured VB6 to run in Windows XP (Service Pack 3) compatibility mode. If anyone else runs in to this issue, check your compatibility settings prior to pulling your hair out.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Wow, I had no idea anyone does this. It can break lots of code because of the "version lie" appcompat shim.
As an alternative I suppose the code could try for the current crypto context name and only try the legacy XP name upon failure. But that still leaves other issues not as easily handled indirectly.
Glad you found it though. I can see where it might get frustrating to track down.
-
2 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Here is a demo using my HS1 class to create signatures for use with Google Maps API for Business.
The inputs are pre-loaded with the same sample values shown at Authentication and Authorization: Signature Examples.
One thing to note is that the sample URL there mistakenly shows braces (i.e. {}) around the value "clientID" and if you use those you will not get the proper results. This just appears to be a flaw in the posted sample URL.
The demo program uses multiline TextBoxes for I/O, though the values are not on multiple lines (the long text just wraps).
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I have added another rendition of the Google Maps API for Business "signer" logic.
Testing code and such have been removed, redundant intermediate variables have been removed, and more formalized URL parsing is used. The result is probably more directly usable in real applications.
Here we have a class GoogleMapsSigner with a single method Sign(). It is dependent on the HS1 class.
To use these in VB6 just add both class modules to your Project. They should also import into Office VBA easily enough as well (Access, Excel) but have not been tested in 64-bit Office applications which might require tweaking due to the changes in integer types there.
The attachment has both of the necessary class modules as well as a test Project similar to the one above.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
You demo work great, but when I try to throw my own data at it, I get: ""Failed to determine decoded length, system error ", "System Error 13"
Any Ideas?
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Nevermind, found the answer above!
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Glad you found it. The version lie seems to be a common problem. I guess a lot of people are lying to VB6.exe by setting some "XP compatibility" option though I don't know what they expect that to buy them except trouble.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Solved
The Encoder was generating a result of: mQIrKnsvUpMQ/rGUe/mAv5xFvpwoqwCRAB1YsYa7YM8=
But the host is calculating/expecting: mz6rcXAtV3Qyx7DqnxQ/0PY8/wj8prf3ON3Dyt22dtk=
I am following the sample project:
Code:
Dim StringToSign As String
StringToSign = signable_string
Dim bytStringToSign() As Byte
bytStringToSign = HS256.ToUTF8(StringToSign)
StringToSign = ""
Dim bytSecretKey() As Byte
bytSecretKey = HS256.ToUTF8(ESL_Settings.PrivateKey)
'Initialize the HMAC with our Key:
HS256.InitHmac bytSecretKey
Erase bytSecretKey
'Create the Signature hash:
Dim bytSignature() As Byte
bytSignature = HS256.HmacSha256(bytStringToSign)
Erase bytStringToSign
'Convert the Signature to Base64:
Dim Base64Signature As String
Base64Signature = HS256.Encode(bytSignature, edfBase64, efNoFolding)
Erase bytSignature
Debug.Print Base64Signature
This line is expecting CrLf
Code:
Base64Signature = HS256.Encode(bytSignature, edfBase64, efNoFolding)
I was send Lf Only
so the correct command is:
Code:
Base64Signature = HS256.Encode(bytSignature, edfBase64, efLf)
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
As long as you got what you need, but...
I don't see how that would have made a difference. That only specifies how long runs of Base64 encoded data are to be wrapped/folded. And of course when running on the now unsupported and dead Windows XP there are issues because the efNoFolding values is not supported there.
In any case that would have no bearing on the output of the HmacSha256() method. Surely there was something else going on.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Well, I guess it did not work.
For some reason it worked once (Or appeared to).
Input string: (Each line ends in a Chr$(10))
Output from Class:
au9MEWefulSThFOdIIzt796TU1uhbeSZWu1NAe6+aac=
Output from Server:
Ig/pGE6kkRC8I370J2OTek3cGVgK5aEoSFGs1jD1FXk=
I tried this VB.Net2008 code and it works, but the project is in VB6
Code:
Public Shared Function HashString(ByVal StringToHash As String, ByVal PrivateKey As String) As String
Dim myEncoder As New System.Text.UTF8Encoding
Dim Key() As Byte = myEncoder.GetBytes(PrivateKey)
Dim Text() As Byte = myEncoder.GetBytes(StringToHash)
Dim myHMACSHA1 As New System.Security.Cryptography.HMACSHA256(Key)
Dim HashCode As Byte() = myHMACSHA1.ComputeHash(Text)
Return Convert.ToBase64String(HashCode)
End Function
Any ideas would be great
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Quote:
Originally Posted by
XardozCom
Well, I guess it did not work.
For some reason it worked once (Or appeared to).
Input string: (Each line ends in a Chr$(10))
87c9320aa8834dffbf5887046713187a
1411317388
POST
/e/csl/products/update
Output from Class:
au9MEWefulSThFOdIIzt796TU1uhbeSZWu1NAe6+aac=
Output from Server:
Ig/pGE6kkRC8I370J2OTek3cGVgK5aEoSFGs1jD1FXk=
I tried this VB.Net2008 code and it works, but the project is in VB6
...
Any ideas would be great
Would like to try to reproduce that here - but without *all* the needed Input
(which would include your PrivateKey-String) - this is not possible...
Olaf
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Exactly.
This needs its own question thread, as far as I can tell there is some usage error or program bug. Probably related to character encoding or something.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Can anyone help me to do an excel function that will take data as string, the key as string to do HMAC(SHA256(Data, Key)? Thanks!
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Post #22 above should have everything you need and more.
First you need to decide what your "string" values really mean since HMACs are created from raw bytes.
So perhaps your Key and/or Data are hex digits? Or maybe they are just printable characters? And if the latter you need to decide whether they need to be converted from Excel VBA's String type strings (i.e. UTF-16LE) to UTF-8 or ANSI or something because UTF-16LE would rarely be used to produce HMACs.
If you only use the ASCII subset of printable characters then ANSI conversion gives the same result as UTF-8 conversion, so that could be a quick and dirty solution (i.e. use the StrConv() function). Or you could call HS256's ToUTF8() method to be sure.
Once you have dealt with how your "string" data needs to be converted to Byte arrays you just call InitHmac() passing your Key and then call HmacSha256() passing your Data and getting back the HMAC value.
Once you have the HMAC value you need to decide how to use it, since it will be binary data. Perhaps you need it converted to hex? You can call Encode() to do that.
Beyond this I suggest you either (1.) get a programmer to help you, or (2.) start a question thread in the Office forum here.
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Please check HMAC-SHA-256 class module, because after I've implemented it in my project, program doesn't act correctly under Windows 8, but under XP it works as it should. To be clear - returned data from your class module is combined with some other data, and it returns expected results when I run program on XP, but on 8 it gives false data and program won't work correctly. Maybe API calls/parameters are different (I think I've read that somewhere regarding CryptoAPI)?
Edit: I see that it has a check for XP, and on Windows 8 it is set as True. Can you fix that? Thanks.
Edit 2: I was talking about HS256 Version 2.2. I've downloaded the latest version and the class won't even intialize (because it's not detecting Windows 8, it tries to initialize with XP parameter):
Attachment 128337
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
The class calls GetVersionEx() to determine the version of Windows in use.
This will always be correct unless a version-lie appcompat shim is being used. However starting in Windows 8.1 (not Windows 8) there is a version-lie that will report that Windows 8 is in use unless overridden using a manifest with a <compatibility/> node containing:
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
i.e. Windows 8.1 compatibility, or the new value for Windows 10 when running on Windows 10.
So what that means is that there should be no problem because the version is never reported as XP unless you have done something foolish like manually applying an appcompat shim telling Windows to lie to your program and say it is on XP.
How does this happen? Not by magic, but only by your own hand.
There is a lot of VERY BAD ADVICE going around telling people to manually mark VB6.EXE as retarded via Explorer properties ("Run this program in compatibility mode for..."). Don't do this, VB6 is not retarded. It is not only utterly unnecessary, it causes this very kind of problem.
Even when Windows 8.1 lies and tells the program it is running under Windows 8, this should be fine for the purposes of HS256.cls version 2.2 and 2.3 if not earlier versions as well. The Windows version only gets reported as XP if you have done something wrong, i.e. running in an XP compatibility mode.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
I have set VB6.EXE to XP SP3 compatibility mode because I have flicker problem with dragging controls in designer, therefore it's not without a reason. I'm using Windows 8 and still have these problems, so it not like you said.
It still gives me false data under Windows 8.
Edit:
I found the problem - it is in Encode/Decode function on this line of code:
Code:
If blnIsWinXP And (Format = edfHexRaw) Then
That is skipped because blnIsWinXP is set to False, but I've removed that check there and it works now as it should.
Also, in its initialization event I've removed system version check and changed it to much easier trial and error approach:
Code:
Private Sub Class_Initialize()
If CryptAcquireContext(hBaseProvider, _
0&, _
StrPtr(MS_DEFAULT_PROVIDER), _
PROV_RSA_FULL, _
CRYPT_VERIFYCONTEXT Or CRYPT_MACHINE_KEYSET) = 0 Then
Err.Raise vbObjectError Or &HC366&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI Base context, system error " _
& CStr(Err.LastDllError)
ElseIf CryptAcquireContext(hAdvProvider, _
0&, _
StrPtr(MS_ENH_RSA_AES_PROV), _
PROV_RSA_AES, _
CRYPT_VERIFYCONTEXT Or CRYPT_MACHINE_KEYSET) <> 0 Then Exit Sub
End If
If CryptAcquireContext(hAdvProvider, _
0&, _
StrPtr(MS_ENH_RSA_AES_PROV_XP), _
PROV_RSA_AES, _
CRYPT_VERIFYCONTEXT Or CRYPT_MACHINE_KEYSET) = 0 Then
Err.Raise vbObjectError Or &HC368&, _
"HS256.Class_Initialize", _
"Failed to obtain CryptoAPI RSA AES context, system error " _
& CStr(Err.LastDllError)
End If
End Sub
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Quote:
Originally Posted by
MikiSoft
I have set VB6.EXE to XP SP3 compatibility mode because I have flicker problem with dragging controls in designer, therefore it's not without a reason. I'm using Windows 8 and still have these problems, so it not like you said.
It still gives me false data under Windows 8.
It is exactly as I guessed, you are using a version-lie shim and you shouldn't be. This has nothing at all to do with any "flicker."
Quote:
Originally Posted by
MikiSoft
Edit:
I found the problem - it is in Encode/Decode function on this line of code:
Code:
If blnIsWinXP And (Format = edfHexRaw) Then
That is skipped because blnIsWinXP is set to False, but I've removed that check there and it works now as it should.
Also, in its initialization event I've removed system version check and changed it to much easier trial and error approach:
This is not a fix, but a hack. The version check is there for a reason. Put it back and stop using the version lie. You are only causing yourself more grief and the hack only creates further risk.
If you do this and you have future problems do not expect a response when you ask for help. Your "fix" is a really bad idea.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
It IS flickering when you drag or try to draw a control if you haven't set compatibility to XP SP3... Try it yourself if you don't believe me, it's really hard to design like that.
My solution works now on both Windows XP and 8, because you didn't helped me to solve the problem when compatibility is set, I resorted to the most trivial way.
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
Quote:
Originally Posted by
MikiSoft
My solution works now on both Windows XP and 8.... I resorted to the most trivial way.
Hi, What was your solution?
thx
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
He ghetto-rigged the code as he said above.
A better fix if you insist on using the version-lie shim is to first attempt to acquire the MS_ENH_RSA_AES_PROV context, and if that fails attempt to acquire the MS_ENH_RSA_AES_PROV_XP context. If that succeeds set blnIsWinXP = True and continue.
Instead he is sorta kinda doing that but he ripped out the blnIsWinXP checks and is taking the slow boat in other parts of the code.
All of this has a downside. I suspect he now has a lurking time bomb: if his code ever runs on Win 2003 Server it will probably give incorrect results.
There is absolutely no reason to apply an XP version-lie shim to VB6.EXE, and it has nothing to do with working with designers in the IDE. He probably can't mentally separate that from the appcompat shim that disables Aero (a.k.a. desktop composition).
-
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
An update to HS256:
This is mostly minor general cleanup, but it also revisits version sniffing to get past any usage of version-lie appcompat shims. It also improves the logic for dealing with "problem child" OSs (Windoww XP, Windows Server 2003) even though these are unsupported OSs I should really just ignore.
The Excel demo is also updated in this attachment.
-
1 Attachment(s)
Re: [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API
HMAC-SHA-512, implemented as HS512.cls:
This was fairly trivial to create from HS256 3.1, requiring only a change in the requested algorithm. It was far more effort just to go in and slap in the test vector "expteced result" values to display.
No Excel demo included, since that requires nothing more than some copy/paste operations. If you need to do this you can open the VB6 files in NotePad if nothing else.
Note:
I have not heavily tested HS512 1.1 or for that matter HS256 3.1, but they seem to be working fine. I think I tried HS256 3.1 on XP SP3 but I can't recall at the moment. Both seem to be working fine on Vista SP2, at least as far as the test vectors go.