HMAC calculation API QC3CALHM

Hi Experts,

First a very happy en successful 2013, for you and your family :-)

I have to create a HMAC, never heard before of that, but I figured out that there is an API for that. I created a test program but it seems that whatever parm I fill with whatever value, the error is the same

CPF9DE0 : Hash algorithm not valid.

A part of the parameter I understand, but for some other it's not clear what the function is.

Can someone tell me what is wrong and why?

LVL 17
MurpheyApplication ConsultantAsked:
Who is Participating?
Gary PattersonVP Technology / Senior Consultant Commented:
You get this error when you specify an invalid value for parameter 4 (Algorithm description) for API QC3CALHM.  

Valid values:

SHA-256 (V5R4 and later)
SHA-384 (V5R4 and later)
SHA-512 (V5R4 and later)

Note the hyphen in "SHA-256".  You omitted it in your code.

Also, be aware that only MD5 and SHA-1 are supported at V5R3 and earlier.

Also, the crypto service provider (software or hardware) that you select must support the selected algorithm.  If you have a 2058 crypto accelerator installed, it DOES NOT support any of these algorithms, so you'll need to select "0" or "1" for the Crypto service provider parameter.  You selected "1" in your code, so that's OK.

Cryptographic service provider
    INPUT; CHAR(1)

    The cryptographic service provider (CSP) that will perform the decryption operation.
    0       Any CSP.
    The system will choose an appropriate CSP to perform the HMAC operation.
    1       Software CSP.
    The system will perform the HMAC operation using software. If the requested algorithm is not available in software, an error is returned.

- Gary Patterson
MurpheyApplication ConsultantAuthor Commented:
Hi Gary,

we running V7R1, so that is't the problem I think.
SHA256 with or without the hyphen, makes no difference.
CSP 0 or 1 makes also no difference here, error is the same.

In my other question "Get HTTPS Data in iSeries", you send me a link :,

there they mentioning a EBCDIC issue while using  cURL,
I assume that a HMAC over EBCDIC will be differ from a HMAC over ASCII?

You have fields defined as VARYING that shouldn't be variable length fields. Each of those should be fixed-length.

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

For example, for 'ALGD0500', AlgDes is a 4-byte integer with value (3) for SHA-256.

MurpheyApplication ConsultantAuthor Commented:

This is not what is in the IBM manual (If I read it the right way)

If you are right, where can I find the right length of the fields?
Gary PattersonVP Technology / Senior Consultant Commented:

After seeing Tom's response, I took a closer look at this, and you definitely have several issues.  As Tom indicated, you have parms defined incorrectly.  

Also, when using ALGD0500 you don't pass a string to indicate the algorithm, you have to pass a numeric parameter:

Hash algorithm

    The hash algorithm. Following are the valid hash algorithms.
    1       MD5
    2       SHA-1
    3       SHA-256
    4       SHA-384
    5       SHA-512

D AlgDes          S              10i 0   INZ(3)                              3=SHA-256

Sometimes you just can't find an RPG example (a lot of times this kind of work is done in C), and you just have to convert the prototypes from C to RPG.  Here are some resources that explain how to convert C prototypes to ILE RPG:

I found one ILE RPG example that ought to get you closer (not the OP example - the response from Scott Klement).

That should get you much closer.  Post back if you still need help.

