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>