Annotation of embedaddon/bird/lib/mac.c, revision 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>