# VBForums UtilityBank > UtilityBank - Components >  [VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API

## dilettante

*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*

----------


## dilettante

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.

----------


## dilettante

*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._

----------


## dilettante

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.

----------


## StevenHB

This HMAC SHA256 implementation has helped me greatly. Thanks!

----------


## dilettante

Great!  Glad somebody else got some use out of it.

----------


## adenke

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!

----------


## dilettante

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.

----------


## adenke

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!

----------


## dilettante

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!

----------


## adenke

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.

----------


## dilettante

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&#37; 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.

----------


## christianlott

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!

----------


## dilettante

What is unusual about the Windows 7 machine with the problem?

Do you have 64-bit Access installed on it?

----------


## christianlott

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 
 :Eek Boom: 

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.

----------


## dilettante

Well I still wonder if Access 2007 64-bit might be involved.

Was there an error number (Err.LastDLLError)?

----------


## christianlott

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.

----------


## dilettante

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_


```
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_


```
    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
```

----------


## christianlott

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.

----------


## dilettante

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.

----------


## qjhacker

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?

----------


## dilettante

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.  :Wink: 

I hope this helps a little.

----------


## qjhacker

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...

----------


## laz42

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

----------


## laz42

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

----------


## dilettante

Glad you caught the problem!

Sorry, I don't have any MWS code to share.

----------


## Karim Wafi

Glad with this thread dilettante, especially:



> 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 APITwitter APIGoogle APIFacebook APIetc ... 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.

----------


## dilettante

I haven't tried working with OAuth.  Have you looked at this:

http://developer.yahoo.com/oauth/gui...h-signing.html

----------


## laz42

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

----------


## dilettante

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.

----------


## laz42

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.



```
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
```

----------


## laz42

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.



```
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
```

----------


## dilettante

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.

----------


## laz42

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.




```
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
```

----------


## dilettante

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.

----------


## gmmastros

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?

----------


## gmmastros

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.

----------


## dilettante

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.

----------


## dilettante

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).

----------


## dilettante

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.

----------


## XardozCom

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?

----------


## XardozCom

Nevermind, found the answer above!

----------


## dilettante

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.

----------


## XardozCom

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:


```
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


```
Base64Signature = HS256.Encode(bytSignature, edfBase64, efNoFolding)
```

I was send Lf Only
so the correct command is:


```
Base64Signature = HS256.Encode(bytSignature, edfBase64, efLf)
```

----------


## dilettante

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.

----------


## 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))


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



