]> git.ipfire.org Git - thirdparty/bird.git/blob - lib/mac.c
Merge remote-tracking branch 'origin/master' into mq-filter-stack
[thirdparty/bird.git] / lib / mac.c
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 }