HMAC: Keyed-Hashing for Message Authentication

About Me






  {
    "employer": "@razorpay",
    "work": [
      "security",
      "devops",
      "architecture"
    ],
    "contact": "me@captnemo.in",
    "geek": [
      "crypto",
      "ux",
      "speedcubes"
    ],
    "twitter": "@captn3m0"
  }   

Format

  • What problem does it solve?
  • How does it solve it?
    • Cover the RFC
  • When to use it?

Pre-requisite:

  1. Some idea of Hashing
  2. Bits and Bytes              

MAC

Message Authentication Code

M

M

M

M

M

M

M

K

M

K

M

Merkle–Damgård construction

Merkle–Damgård construction

M

K

M

K

M

M

K

M

K

M

16

100

28

M

K

M

K

M

16

100

28

10

HMAC Goals

  • Be Fast
  • Use existing hash functions
  • Simple Key handling
  • Easy to use

Terms

  • H = Hash Function

  • K = Authentication Key

  • B = Byte-Length (H)

  • L = Byte-Length (H(x))

Key Shortening

if(K > L)
{
  K = H(key)
}
if (K < L)
{
  K = RPAD(K, 0x00)
}

Padding

ipad = 0x36 * B
opad = 0x5C * B

// repeated B times

RFC 2104

H(K⊕opad, H(K⊕ipad, text))
H(K⊕opad, H(K⊕ipad, text))
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
        // key = MD5(key)
        MD5_CTX      tctx;

        MD5Init(&tctx);
        MD5Update(&tctx, key, key_len);
        MD5Final(tk, &tctx);

        key = tk;
        key_len = 16;
}
H(K⊕opad, H(K⊕ipad, text))
/*
 * 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);
H(K⊕opad, H(K⊕ipad, text))
/*
 * 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);

/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
}
H(K⊕opad, H(K⊕ipad, text))
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
}

/*
 * perform inner MD5
 */
MD5Init(&context);                   /* init context for 1st
                                      * pass */
MD5Update(&context, k_ipad, 64)      /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
MD5Final(digest, &context);          /* finish up 1st pass */
H(K⊕opad, H(K⊕ipad, text))
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
}

/*
 * perform inner MD5
 */
MD5Init(&context);                   /* init context for 1st
                                      * pass */
MD5Update(&context, k_ipad, 64)      /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
MD5Final(digest, &context);          /* finish up 1st pass */

/*
 * perform outer MD5
 */
MD5Init(&context);                   /* init context for 2nd
                                      * pass */
MD5Update(&context, k_opad, 64);     /* start with outer pad */
MD5Update(&context, digest, 16);     /* then results of 1st
                                      * hash */
MD5Final(digest, &context);          /* finish up 2nd pass */
H(K⊕opad, H(K⊕ipad, text))
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
}

/*
 * perform inner MD5
 */
MD5Init(&context);                   /* init context for 1st
                                      * pass */
MD5Update(&context, k_ipad, 64)      /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
MD5Final(digest, &context);          /* finish up 1st pass */

/*
 * perform outer MD5
 */
MD5Init(&context);                   /* init context for 2nd
                                      * pass */
MD5Update(&context, k_opad, 64);     /* start with outer pad */
MD5Update(&context, digest, 16);     /* then results of 1st
                                      * hash */
MD5Final(digest, &context);          /* finish up 2nd pass */
H(K⊕opad, H(K⊕ipad, text))
/*
 * Function: hmac_md5
 */

void
hmac_md5(text, text_len, key, key_len, digest)
unsigned char*  text;                /* pointer to data stream */
int             text_len;            /* length of data stream */
unsigned char*  key;                 /* pointer to authentication key */
int             key_len;             /* length of authentication key */
caddr_t         digest;              /* caller digest to be filled in */

{
    MD5_CTX context;
    //...
    MD5Final(digest, &context);

}

RFC 2104

  • Truncated HMAC
  • Test Vectors for HMAC-MD5
  • Security Guarantees
  • RFC 6151- Updated Security Considerations for MD5 and HMAC-MD5
  • RFC 4635 - HMAC SHA TSIG Algorithm Identifiers
  • RFC 4868 - Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 with IPsec
  • RFC 2202 - Test Cases for HMAC-MD5 and HMAC-SHA-1
  • RFC 4231 - Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512
key =         "Jefe"
data =        "what do ya want for nothing?"
data_len =    28 bytes
digest =      0x750c783e6ab0b503eaa86e310a5db738
key_len =     4
Made with Slides.com