- Gary Patterson
MurpheyApplication ConsultantAuthor Commented:
Hi Gary, Tom,`

I changed the ALgDes parm and it runs in an new error:

CPF9DF5 : The key context is not found or was previously destroyed.

So I assume one of the "Key"parms is also wrong?

I can't find it in the manual, how can I (or did you) figured out what the right info is?
According to the manual :
Required Parameter Group:

1	Input data				Input	Char(*)
2	Length of input data			Input	Binary(4)
3	Input data format name			Input	Char(8)
4	Algorithm description			Input	Char(*)
5	Algorithm description format name	Input	Char(8)
6	Key description				Input	Char(*)
7	Key description format name		Input	Char(8)
8	Cryptographic service provider		Input	Char(1)
9	Cryptographic device name		Input	Char(10)
10	HMAC					Output	Char(*)
11	Error code				I/O	Char(*)

Open in new window

Gary PattersonVP Technology / Senior Consultant Commented:
If you use Key Description Format Name KEYD0100, then you need to first create a key context using API QC3CRTKX / Qc3CreateKeyContext.

This is right out of the manual:

Key description format name

The format of the key description.
If the pointer to the key description parameter is NULL, this parameter will be ignored.

The possible format names follow.

The token for a key context. This format identifies a key context. A key context is used to store a key value so it need not be recreated or retrieved every time it is used. To create a key context, use the Create Key Context (OPM, QC3CRTKX; ILE, Qc3CreateKeyContext) API.
In your original code, you aren't doing that, so you probably want to use KEYD0200 instead.

Suggest you follow the example in the link above, which uses KEYD0200.

- Gary Patterson
MurpheyApplication ConsultantAuthor Commented:

Until yesterday I thought that my RPG knowledge was after 30 years above average,
Reading the example program, I'm kicked back to my place as junior programmer :-(.
On top of that, I don't know a thing of Hash calculation or what look or sound like that and missing base knowledge of internet communication security etc.

So the Scott Klement program is working, but I'm not sure if it is the right output:

If I put various data in var dataToHash, the output is alway's 28 pos long.
is there any link tot the datalength and the length of the HMAC output?
(Maybe I need a good link to understand the whole process)

What is the definition of human readable? in:
0115.00        //---------------------------------------------------------
0116.00        // If your key is human-readable (as opposed to hex/binary)
0117.00        // then that should also be converted to UTF-8 first       
0118.00        //---------------------------------------------------------

Open in new window

Gary PattersonVP Technology / Senior Consultant Commented:

Don't feel bad.  Crypto programming is definitely a specialized skill, and there are a wide variety of tools, techniques, and standards.

SHA-256 should always produce a 256 bit (32 byte) result, regardless of the input message.  It should always produce the same result when given the same input message, and produce a different result (almost always), when you vary the input message.  

From the API reference:


    The area to store the HMAC. The length of HMAC is defined by the hash algorithm.

    MD5       16 bytes
    SHA-1       20 bytes
    SHA-256       32 bytes
    SHA-384       48 bytes
    SHA-512       64 bytes

Crypto can be really confusing, and crypto programming can be complex.  It really is a good idea to have a strong grasp of crypto basics before you go too far into a project like this.

Let's talk about hash functions in particular for a minute:

A "hash function" is an algorithm that takes a variable amount of data (often a large amount of variable data) called a "message", and produces a short fixed-length value, called a "message digest".

Message digests (hashes) are used for a lot of reasons.  

For example, most systems don't store passwords.  Instead, many store the hashed result (message digest) of applying a particular secure hash algorithm (SHA stands for Secure Hash Algorithm) to a password.  This allows the system to verify the a password without actually storing a copy of the password itself:

THISISMYPASSWORD -> Hash function -> ASDFWERT (this is what is stored on the host system.

Now, to verify a user's password, the user types in the password, it is hashed, and the hashed value compared to the stored message digest.  If they match, they password is assumed to be correct.  The advantage is clear - the password is never stored, and is never transmitted.

User enters THISISMYPASSWORD -> Hash function > ASDFWERT <-> Compared to stored value

This is a simplified example, but you get the idea.

Hashes can also be used to verify data integrity.  For example, if you have a file of some type, you can hash the entire file, and get a nice small hash value (message digest).  You can then transmit the file to someone else.  If you provide the recipient with the message digest, they can hash the file they received using the same algorithm, and verify that the file they received is identical to the file you sent.  You'll often see MD5 checksums published for downloadable files on various sites so that users can verify they haven't been tampered with.

Some good background reading:

- Gary Patterson
Gary PattersonVP Technology / Senior Consultant Commented:
I don't know what your task is, but I only intended you to use the example program for the QC3CALHM calls.  The conversion coding in the example may or may not be needed depending on what it is you need the HMAC for.

Human-readable just means a message that is, well, readable by a human:

"This is a human readable message."

As opposed to a binary message (represented here in hex for length considerations):


- Gary Patterson
MurpheyApplication ConsultantAuthor Commented:
Sorry for the "stupid" question, I know the term "human readable",
But there were 3 options Binary, Hex or human readable.

The output I got was : "lhOyGk6t7lGsPUSpyULTp7UZ/8g="

Not binary, not Hex, and not real human readable I think.

I looked a bit better to the program and see that the output ia a Bas64 presentation of the binary output.

The goal of this is to retrieve a file from a HTTPS: source that expect that I post a request.
(I think a little similar to the Amazone example from Scott).

This program is a nice start, but need a lot of changes

I have a nice cURL example in PHP, a pitty that I cant run PHP on my iSeries :-(
Sorry, Murph, that I haven't had good time yet for this.
Required Parameter Group:

1	Input data				Input	Char(*)

Open in new window

That doesn't mean that it's a variable length field. It just means that it needs a character field of "some" length. For different calls to the API, you can pass in different fields. Each time, it can be a field of a different length. The char(*) definition is just a reference to a pointer to a data type of CHAR. (The parm is really nothing but a pointer.)

Because it's a fixed-lingth field and it can represent different lengths, you also need this field:
2	Length of input data			Input	Binary(4)

Open in new window

If it could be variable-length, that second field wouldn't be needed. The length would be part of the value. Now, for this field:
4	Algorithm description			Input	Char(*)

Open in new window

It's fixed-length, but the length is different for each possible Algorithm description format name. You chose to use 'ALGD0500', so the description field is a 4-byte integer with value (3) for SHA-256. I'd link to the description, but linking doesn't work. You have to click on the 'ALGD0500' link in the API documentation to see that the data format is BINARY(4), i.e., a 4-byte binary field or a 32-bit integer. In RPG, it's a 10I 0 variable.

If you used 'ALGD0200', the field would be a 52-byte data structure. Again, you'll have to click on the 'ALGD0200' link in the docs to see what that data structure looks like.

Each format has its own structure. There's no good way to show all the variations in the list of parms. Instead, it's defined as CHAR(*). None of the possible formats are variable-length; all are fixed-length. However, you don't need to have a parm to pass the length of the description field to the API because it's inherent in the format name. You have to pass in a field that can hold the data for the format that you choose.

You can use a larger field than you need, but it still has to be fixed-length. You can't have that two-length area stuck on the front because it offsets all of the subfields.

Did I make any sense?

Gary PattersonVP Technology / Senior Consultant Commented:

1) Scott's sample code is for SHA-1, not SHA-256, so his binaryHMAC and encodedHMAC variables are too small for SHA-256.  

You'll need to increase the length of those two variables (and maybe others - you'll need to see what other lengths might be impacted).

2) There aren't really 3 options.  There is just a binary key.  Binary values are commonly written and coded in hex to save space and improve readability (that's what binary/hex means), and sometimes a key might be provided as a human readable string:

"THIS is MY secret KEY!!!"

Human readable is a problem for us AS/400 guys, since most of the rest of the world doesn't use EBCDIC.  If you stick that key into a character variable and use it as an encryption key in RPG on a CCSID 37 AS/400, you're going to get a different binary key than the programmer that sticks in into a Java String variable on a Unix system.  Since the whole point of these HMACs is to allow two different systems to independently produce the same hash, using two different binary keys is going to be a problem.  

The program comment just means that if you are given a "human readable" key by someone, they probably don't expect it to get encoded using EBCDIC, so you need to convert it to UTF-8 (or ASCII, or something other than EBCDIC).
3) Scott's comment refers to the INPUT key as being binary or human readable, not the output value (message digent).  The unencoded HMAC that is OUTPUT from this API is always binary.  Base64 encoding will, however, always result in a human readable result that can be encoded as "printable" characters.

4) In case you didn't know, Zend offers a free community edition php runtime for iSeries and IBM i:

- Gary Patterson
Yeah, the ASCII/EBCDIC encoding can be tricky. Agreement must exist on encoding before any reliable transfer of data can be done. After enough experience, it's easier to recognize when someone sent one encoding while the recipient expected a different encoding. It's still an irritation to have to interrupt a project to do translation when it wasn't expected.

Having the various iconv() APIs already available as procedures will come in handy at some point. The sooner you start on coding those, probably the better. Create a service program to hold them. Then you can plug them in as soon as needed.

But note that agreement on encoding is almost always necessary whenever data moves between systems. You should start by ensuring that your systems are running under an appropriate QCCSID system value.

MurpheyApplication ConsultantAuthor Commented:
Decided not to use RPG for it, Java should be a better solution I think,
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.