Create stabilization branch for 2.6 release
[bertos.git] / bertos / sec / mac / omac.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 2006 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief OMAC implementation
34  * \author Giovanni Bajo <rasky@develer.com>
35  */
36
37 #include "omac.h"
38 #include <cfg/macros.h>
39 #include <sec/util.h>
40
41 static void omac_set_key(Mac *ctx_, const void* key, size_t len)
42 {
43         OmacContext *ctx = (OmacContext *)ctx_;
44         cipher_set_vkey(ctx->c, key, len);
45 }
46
47 static void omac_begin(Mac *ctx_)
48 {
49         OmacContext *ctx = (OmacContext *)ctx_;
50
51         ctx->acc = 0;
52
53         memset(ctx->Y, 0, cipher_block_len(ctx->c));
54         cipher_cbc_begin(ctx->c, ctx->Y);
55 }
56
57 static void omac_update(Mac *ctx_, const void *data_, size_t len)
58 {
59         OmacContext *ctx = (OmacContext *)ctx_;
60         size_t blen = cipher_block_len(ctx->c);
61         const uint8_t *data = (const uint8_t *)data_;
62
63         while (len)
64         {
65                 ASSERT(ctx->acc <= blen);
66                 if (ctx->acc == blen)
67                 {
68                         cipher_cbc_encrypt(ctx->c, ctx->accum);
69                         ctx->acc = 0;
70                 }
71
72                 size_t L = MIN(len, blen - ctx->acc);
73                 memcpy(ctx->accum + ctx->acc, data, L);
74                 data += L;
75                 len -= L;
76                 ctx->acc += L;
77         }
78 }
79
80 static void omac_shift_left(uint8_t *L, size_t len)
81 {
82         int firstbit = L[0] >> 7;
83         size_t i;
84
85         for (i=0; i<len-1; ++i)
86                 L[i] = (L[i] << 1) | (L[i+1] >> 7);
87         L[i] <<= 1;
88
89         if (firstbit)
90         {
91                 if (len == 16)
92                         L[i] ^= 0x87;
93                 else if (len == 8)
94                         L[i] ^= 0x1B;
95                 else
96                         ASSERT(0);
97         }
98 }
99
100 static void omac_shift_right(uint8_t *L, size_t len)
101 {
102         int firstbit = L[len-1] & 1;
103         size_t i;
104
105         for (i=len-1; i>0; --i)
106                 L[i] = (L[i] >> 1) | (L[i-1] << 7);
107         L[i] >>= 1;
108
109         if (firstbit)
110         {
111                 L[i] |= 0x80;
112                 if (len == 16)
113                         L[len-1] ^= 0x43;
114                 else if (len == 8)
115                         L[len-1] ^= 0x0D;
116                 else
117                         ASSERT(0);
118         }
119 }
120
121 static uint8_t *omac1_final(Mac *ctx_)
122 {
123         OmacContext *ctx = (OmacContext *)ctx_;
124         size_t blen = cipher_block_len(ctx->c);
125
126         uint8_t L[blen];
127         memset(L, 0, blen);
128         cipher_ecb_encrypt(ctx->c, L);
129
130         omac_shift_left(L, blen);
131         if (ctx->acc < blen)
132         {
133                 ctx->accum[ctx->acc++] = 0x80;
134                 memset(ctx->accum + ctx->acc, 0, blen - ctx->acc);
135                 omac_shift_left(L, blen);
136         }
137
138         xor_block(ctx->accum, ctx->accum, L, blen);
139         cipher_cbc_encrypt(ctx->c, ctx->accum);
140         return ctx->accum;
141 }
142
143 static uint8_t *omac2_final(Mac *ctx_)
144 {
145         OmacContext *ctx = (OmacContext *)ctx_;
146         size_t blen = cipher_block_len(ctx->c);
147
148         uint8_t L[blen];
149         memset(L, 0, blen);
150         cipher_ecb_encrypt(ctx->c, L);
151
152         if (ctx->acc < blen)
153         {
154                 ctx->accum[ctx->acc++] = 0x80;
155                 memset(ctx->accum + ctx->acc, 0, blen - ctx->acc);
156                 omac_shift_right(L, blen);
157         }
158         else
159                 omac_shift_left(L, blen);
160
161         xor_block(ctx->accum, ctx->accum, L, blen);
162         cipher_cbc_encrypt(ctx->c, ctx->accum);
163         return ctx->accum;
164 }
165
166
167 /****************************************************************************/
168
169 static void omac_init(OmacContext *ctx, BlockCipher *c)
170 {
171         ctx->mac.set_key = omac_set_key;
172         ctx->mac.begin = omac_begin;
173         ctx->mac.update = omac_update;
174         ctx->mac.key_len = cipher_key_len(c);
175         ctx->mac.digest_len = cipher_block_len(c);
176         ctx->c = c;
177
178         ASSERT(cipher_block_len(c) == 8 || cipher_block_len(c) == 16);
179         ASSERT(sizeof(ctx->Y) >= cipher_block_len(c));
180         ASSERT(sizeof(ctx->accum) >= cipher_block_len(c));
181 }
182
183 void omac1_init(OmacContext *ctx, BlockCipher *c)
184 {
185         omac_init(ctx, c);
186         ctx->mac.final = omac1_final;
187 }
188
189 void omac2_init(OmacContext *ctx, BlockCipher *c)
190 {
191         omac_init(ctx, c);
192         ctx->mac.final = omac2_final;
193 }