Annotation of embedaddon/bird/lib/mac.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD Library -- Message Authentication Codes
                      3:  *
                      4:  *     (c) 2016 Ondrej Zajicek <santiago@crfreenet.org>
                      5:  *     (c) 2016 CZ.NIC z.s.p.o.
                      6:  *
                      7:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      8:  */
                      9: 
                     10: /**
                     11:  * DOC: Message authentication codes
                     12:  *
                     13:  * MAC algorithms are simple cryptographic tools for message authentication.
                     14:  * They use shared a secret key a and message text to generate authentication
                     15:  * code, which is then passed with the message to the other side, where the code
                     16:  * is verified. There are multiple families of MAC algorithms based on different
                     17:  * cryptographic primitives, BIRD implements two MAC families which use hash
                     18:  * functions.
                     19:  *
                     20:  * The first family is simply a cryptographic hash camouflaged as MAC algorithm.
                     21:  * Originally supposed to be (m|k)-hash (message is concatenated with key, and
                     22:  * that is hashed), but later it turned out that a raw hash is more practical.
                     23:  * This is used for cryptographic authentication in OSPFv2, RIP and BFD.
                     24:  *
                     25:  * The second family is the standard HMAC (RFC 2104), using inner and outer hash
                     26:  * to process key and message. HMAC (with SHA) is used in advanced OSPF and RIP
                     27:  * authentication (RFC 5709, RFC 4822).
                     28:  */
                     29: 
                     30: #include "lib/mac.h"
                     31: #include "lib/md5.h"
                     32: #include "lib/sha1.h"
                     33: #include "lib/sha256.h"
                     34: #include "lib/sha512.h"
                     35: 
                     36: 
                     37: /*
                     38:  *     Internal hash calls
                     39:  */
                     40: 
                     41: static inline void
                     42: hash_init(struct mac_context *mctx, struct hash_context *hctx)
                     43: { mctx->type->hash_init(hctx); }
                     44: 
                     45: static inline void
                     46: hash_update(struct mac_context *mctx, struct hash_context *hctx, const byte *buf, uint len)
                     47: { mctx->type->hash_update(hctx, buf, len); }
                     48: 
                     49: static inline byte *
                     50: hash_final(struct mac_context *mctx, struct hash_context *hctx)
                     51: { return mctx->type->hash_final(hctx); }
                     52: 
                     53: static inline void
                     54: hash_buffer(struct mac_context *mctx, byte *outbuf, const byte *buffer, uint length)
                     55: {
                     56:   struct hash_context hctx;
                     57: 
                     58:   hash_init(mctx, &hctx);
                     59:   hash_update(mctx, &hctx, buffer, length);
                     60:   memcpy(outbuf, hash_final(mctx, &hctx), mctx->type->hash_size);
                     61: }
                     62: 
                     63: 
                     64: /*
                     65:  *     (not-really-MAC) Hash
                     66:  */
                     67: 
                     68: static void
                     69: nrmh_init(struct mac_context *ctx, const byte *key UNUSED, uint keylen UNUSED)
                     70: {
                     71:   struct nrmh_context *ct = (void *) ctx;
                     72:   hash_init(ctx, &ct->ictx);
                     73: }
                     74: 
                     75: static void
                     76: nrmh_update(struct mac_context *ctx, const byte *data, uint datalen)
                     77: {
                     78:   struct nrmh_context *ct = (void *) ctx;
                     79:   hash_update(ctx, &ct->ictx, data, datalen);
                     80: }
                     81: 
                     82: static byte *
                     83: nrmh_final(struct mac_context *ctx)
                     84: {
                     85:   struct nrmh_context *ct = (void *) ctx;
                     86:   return hash_final(ctx, &ct->ictx);
                     87: }
                     88: 
                     89: 
                     90: /*
                     91:  *     HMAC
                     92:  */
                     93: 
                     94: static void
                     95: hmac_init(struct mac_context *ctx, const byte *key, uint keylen)
                     96: {
                     97:   struct hmac_context *ct = (void *) ctx;
                     98:   uint block_size = ctx->type->block_size;
                     99:   uint hash_size = ctx->type->hash_size;
                    100: 
                    101:   byte *keybuf = alloca(block_size);
                    102:   byte *buf = alloca(block_size);
                    103:   uint i;
                    104: 
                    105:   /* Hash the key if necessary */
                    106:   if (keylen <= block_size)
                    107:   {
                    108:     memcpy(keybuf, key, keylen);
                    109:     memset(keybuf + keylen, 0, block_size - keylen);
                    110:   }
                    111:   else
                    112:   {
                    113:     hash_buffer(ctx, keybuf, key, keylen);
                    114:     memset(keybuf + hash_size, 0, block_size - hash_size);
                    115:   }
                    116: 
                    117:   /* Initialize the inner digest */
                    118:   hash_init(ctx, &ct->ictx);
                    119:   for (i = 0; i < block_size; i++)
                    120:     buf[i] = keybuf[i] ^ 0x36;
                    121:   hash_update(ctx, &ct->ictx, buf, block_size);
                    122: 
                    123:   /* Initialize the outer digest */
                    124:   hash_init(ctx, &ct->octx);
                    125:   for (i = 0; i < block_size; i++)
                    126:     buf[i] = keybuf[i] ^ 0x5c;
                    127:   hash_update(ctx, &ct->octx, buf, block_size);
                    128: }
                    129: 
                    130: static void
                    131: hmac_update(struct mac_context *ctx, const byte *data, uint datalen)
                    132: {
                    133:   struct hmac_context *ct = (void *) ctx;
                    134: 
                    135:   /* Just update the inner digest */
                    136:   hash_update(ctx, &ct->ictx, data, datalen);
                    137: }
                    138: 
                    139: static byte *
                    140: hmac_final(struct mac_context *ctx)
                    141: {
                    142:   struct hmac_context *ct = (void *) ctx;
                    143: 
                    144:   /* Finish the inner digest */
                    145:   byte *isha = hash_final(ctx, &ct->ictx);
                    146: 
                    147:   /* Finish the outer digest */
                    148:   hash_update(ctx, &ct->octx, isha, ctx->type->hash_size);
                    149:   return hash_final(ctx, &ct->octx);
                    150: }
                    151: 
                    152: 
                    153: /*
                    154:  *     Common code
                    155:  */
                    156: 
                    157: #define HASH_DESC(name, px, PX) \
                    158:   { name, PX##_SIZE, sizeof(struct nrmh_context), nrmh_init, nrmh_update, nrmh_final, \
                    159:     PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final }
                    160: 
                    161: #define HMAC_DESC(name, px, PX)                                                \
                    162:   { name, PX##_SIZE, sizeof(struct hmac_context), hmac_init, hmac_update, hmac_final, \
                    163:     PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final }
                    164: 
                    165: const struct mac_desc mac_table[ALG_MAX] = {
                    166:   [ALG_MD5] =          HASH_DESC("Keyed MD5",          md5,    MD5),
                    167:   [ALG_SHA1] =         HASH_DESC("Keyed SHA-1",        sha1,   SHA1),
                    168:   [ALG_SHA224] =       HASH_DESC("Keyed SHA-224",      sha224, SHA224),
                    169:   [ALG_SHA256] =       HASH_DESC("Keyed SHA-256",      sha256, SHA256),
                    170:   [ALG_SHA384] =       HASH_DESC("Keyed SHA-384",      sha384, SHA384),
                    171:   [ALG_SHA512] =       HASH_DESC("Keyed SHA-512",      sha512, SHA512),
                    172:   [ALG_HMAC_MD5] =     HMAC_DESC("HMAC-MD5",           md5,    MD5),
                    173:   [ALG_HMAC_SHA1] =    HMAC_DESC("HMAC-SHA-1",         sha1,   SHA1),
                    174:   [ALG_HMAC_SHA224] =  HMAC_DESC("HMAC-SHA-224",       sha224, SHA224),
                    175:   [ALG_HMAC_SHA256] =  HMAC_DESC("HMAC-SHA-256",       sha256, SHA256),
                    176:   [ALG_HMAC_SHA384] =  HMAC_DESC("HMAC-SHA-384",       sha384, SHA384),
                    177:   [ALG_HMAC_SHA512] =  HMAC_DESC("HMAC-SHA-512",       sha512, SHA512),
                    178: };
                    179: 
                    180: 
                    181: /**
                    182:  * mac_init - initialize MAC algorithm
                    183:  * @ctx: context to initialize
                    184:  * @id: MAC algorithm ID
                    185:  * @key: MAC key
                    186:  * @keylen: MAC key length
                    187:  *
                    188:  * Initialize MAC context @ctx for algorithm @id (e.g., %ALG_HMAC_SHA1), with
                    189:  * key @key of length @keylen. After that, message data could be added using
                    190:  * mac_update() function.
                    191:  */
                    192: void
                    193: mac_init(struct mac_context *ctx, uint id, const byte *key, uint keylen)
                    194: {
                    195:   ctx->type = &mac_table[id];
                    196:   ctx->type->init(ctx, key, keylen);
                    197: }
                    198: 
                    199: #if 0
                    200: /**
                    201:  * mac_update - add more data to MAC algorithm
                    202:  * @ctx: MAC context
                    203:  * @data: data to add
                    204:  * @datalen: length of data
                    205:  *
                    206:  * Push another @datalen bytes of data pointed to by @data into the MAC
                    207:  * algorithm currently in @ctx. Can be called multiple times for the same MAC
                    208:  * context. It has the same effect as concatenating all the data together and
                    209:  * passing them at once.
                    210:  */
                    211: void mac_update(struct mac_context *ctx, const byte *data, uint datalen)
                    212: { DUMMY; }
                    213: 
                    214: /**
                    215:  * mac_final - finalize MAC algorithm
                    216:  * @ctx: MAC context
                    217:  *
                    218:  * Finish MAC computation and return a pointer to the result. No more
                    219:  * @mac_update() calls could be done, but the context may be reinitialized
                    220:  * later.
                    221:  *
                    222:  * Note that the returned pointer points into data in the @ctx context. If it
                    223:  * ceases to exist, the pointer becomes invalid.
                    224:  */
                    225: byte *mac_final(struct mac_context *ctx)
                    226: { DUMMY; }
                    227: 
                    228: /**
                    229:  * mac_cleanup - cleanup MAC context
                    230:  * @ctx: MAC context
                    231:  *
                    232:  * Cleanup MAC context after computation (by filling with zeros). Not strictly
                    233:  * necessary, just to erase sensitive data from stack. This also invalidates the
                    234:  * pointer returned by @mac_final().
                    235:  */
                    236: void mac_cleanup(struct mac_context *ctx)
                    237: { DUMMY; }
                    238: 
                    239: #endif
                    240: 
                    241: /**
                    242:  * mac_fill - compute and fill MAC
                    243:  * @id: MAC algorithm ID
                    244:  * @key: secret key
                    245:  * @keylen: key length
                    246:  * @data: message data
                    247:  * @datalen: message length
                    248:  * @mac: place to fill MAC
                    249:  *
                    250:  * Compute MAC for specified key @key and message @data using algorithm @id and
                    251:  * copy it to buffer @mac. mac_fill() is a shortcut function doing all usual
                    252:  * steps for transmitted messages.
                    253:  */
                    254: void
                    255: mac_fill(uint id, const byte *key, uint keylen, const byte *data, uint datalen, byte *mac)
                    256: {
                    257:   struct mac_context ctx;
                    258: 
                    259:   mac_init(&ctx, id, key, keylen);
                    260:   mac_update(&ctx, data, datalen);
                    261:   memcpy(mac, mac_final(&ctx), mac_get_length(&ctx));
                    262:   mac_cleanup(&ctx);
                    263: }
                    264: 
                    265: /**
                    266:  * mac_verify - compute and verify MAC
                    267:  * @id: MAC algorithm ID
                    268:  * @key: secret key
                    269:  * @keylen: key length
                    270:  * @data: message data
                    271:  * @datalen: message length
                    272:  * @mac: received MAC
                    273:  *
                    274:  * Compute MAC for specified key @key and message @data using algorithm @id and
                    275:  * compare it with received @mac, return whether they are the same. mac_verify()
                    276:  * is a shortcut function doing all usual steps for received messages.
                    277:  */
                    278: int
                    279: mac_verify(uint id, const byte *key, uint keylen, const byte *data, uint datalen, const byte *mac)
                    280: {
                    281:   struct mac_context ctx;
                    282: 
                    283:   mac_init(&ctx, id, key, keylen);
                    284:   mac_update(&ctx, data, datalen);
                    285:   int res = !memcmp(mac, mac_final(&ctx), mac_get_length(&ctx));
                    286:   mac_cleanup(&ctx);
                    287: 
                    288:   return res;
                    289: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>