chashopensslone-time-passwordhmacsha1

implementing hmac sha1 in C


I am trying out a small piece of code that would generate Hmac-sha1. I have been asked to code the hmac implementation myself using the OpenSSL libs for SHA1 calculation. After 'wiki'ing for the algorithm, here is what I have below.I have used input with RFC 2246 specified test values:

   Count    Hexadecimal HMAC-SHA-1(secret, count)
   0        cc93cf18508d94934c64b65d8ba7667fb7cde4b0
   1        75a48a19d4cbe100644e8ac1397eea747a2d33ab
   2        0bacb7fa082fef30782211938bc1c5e70416ff44
   3        66c28227d03a2d5529262ff016a1e6ef76557ece
   4        a904c900a64b35909874b33e61c5938a8e15ed1c
   5        a37e783d7b7233c083d4f62926c7a25f238d0316
   6        bc9cd28561042c83f219324d3c607256c03272ae
   7        a4fb960c0bc06e1eabb804e5b397cdc4b45596fa
   8        1b3c89f65e6c9e883012052823443f048b4332db
   9        1637409809a679dc698207310c8c7fc07290d9e5

With the below code that I have done using example from RFC2104, I am getting the value for COUNTER = 0 as desired but when COUNTER value is set to other values like 2,3 etc as above, the HMAC SHA1 doesnt match with the above values in RFC 2246. Also another problem is if I use memcpy and memset instead of bzero or bcopy, the code shows a different(wrong) Hmac Sha1 value which doesnt match with COUNTER = 0 value. Please explain why this strange beahviour?

    #include <openssl/evp.h>
    #include <openssl/bn.h>
    #include <openssl/sha.h>
    #include <openssl/err.h>
    #include <openssl/conf.h>
    #include <openssl/engine.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>     /* for memset() */
    #include <unistd.h>

    #define IPAD 0x36
    #define OPAD 0x5C

    #define SHA1_DIGESTLENGTH 20
    #define SHA1_BLOCK_LENGTH 64
    #define COUNTER_LENGTH 8

    typedef unsigned          char uint8_t;
    typedef unsigned short     int uint16_t;
    typedef unsigned           int uint32_t;

    /**
     * Key
     */
   #define SECRET {  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30  }
#define COUNTER {  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }



void hmacsha1(){
    uint8_t key[]= SECRET;
    int key_len = sizeof(key);
    uint8_t ctr[] = COUNTER;
    unsigned char k_ipad[65];    /* inner padding -
     * key XORd with ipad
     */
    unsigned char k_opad[65];    /* outer padding -
     * key XORd with opad
     */
    int i;
    uint8_t digest[20];
    memset(digest, 0, sizeof(digest));
    /*
     * the HMAC_MD5 transform looks like:
     *
     * MD5(K XOR opad, MD5(K XOR ipad, text))
     *
     * where K is an n byte key
     * ipad is the byte 0x36 repeated 64 times
     * opad is the byte 0x5c repeated 64 times
     * and text is the data being protected
     */

    /* start out by storing key in pads */

    bzero( k_ipad, sizeof k_ipad);
    bzero( k_opad, sizeof k_opad);
    bcopy( key, k_ipad, key_len);
    bcopy( key, k_opad, key_len);

/*
    memset( k_ipad, 0, sizeof k_ipad);
    memset( k_opad, 0, sizeof k_opad);
    memcpy( key, k_ipad, key_len);
    memcpy( key, k_opad, key_len);
*/
    /* XOR key with ipad and opad values */
    for (i=0; i<64; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }
    /*
     * perform inner MD5
     */
    EVP_MD_CTX mdctx;
    const EVP_MD *md;

    unsigned char md_value[EVP_MAX_MD_SIZE];
    unsigned int md_len;

    OpenSSL_add_all_digests();


    md = EVP_get_digestbyname("sha1");

    if(!md) {
        printf("Unknown message digest\n");
        exit(1);
    }

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, k_ipad, 64 );
    EVP_DigestUpdate(&mdctx, ctr, 8 );
    EVP_DigestFinal_ex(&mdctx, md_value, &md_len);

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, k_opad, 64 );
    EVP_DigestUpdate(&mdctx, md_value, md_len );
    EVP_DigestFinal_ex(&mdctx, digest, &md_len);
    EVP_MD_CTX_cleanup(&mdctx);

    printf("Digest is: ");
    for(i = 0; i < md_len; i++) printf("%02x", digest[i]);
    printf("\n");

}

Solution

  • First, you have to do

    memcpy(k_ipad, key, key_len);
    
    memcpy(k_opad, key, key_len);
    

    instead of

    memcpy( key, k_ipad, key_len);
    
    memcpy( key, k_opad, key_len);