```
    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

----------


## Schmidt

> 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
> 
> ...


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

----------


## dilettante

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.

----------


## berrystar

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!

----------


## dilettante

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.

----------


## MikiSoft

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):

----------


## dilettante

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.

----------


## 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.

Edit:
I found the problem - it is in Encode/Decode function on this line of 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: 

```
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
```

----------


## dilettante

> 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."




> Edit:
> I found the problem - it is in Encode/Decode function on this line of 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.

----------


## MikiSoft

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.

----------


## johnywhy

> My solution works now on both Windows XP and 8.... I resorted to the most trivial way.


Hi, What was your solution?
thx

----------


## dilettante

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).

----------


## johnywhy

OK, Thx!

----------


## dilettante

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.

----------


## dilettante

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.

----------


## MikiSoft

Well, I've got a report for HS512 class on Windows 8.1 64-bit that this error has shown:


And this is the code which is calling the class: 

```
With hs5
.InitHmac .ToUTF8(server_seed)
roll_hash = .Encode(.HmacSha512(.ToUTF8("1-" & i)))
End With
```

What it could be, how to solve it? On my Windows 7 32-bit it's working perfectly though.

----------


## MikiSoft

The one who sent me the screenshot from above corrected himself that he's using Windows 8.1 (not 8), so I've corrected that in the above post and searched for that error, and I've found this: http://stackoverflow.com/questions/1...nswer-19965034
Since its' cause is probably that system bug it can't be fixed, eh?

----------


## dilettante

Odd.

I just tried the demo program on a Windows 10 x64 system and it works fine there.

https://rcpmag.com/articles/2016/01/...-deadline.aspx




> As of Jan. 12, 2016, Windows 8 is now considered to be "unsupported" by Microsoft, meaning the company will no longer issues hotfixes or security updates for the operating system. Exceptions to this policy might be organizations that have purchased Microsoft's "custom support," but that option is thought to be an expensive one, with contracts lasting just a year.


So Windows 8 is dead anyway, but Win8.1 Update 1 (or is it Update 2?) should still be supported for a little while.  If somebody reports the bug there is a chance it might get fixed.  However they really, really, really want people to move off 8.x OSs entirely so maybe it won't.

----------


## DevJay

> Odd.
> 
> I just tried the demo program on a Windows 10 x64 system and it works fine there.


I can't get the HS256 class working with Windows 10 x64 Excel. All the "Declare Kernal32" functions are red and I get the following error:

----------


## DevJay

> Odd.
> 
> I just tried the demo program on a Windows 10 x64 system and it works fine there.


The HS256 class is not working for me in Windows 10 Excel x64. All the "Declare Kernal32" lines are red and I get an error about 64bit compatibility if I try to create one.

----------


## dilettante

You will have to go through it and make the necessary changes.  Part of the problem with 64-bit Office and later versions of Office in general is that VBA6.5 and VBA7 lose some VB6 compatibility.

Add the PtrSafe decorator to Declare statements, and change the type of pointer and handle arguments from Long to LongPtr.

See PtrSafe <keyword>

I don't have 64-bit Excel to test with.

----------


## vbpian

Hi, dilettante

First of all thank you for the project sample, i have problem using this class to my case. 

i have this this data:

Data: hypermart1468914526
Key: a4f6bf89b2a85781b7c1cab997b7ee0c89be03f7ac6ef29b63a45d07253cc401

i have tested in http://codebeautify.org/hmac-generator with HMAC-SHA256 and the result was correct.

How i implement this with your class.

Thank you

----------


## dilettante

That web page sort of sucks.

The "key" value must be entered as printable/typeable text, you can't use a string of hex digits.  If you do that it just takes it as text and you get an incorrect HMAC value there.

Here's an example with optional "sucks" mode:




Same result as "sucky" web page

----------


## vbpian

> That web page sort of sucks.
> 
> The "key" value must be entered as printable/typeable text, you can't use a string of hex digits.  If you do that it just takes it as text and you get an incorrect HMAC value there.
> 
> Here's an example with optional "sucks" mode:


Thank you for you sample dilettante, it works as expected.

here is my code before



```
Private Sub Command1_Click()
    Dim xKey As String
    Dim xData As String
    Dim bSig() As Byte


    Dim StringToSign() As Byte
    Dim secretKey() As Byte

    xKey = "a4f6bf89b2a85781b7c1cab997b7ee0c89be03f7ac6ef29b63a45d07253cc401"
    xData = "hypermart1468914526"

    With hs256
        StringToSign = .ToUTF8(xData)
        secretKey = .ToUTF8(xKey)
        .InitHmac secretKey
        Erase secretKey

        bSig = .HmacSha256(StringToSign)
        Erase StringToSign

        MsgBox .Encode(bSig, edfBase64, efNoFolding)
        Erase bSig
    End With
End Sub
```

i realize that the msgbox line was the cause why the result always incorrect, after removing edfBase64 and efNoFolding the result was correct

----------


## dilettante

Another version that might work better in some scenarios.  It only uses the default Base Provider.

However note that this might only work on newer versions of Windows.  See Microsoft Base Cryptographic Provider:




> To maintain backward compatibility with earlier versions the new version of the provider retains the version 1.0 designation of the name in Wincrypt.h. However, version 2.0 of this provider is currently shipping. To determine the actual version of the provider in use, call CryptGetProvParam with the dwParam argument set to PP_VERSION. If 0x0200 is returned in pbData, then you have version 2.0.


So while the operations my class performs are working under Windows 10 they may rely on things that are only in version 2.0 of this Provider.

Tested and works on Windows 10 1709 and on Windows Home Server 2011 SP 1 (basically the Windows 7 codebase).

----------


## wqweto

All 7 cases in HS512 Demo 1-2 Base.zip seem to work fine on Windows Server 2013 here.

cheers,
</wqw>

----------


## fatkidz4

Please help a self-taught VBA user that can’t quite close the knowledge gap and use the Excel class that dilettante provided.  Does the HS256 Excel demo from post #59 contain the code necessary for the following problem that I have?  

I am trying sign a request for an API.  The secret key below is an example.  The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the base64-decoded secret key on the prehash string and base64-encode the output.  “1522000342.391” is the timestamp in UNIX Epoch time.

Prehash string: 
1522000342.391POST/orders{"price":“1.0”,“size”:“1.0”,“side”:“buy”,“product_id”:“BTC-USD”}

Secret key: 
D1/0wNj3wsKg8XcTs4KCfZUVzsHXIOW7w38Moj+YximHA5VQS7zAG47bgNSNGIGtFtYQ0vei2JiSPvX3JkBsA==

----------


## abumohammed

How to validate the Signature ? I am using below php code:



```

