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>