Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / lib / mac.c @ 6b3f1a54

History | View | Annotate | Download (8.04 KB)

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
}