function dec_enc($action, $string) {
    $output = false;
 
    $encrypt_method = "AES-256-CBC";
    $secret_key = 'This is my secret key';
    $secret_iv = 'This is my secret iv';
     // hash
    $key = hash('sha256', $secret_key);
  
    // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
    $iv = substr(hash('sha256', $secret_iv), 0, 16);
     if( $action == 'encrypt' ) {
        $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
        $output = base64_encode($output);
    }
    else if( $action == 'decrypt' ){
        $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
    }
    return $output;
} 


```

----------


## xiaoyao

what about CryptBinaryToStringA sha512?

----------


## AndrewBeff

> You will have to go through it and make the necessary changes.  Part of the problem with 64-bit Office and later versions of Office in general is that VBA6.5 and VBA7 lose some VB6 compatibility.
> 
> Add the PtrSafe decorator to Declare statements, and change the type of pointer and handle arguments from Long to LongPtr.
> 
> See PtrSafe <keyword>
> 
> I don't have 64-bit Excel to test with.


Hi.  
I've added PtrSafe and changed Long to LongPtr (where necessary) in declarations , but the "HS256 Demo 3-1" does not work.  It throws "Failed to import key, system error 87".  Would it be possible to amend the HS256 Demo 3-1  to be operative in 64-bit Excel ?

----------


## dilettante

Error 87 is "The parameter is incorrect."

I suspect you may have changed some Long arguments to LongPtr where they shouldn't be changed.  DWORD is an example of a data type that is still 32 bits on an x64 Windows installation.

----------


## AndrewBeff

> Error 87 is "The parameter is incorrect."
> 
> I suspect you may have changed some Long arguments to LongPtr where they shouldn't be changed.  DWORD is an example of a data type that is still 32 bits on an x64 Windows installation.


Dear Dilettante.
I've changed Long to LongPtr where the VBE demands it for successful compilation.  
The amended project is at the link:  https://drive.google.com/file/d/1va8...ew?usp=sharing
Could you kindly look into it  to detect an incorrect thing ?

----------


## AndrewBeff

> Error 87 is "The parameter is incorrect."
> 
> I suspect you may have changed some Long arguments to LongPtr where they shouldn't be changed.  DWORD is an example of a data type that is still 32 bits on an x64 Windows installation.


Dear Dilettante
I've changed Long to LongPtr where the VBE demands it for successful compilation.  May I send you the amended  HmacSha256Demo and ask you to look into it and correct as necessary ?

----------


## wqweto

You can copy the PtrSafe API declares from WinXP compatible HMAC codebank submission which is x64 compatible.

In x64 version of the OS the handles are 64-bit too i.e. must use LongPtr parameters *and* variables for hKey, hHash, hProv, etc.

cheers,
</wqw>

----------


## AndrewBeff

> You can copy the PtrSafe API declares from WinXP compatible HMAC codebank submission which is x64 compatible.
> 
> In x64 version of the OS the handles are 64-bit too i.e. must use LongPtr parameters *and* variables for hKey, hHash, hProv, etc.
> 
> cheers,
> </wqw>


Dear wqweto .  
Thank you indeed.
The sample (given in your topic) works well in x64 Excel.

----------

