HMAC Implementation - Pseudo code

4.1k views Asked by At

I am having to implement my own HMAC-SHA256 for use in an embedded project. I am having trouble getting it to work. I cant even get the pseudo code, hand-calculated to work, so I know I am doing something wrong!

My pseduoCode calcuations. Following the diagram in wikipedia

 1 function hmac (key, message)
 2     if (length(key) > blocksize) then
 3         // keys longer than blocksize are shortened
 4         key = hash(key)
 5     end if
 6     if (length(key) < blocksize) then
 7         // keys shorter than blocksize are zero-padded
 8         key = key ∥ zeroes(blocksize - length(key))
 9     end if
10
11     // Where blocksize is that of the underlying hash function
12     o_key_pad = [0x5c * blocksize] ⊕ key
13     i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
14     // Where ∥ is concatenation
15     return hash(o_key_pad ∥ hash(i_key_pad ∥ message))
16 end function

When I do by-hand calculations for key="mykey" and message="helloworld" I get the following:

key = 0x6d796b6579000000000000000000000000000000000000000000000000000000

o_key_pad = 0x31253739255c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c

i_key_pad = 0x5b4f5d534f363636363636363636363636363636363636363636363636363636

hash(i_key_pad ∥ message) = 6fb2e91de7b8b5ec6283846ff7245cd6eb4a4fd26056b529bd42d99fcf3314d2

and the overall hmac of 0d76a16089f85cd2169bb64b6f2c818e6a404a218896483fcd97fee5cce185ae

2

There are 2 answers

0
matt On BEST ANSWER

When fixing the key length and calulating the inner and outer padding, you need to use the blocksize of the underlying hash function, which is not the same as its output size. This is the size of the input blocks that the function operates on. In the case of SHA256, the blocksize is 512 bits (64 bytes) and the output size is 256 bits (32 bytes).

Your results are what you get if you use 32 as the blocksize.

Using the correct length blocksize the key, o_key_pad and i_key_pad are basically the same, only twice as long with trailing 00, 5c or 36 bytes respectively.

The result of the inner hash (i.e. hash(i_key_pad ∥ message) is:

8bf029764919f9e35249d0d55ffb8fd6c62fe23a85c1515e0120c5005aa813d5

and the final value (hash(o_key_pad ∥ hash(i_key_pad ∥ message))) is:

7fdfaa9c9c0931f52d9ebf2538bc99700f2e771f3af1c1d93945c2256c11aedd

which matches the result I get from OpenSSL’s HMAC implementation.

0
Reid On

This is the code I came up with:

 /**
 * This function takes in a key, the length of that key, a message (null terminated) and a pointer to a char[32] or greater array
 * It calculates the HMAC-SHA256 of the given key message combo and returns the resulting code in binary form, 32 hex pairs
1 @example ???? todo function hmac (key, message)
2     if (length(key) > blocksize) then
3         // keys longer than blocksize are shortened
4         key = hash(key)
5     end if
6     if (length(key) < blocksize) then
7         // keys shorter than blocksize are zero-padded
8         key = key ∥ zeroes(blocksize - length(key))
9     end if
10
11     // Where blocksize is that of the underlying hash function
12     o_key_pad = [0x5c * blocksize] ⊕ key
13     i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
14     // Where ∥ is concatenation
15     return hash(o_key_pad ∥ hash(i_key_pad ∥ message))
16 end function
 * @param key todo
 * @param length todo
 * @param message todo
 * @param hmac todo
*/
void hmac(char key[], int length, char message[], char *hmac){
    int msgLen = strlen(message);   //get the length of the message to be encrypted
    char keyFinal[BLOCK_SIZE] = {0}; //setup array for the data to go into

    if(length > BLOCK_SIZE){         //if the given data is too long, hash it
        shaHash(key, keyFinal);
    }
    if(length < BLOCK_SIZE){         //if the given data is too short, pad it with 0x00
        int i;
        for(i = 0; i < BLOCK_SIZE; i++){
            if(i < length){             //read in the data
                keyFinal[i] = key[i];
            }else{                      //if there is no more data to read, read in zeros
                keyFinal[i] = 0x00;
            }
        }
    }
    if(length == BLOCK_SIZE){        //if the given data is the right size, transfer it to keyFinal
        int i;
        for(i = 0; i < BLOCK_SIZE; i++){
            keyFinal[i] = key[i];
        }
    }

    char oKeyPad[BLOCK_SIZE] = {0};    //setup the oKeyPad
    char iKeyPad[BLOCK_SIZE] = {0};    //setup the ikeypad

    int i;
    for(i = 0; i < BLOCK_SIZE; i++){ //for each item in key final, xor it with O_KEY_PAD and I_KEY_PAD
        oKeyPad[i] = keyFinal[i] ^ O_KEY_PAD;
        iKeyPad[i] = keyFinal[i] ^ I_KEY_PAD;
    }

    char iandmesg[BLOCK_SIZE+MAX_SHA];   //setup the inner hash ikeypad concat with message
    char hash_iandmesg[HASH_LEN] = {0};       //get ready to get bytes back from the hashing function

    //make the message to be hashed, ikeypad concatinated with message
    for(i = 0; i < BLOCK_SIZE; i++){ //read in ikeypad
        iandmesg[i] = iKeyPad[i];
    }
    for(i = BLOCK_SIZE; i < (msgLen + BLOCK_SIZE); i++){ //read in message
        iandmesg[i] = message[i-BLOCK_SIZE];
    }

    shaHash_len(iandmesg, (msgLen+BLOCK_SIZE), hash_iandmesg);   //create the inner hash (ikeypad + message)

    char oandihash[(BLOCK_SIZE + HASH_LEN)];    //setup the outter hash, okeypad + (hash of ikeypad + message)

    //make the message to be hashed, okeypad concatinated with the hash of (ikeypad + message)
    for(i = 0; i < BLOCK_SIZE; i++){ //read in okeypad
        oandihash[i] = oKeyPad[i];
    }
    for(i = BLOCK_SIZE; i < (BLOCK_SIZE + HASH_LEN); i++){ //read in hash of ikeypad + message
        oandihash[i] = hash_iandmesg[i-BLOCK_SIZE];
    }

    //return the result of the hash of (okeypad + hash(ikeypad + message))
    shaHash_len(oandihash, (BLOCK_SIZE + HASH_LEN), hmac);
}