Link to home
Start Free TrialLog in
Avatar of Theo Kouwenhoven
Theo KouwenhovenFlag for Netherlands

asked on

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?

Thanks
Murph
HMAC-RPG.txt
ASKER CERTIFIED SOLUTION
Avatar of Gary Patterson, CISSP
Gary Patterson, CISSP
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Theo Kouwenhoven

ASKER

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 :
https://github.com/bagder/curl/blob/master/packages/OS400/README.OS400,

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

Murph:

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

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

Tom
Tom,

This is not what is in the IBM manual (If I read it the right way)
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fapis%2Fqc3calhm.htm

If you are right, where can I find the right length of the fields?
Murphy,

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:

http://www.scottklement.com/rpg/callc.html
https://www.ibm.com/developerworks/mydeveloperworks/wikis/home/wiki/We13116a562db_467e_bcd4_882013aec57a/page/Converting%20C%20Prototypes%20to%20RPG?lang=en

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

http://www.iprodeveloper.com/forums/aft/134541

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

- Gary Patterson
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

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
INPUT; CHAR(8)

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.

KEYD0100
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 iprodeveloper.com link above, which uses KEYD0200.

- Gary Patterson
Guys,

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

Murphy,

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:

HMAC
    OUTPUT; CHAR(*)

    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:

http://fisher.osu.edu/~muhanna_1/pdf/crypto.pdf
http://en.wikipedia.org/wiki/Cryptographic_hash_function

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

x416e67727920737175697272656c

- Gary Patterson
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 :-(
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Murph,

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:

http://www-03.ibm.com/systems/i/software/php/index.html

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

Tom
Decided not to use RPG for it, Java should be a better solution I think,