File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / lib / mac.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Aug 22 12:33:54 2017 UTC (6 years, 10 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, v1_6_3p0, v1_6_3, HEAD
bird 1.6.3

    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>