7e077e94c71bedc41681cec6b7ac6e72fb54c694
[bertos.git] / bertos / sec / mac / hmac.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief HMAC implementation
34  * \author Giovanni Bajo <rasky@develer.com>
35  *
36  */
37
38 #include "hmac.h"
39 #include <sec/util.h>
40 #include <string.h>
41
42
43 static void hmac_set_key(Mac *m, const void *key, size_t key_len)
44 {
45         HmacContext *ctx = (HmacContext *)m;
46
47         memset(ctx->key, 0, ctx->m.key_len);
48         if (key_len <= ctx->m.key_len)
49                 memcpy(ctx->key, key, key_len);
50         else
51         {
52                 hash_begin(ctx->h);
53                 hash_update(ctx->h, key, key_len);
54                 memcpy(ctx->key, hash_final(ctx->h), hash_digest_len(ctx->h));
55         }
56
57         xor_block_const(ctx->key, ctx->key, 0x5C, ctx->m.key_len);
58 }
59
60 static void hmac_begin(Mac *m)
61 {
62         HmacContext *ctx = (HmacContext *)m;
63         int klen = ctx->m.key_len;
64
65         xor_block_const(ctx->key, ctx->key, 0x36^0x5C, klen);
66         hash_begin(ctx->h);
67         hash_update(ctx->h, ctx->key, klen);
68 }
69
70 static void hmac_update(Mac *m, const void *data, size_t len)
71 {
72         HmacContext *ctx = (HmacContext *)m;
73         hash_update(ctx->h, data, len);
74 }
75
76 static uint8_t *hmac_final(Mac *m)
77 {
78         HmacContext *ctx = (HmacContext *)m;
79         int hlen = hash_digest_len(ctx->h);
80
81         uint8_t temp[hlen];
82         memcpy(temp, hash_final(ctx->h), hlen);
83
84         xor_block_const(ctx->key, ctx->key, 0x5C^0x36, ctx->m.key_len);
85         hash_begin(ctx->h);
86         hash_update(ctx->h, ctx->key, ctx->m.key_len);
87         hash_update(ctx->h, temp, hlen);
88
89         PURGE(temp);
90         return hash_final(ctx->h);
91 }
92
93 /*********************************************************************/
94
95 void hmac_init(HmacContext *ctx, Hash *h)
96 {
97         ctx->h = h;
98         ctx->m.key_len = hash_block_len(h);
99         ctx->m.digest_len = hash_digest_len(h);
100         ctx->m.set_key = hmac_set_key;
101         ctx->m.begin = hmac_begin;
102         ctx->m.update = hmac_update;
103         ctx->m.final = hmac_final;
104         ASSERT(sizeof(ctx->key) >= ctx->m.key_len);
105 }