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
hash_init(struct mac_context * mctx,struct hash_context * hctx)42 hash_init(struct mac_context *mctx, struct hash_context *hctx)
43 { mctx->type->hash_init(hctx); }
44 
45 static inline void
hash_update(struct mac_context * mctx,struct hash_context * hctx,const byte * buf,uint len)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 *
hash_final(struct mac_context * mctx,struct hash_context * hctx)50 hash_final(struct mac_context *mctx, struct hash_context *hctx)
51 { return mctx->type->hash_final(hctx); }
52 
53 static inline void
hash_buffer(struct mac_context * mctx,byte * outbuf,const byte * buffer,uint length)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
nrmh_init(struct mac_context * ctx,const byte * key UNUSED,uint keylen UNUSED)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
nrmh_update(struct mac_context * ctx,const byte * data,uint datalen)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 *
nrmh_final(struct mac_context * ctx)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
hmac_init(struct mac_context * ctx,const byte * key,uint keylen)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
hmac_update(struct mac_context * ctx,const byte * data,uint datalen)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 *
hmac_final(struct mac_context * ctx)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
mac_init(struct mac_context * ctx,uint id,const byte * key,uint keylen)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
mac_fill(uint id,const byte * key,uint keylen,const byte * data,uint datalen,byte * mac)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
mac_verify(uint id,const byte * key,uint keylen,const byte * data,uint datalen,const byte * mac)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 }
290