[BACK]Return to hmac.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libcrypt

Annotation of src/lib/libcrypt/hmac.c, Revision 1.3

1.3     ! drochner    1: /* $NetBSD: hmac.c,v 1.2 2009/01/18 12:15:27 lukem Exp $ */
1.1       drochner    2:
                      3: /*
                      4:  * Copyright (c) 2004, Juniper Networks, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. Neither the name of the copyright holders nor the names of its
                     16:  *    contributors may be used to endorse or promote products derived
                     17:  *    from this software without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     20:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     21:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     22:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
                     23:  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     24:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     25:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     26:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     27:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     29:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31: /*
                     32:  * Implement HMAC as described in RFC 2104
                     33:  *
                     34:  * You need to define the following before including this file.
                     35:  *
                     36:  * HMAC_FUNC the name of the function (hmac_sha1 or hmac_md5 etc)
                     37:  * HASH_LENGTH the size of the digest (20 for SHA1, 16 for MD5)
                     38:  * HASH_CTX the name of the HASH CTX
                     39:  * HASH_Init
                     40:  * HASH_Update
                     41:  * Hash_Final
                     42:  */
                     43: #include <sys/cdefs.h>
                     44: #if !defined(lint)
1.3     ! drochner   45: __RCSID("$NetBSD: hmac.c,v 1.2 2009/01/18 12:15:27 lukem Exp $");
1.1       drochner   46: #endif /* not lint */
                     47:
                     48: #include <stdlib.h>
                     49: #include <string.h>
                     50:
                     51: /* Don't change these */
                     52: #define HMAC_IPAD 0x36
                     53: #define HMAC_OPAD 0x5c
                     54:
                     55: /* Nor this */
                     56: #ifndef HMAC_BLOCKSZ
                     57: # define HMAC_BLOCKSZ 64
                     58: #endif
                     59:
                     60: /*
                     61:  * The logic here is lifted straight from RFC 2104 except that
                     62:  * rather than filling the pads with 0, copying in the key and then
                     63:  * XOR with the pad byte, we just fill with the pad byte and
                     64:  * XOR with the key.
                     65:  */
                     66: void
                     67: HMAC_FUNC (const unsigned char *text, size_t text_len,
                     68:           const unsigned char *key, size_t key_len,
                     69:           unsigned char *digest)
                     70: {
                     71:     HASH_CTX context;
                     72:     /* Inner padding key XOR'd with ipad */
1.3     ! drochner   73:     unsigned char k_ipad[HMAC_BLOCKSZ];
1.1       drochner   74:     /* Outer padding key XOR'd with opad */
1.3     ! drochner   75:     unsigned char k_opad[HMAC_BLOCKSZ];
1.1       drochner   76:     /* HASH(key) if needed */
                     77:     unsigned char tk[HASH_LENGTH];
1.2       lukem      78:     size_t i;
1.1       drochner   79:
                     80:     /*
                     81:      * If key is longer than HMAC_BLOCKSZ bytes
                     82:      * reset it to key=HASH(key)
                     83:      */
                     84:     if (key_len > HMAC_BLOCKSZ) {
                     85:        HASH_CTX      tctx;
                     86:
                     87:        HASH_Init(&tctx);
                     88:        HASH_Update(&tctx, key, key_len);
                     89:        HASH_Final(tk, &tctx);
                     90:
                     91:        key = tk;
                     92:        key_len = HASH_LENGTH;
                     93:     }
                     94:
                     95:     /*
                     96:      * The HMAC_ transform looks like:
                     97:      *
                     98:      * HASH(K XOR opad, HASH(K XOR ipad, text))
                     99:      *
                    100:      * where K is an n byte key
                    101:      * ipad is the byte HMAC_IPAD repeated HMAC_BLOCKSZ times
                    102:      * opad is the byte HMAC_OPAD repeated HMAC_BLOCKSZ times
                    103:      * and text is the data being protected
                    104:      */
                    105:
                    106:     /*
                    107:      * Fill the pads and XOR in the key
                    108:      */
                    109:     memset( k_ipad, HMAC_IPAD, sizeof k_ipad);
                    110:     memset( k_opad, HMAC_OPAD, sizeof k_opad);
                    111:     for (i = 0; i < key_len; i++) {
                    112:        k_ipad[i] ^= key[i];
                    113:        k_opad[i] ^= key[i];
                    114:     }
                    115:
                    116:     /*
                    117:      * Perform inner HASH.
                    118:      * Start with inner pad,
                    119:      * then the text.
                    120:      */
                    121:     HASH_Init(&context);
                    122:     HASH_Update(&context, k_ipad, HMAC_BLOCKSZ);
                    123:     HASH_Update(&context, text, text_len);
                    124:     HASH_Final(digest, &context);
                    125:
                    126:     /*
                    127:      * Perform outer HASH.
                    128:      * Start with the outer pad,
                    129:      * then the result of the inner hash.
                    130:      */
                    131:     HASH_Init(&context);
                    132:     HASH_Update(&context, k_opad, HMAC_BLOCKSZ);
                    133:     HASH_Update(&context, digest, HASH_LENGTH);
                    134:     HASH_Final(digest, &context);
                    135: }
                    136:
                    137: #if defined(MAIN) || defined(UNIT_TEST)
                    138: #include <stdio.h>
                    139:
                    140:
                    141: static char *
                    142: b2x(char *buf, int bufsz, unsigned char *data, int nbytes)
                    143: {
                    144:        int i;
                    145:
                    146:        if (bufsz <= (nbytes * 2))
                    147:            return NULL;
                    148:        buf[0] = '\0';
                    149:        for (i = 0; i < nbytes; i++) {
                    150:            (void) sprintf(&buf[i*2], "%02x", data[i]);
                    151:        }
                    152:        return buf;
                    153: }
                    154:
                    155: #if defined(UNIT_TEST)
                    156:
                    157: static int
                    158: x2b(unsigned char *buf, int bufsz, char *data, int nbytes)
                    159: {
                    160:        int i;
                    161:        int c;
                    162:
                    163:        if (nbytes < 0)
                    164:            nbytes = strlen(data);
                    165:        nbytes /= 2;
                    166:        if (bufsz <= nbytes)
                    167:            return 0;
                    168:        for (i = 0; i < nbytes; i++) {
                    169:            if (sscanf(&data[i*2], "%02x", &c) < 1)
                    170:                break;
                    171:            buf[i] = c;
                    172:        }
                    173:        buf[i] = 0;
                    174:        return i;
                    175: }
                    176:
                    177: #ifndef HMAC_KAT
                    178: # define HMAC_KAT hmac_kat
                    179: #endif
                    180:
                    181: /*
                    182:  * If a test key or data starts with 0x we'll convert to binary.
                    183:  */
                    184: #define X2B(v, b) do { \
                    185:     if (strncmp(v, "0x", 2) == 0) { \
                    186:         v += 2; \
                    187:         x2b(b, sizeof(b), v, strlen(v)); \
                    188:         v = b; \
                    189:     } \
                    190: } while (0)
                    191:
                    192: /*
                    193:  * Run some of the known answer tests from RFC 2202
                    194:  * We assume that HASH_LENGTH==20 means SHA1 else MD5.
                    195:  */
                    196: static int
                    197: HMAC_KAT (FILE *fp)
                    198: {
                    199:     struct test_s {
                    200:        unsigned char *key;
                    201:        unsigned char *data;
                    202:        unsigned char *expect;
                    203:     } tests[] = {
                    204:        {
                    205: #if HASH_LENGTH == 20
                    206:            "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
                    207:            "Hi There",
                    208:            "0xb617318655057264e28bc0b6fb378c8ef146be00",
                    209: #else
                    210:            "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
                    211:            "Hi There",
                    212:            "0x9294727a3638bb1c13f48ef8158bfc9d",
                    213: #endif
                    214:        },
                    215:        {
                    216:            "Jefe",
                    217:            "what do ya want for nothing?",
                    218: #if HASH_LENGTH == 20
                    219:            "0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
                    220: #else
                    221:            "0x750c783e6ab0b503eaa86e310a5db738",
                    222: #endif
                    223:        },
                    224:        {
                    225: #if HASH_LENGTH == 20
                    226:            "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
                    227:            "Test With Truncation",
                    228:            "0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
                    229: #else
                    230:            "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
                    231:            "Test With Truncation",
                    232:            "0x56461ef2342edc00f9bab995690efd4c",
                    233: #endif
                    234:        },
                    235:        {
                    236:            "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                    237:            "Test Using Larger Than Block-Size Key - Hash Key First",
                    238: #if HASH_LENGTH == 20
                    239:            "0xaa4ae5e15272d00e95705637ce8a3b55ed402112",
                    240: #else
                    241:            "0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
                    242: #endif
                    243:        },
                    244:        {
                    245:                0, 0, 0,
                    246:        },
                    247:     };
                    248:     struct test_s *test = tests;
                    249:     unsigned char digest[HASH_LENGTH];
                    250:     unsigned char kbuf[BUFSIZ];
                    251:     unsigned char dbuf[BUFSIZ];
                    252:     unsigned char *key;
                    253:     unsigned char *data;
                    254:     char *result;
                    255:     int n = 0;
                    256:
                    257:     for (test = tests; test->key; test++) {
                    258:        key = test->key;
                    259:        X2B(key, kbuf);
                    260:        data = test->data;
                    261:        X2B(data, dbuf);
                    262:        HMAC_FUNC(data, strlen(data), key, strlen(key), digest);
                    263:        strcpy(dbuf, "0x");
                    264:        b2x(&dbuf[2], (sizeof dbuf) - 2, digest, HASH_LENGTH);
                    265:
                    266:        if (strcmp(dbuf, test->expect) == 0)
                    267:            result = "Ok";
                    268:        else {
                    269:            n++;
                    270:            result = test->expect;
                    271:        }
                    272:        if (fp)
                    273:            fprintf(fp, "key=%s, data=%s, result=%s: %s\n",
                    274:                    test->key, test->data, dbuf, result);
                    275:     }
                    276:     return n;
                    277: }
                    278: #endif
                    279:
                    280:
                    281: int
                    282: main (int argc, char *argv[])
                    283: {
                    284:     char buf[BUFSIZ];
                    285:     unsigned char *key;
                    286:     unsigned char *data;
                    287:     int key_len;
                    288:     int data_len;
                    289:     int i;
                    290:     unsigned char digest[HASH_LENGTH];
                    291:
                    292: #ifdef UNIT_TEST
                    293:     if (argc == 1)
                    294:        exit(HMAC_KAT(stdout));
                    295: #endif
                    296:
                    297:     if (argc < 3) {
                    298:        fprintf(stderr, "Usage:\n\t%s key data\n", argv[0]);
                    299:        exit(1);
                    300:     }
                    301:     key = argv[1];
                    302:     data = argv[2];
                    303:     key_len = strlen(key);
                    304:     data_len = strlen(data);
                    305:     HMAC_FUNC(data, data_len, key, key_len, digest);
                    306:     printf("0x%s\n", b2x(buf, sizeof buf, digest, HASH_LENGTH));
                    307:     exit(0);
                    308: }
                    309: #endif
                    310:
                    311:

CVSweb <webmaster@jp.NetBSD.org>