]>
git.ipfire.org Git - thirdparty/bird.git/blob - lib/mac.c
2 * BIRD Library -- Message Authentication Codes
4 * (c) 2016 Ondrej Zajicek <santiago@crfreenet.org>
5 * (c) 2016 CZ.NIC z.s.p.o.
7 * Can be freely distributed and used under the terms of the GNU GPL.
11 * DOC: Message authentication codes
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
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.
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).
33 #include "lib/sha256.h"
34 #include "lib/sha512.h"
42 hash_init(struct mac_context
*mctx
, struct hash_context
*hctx
)
43 { mctx
->type
->hash_init(hctx
); }
46 hash_update(struct mac_context
*mctx
, struct hash_context
*hctx
, const byte
*buf
, uint len
)
47 { mctx
->type
->hash_update(hctx
, buf
, len
); }
50 hash_final(struct mac_context
*mctx
, struct hash_context
*hctx
)
51 { return mctx
->type
->hash_final(hctx
); }
54 hash_buffer(struct mac_context
*mctx
, byte
*outbuf
, const byte
*buffer
, uint length
)
56 struct hash_context hctx
;
58 hash_init(mctx
, &hctx
);
59 hash_update(mctx
, &hctx
, buffer
, length
);
60 memcpy(outbuf
, hash_final(mctx
, &hctx
), mctx
->type
->hash_size
);
65 * (not-really-MAC) Hash
69 nrmh_init(struct mac_context
*ctx
, const byte
*key UNUSED
, uint keylen UNUSED
)
71 struct nrmh_context
*ct
= (void *) ctx
;
72 hash_init(ctx
, &ct
->ictx
);
76 nrmh_update(struct mac_context
*ctx
, const byte
*data
, uint datalen
)
78 struct nrmh_context
*ct
= (void *) ctx
;
79 hash_update(ctx
, &ct
->ictx
, data
, datalen
);
83 nrmh_final(struct mac_context
*ctx
)
85 struct nrmh_context
*ct
= (void *) ctx
;
86 return hash_final(ctx
, &ct
->ictx
);
95 hmac_init(struct mac_context
*ctx
, const byte
*key
, uint keylen
)
97 struct hmac_context
*ct
= (void *) ctx
;
98 uint block_size
= ctx
->type
->block_size
;
99 uint hash_size
= ctx
->type
->hash_size
;
101 byte
*keybuf
= alloca(block_size
);
102 byte
*buf
= alloca(block_size
);
105 /* Hash the key if necessary */
106 if (keylen
<= block_size
)
108 memcpy(keybuf
, key
, keylen
);
109 memset(keybuf
+ keylen
, 0, block_size
- keylen
);
113 hash_buffer(ctx
, keybuf
, key
, keylen
);
114 memset(keybuf
+ hash_size
, 0, block_size
- hash_size
);
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
);
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
);
131 hmac_update(struct mac_context
*ctx
, const byte
*data
, uint datalen
)
133 struct hmac_context
*ct
= (void *) ctx
;
135 /* Just update the inner digest */
136 hash_update(ctx
, &ct
->ictx
, data
, datalen
);
140 hmac_final(struct mac_context
*ctx
)
142 struct hmac_context
*ct
= (void *) ctx
;
144 /* Finish the inner digest */
145 byte
*isha
= hash_final(ctx
, &ct
->ictx
);
147 /* Finish the outer digest */
148 hash_update(ctx
, &ct
->octx
, isha
, ctx
->type
->hash_size
);
149 return hash_final(ctx
, &ct
->octx
);
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 }
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 }
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
),
182 * mac_init - initialize MAC algorithm
183 * @ctx: context to initialize
184 * @id: MAC algorithm ID
186 * @keylen: MAC key length
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.
193 mac_init(struct mac_context
*ctx
, uint id
, const byte
*key
, uint keylen
)
195 ctx
->type
= &mac_table
[id
];
196 ctx
->type
->init(ctx
, key
, keylen
);
201 * mac_update - add more data to MAC algorithm
204 * @datalen: length of data
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.
211 void mac_update(struct mac_context
*ctx
, const byte
*data
, uint datalen
)
215 * mac_final - finalize MAC algorithm
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
222 * Note that the returned pointer points into data in the @ctx context. If it
223 * ceases to exist, the pointer becomes invalid.
225 byte
*mac_final(struct mac_context
*ctx
)
229 * mac_cleanup - cleanup MAC context
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().
236 void mac_cleanup(struct mac_context
*ctx
)
242 * mac_fill - compute and fill MAC
243 * @id: MAC algorithm ID
245 * @keylen: key length
246 * @data: message data
247 * @datalen: message length
248 * @mac: place to fill MAC
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.
255 mac_fill(uint id
, const byte
*key
, uint keylen
, const byte
*data
, uint datalen
, byte
*mac
)
257 struct mac_context ctx
;
259 mac_init(&ctx
, id
, key
, keylen
);
260 mac_update(&ctx
, data
, datalen
);
261 memcpy(mac
, mac_final(&ctx
), mac_get_length(&ctx
));
266 * mac_verify - compute and verify MAC
267 * @id: MAC algorithm ID
269 * @keylen: key length
270 * @data: message data
271 * @datalen: message length
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.
279 mac_verify(uint id
, const byte
*key
, uint keylen
, const byte
*data
, uint datalen
, const byte
*mac
)
281 struct mac_context ctx
;
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
));