implemented append mode for xcbc, testcase
[strongswan.git] / src / libstrongswan / plugins / xcbc / xcbc.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General xcbc License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General xcbc License
13 * for more details.
14 *
15 * $Id: xcbc.c 3589 2008-03-13 14:14:44Z martin $
16 */
17
18 #include <string.h>
19
20 #include "xcbc.h"
21
22 #include <debug.h>
23
24 typedef struct private_xcbc_t private_xcbc_t;
25
26 /**
27 * Private data of a xcbc_t object.
28 *
29 * The variable names are the same as in the RFC.
30 */
31 struct private_xcbc_t {
32 /**
33 * Public xcbc_t interface.
34 */
35 xcbc_t xcbc;
36
37 /**
38 * Block size, in bytes
39 */
40 u_int8_t b;
41
42 /**
43 * crypter using k1
44 */
45 crypter_t *k1;
46
47 /**
48 * k2
49 */
50 u_int8_t *k2;
51
52 /**
53 * k3
54 */
55 u_int8_t *k3;
56
57 /**
58 * E
59 */
60 u_int8_t *e;
61
62 /**
63 * remaining, unprocessed bytes in append mode
64 */
65 u_int8_t *remaining;
66
67 /**
68 * number of bytes in remaining
69 */
70 int remaining_bytes;
71
72 /**
73 * TRUE if we have zero bytes to xcbc in final()
74 */
75 bool zero;
76 };
77
78 /**
79 * xcbc supplied data, but do not run final operation
80 */
81 static void update(private_xcbc_t *this, chunk_t data)
82 {
83 chunk_t iv;
84
85 if (data.len)
86 {
87 this->zero = FALSE;
88 }
89
90 if (this->remaining_bytes + data.len <= this->b)
91 { /* no complete block, just copy into remaining */
92 memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len);
93 this->remaining_bytes += data.len;
94 return;
95 }
96
97 iv = chunk_alloca(this->b);
98 memset(iv.ptr, 0, iv.len);
99
100 /* (3) For each block M[i], where i = 1 ... n-1:
101 * XOR M[i] with E[i-1], then encrypt the result with Key K1,
102 * yielding E[i].
103 */
104
105 /* append data to remaining bytes, process block M[1] */
106 memcpy(this->remaining + this->remaining_bytes, data.ptr,
107 this->b - this->remaining_bytes);
108 data = chunk_skip(data, this->b - this->remaining_bytes);
109 memxor(this->e, this->remaining, this->b);
110 this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL);
111
112 /* process blocks M[2] ... M[n-1] */
113 while (data.len > this->b)
114 {
115 memcpy(this->remaining, data.ptr, this->b);
116 data = chunk_skip(data, this->b);
117 memxor(this->e, this->remaining, this->b);
118 this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL);
119 }
120
121 /* store remaining bytes of block M[n] */
122 memcpy(this->remaining, data.ptr, data.len);
123 this->remaining_bytes = data.len;
124 }
125
126 /**
127 * run last round, data is in this->e
128 */
129 static void final(private_xcbc_t *this, u_int8_t *out)
130 {
131 chunk_t iv;
132
133 iv = chunk_alloca(this->b);
134 memset(iv.ptr, 0, iv.len);
135
136 /* (4) For block M[n]: */
137 if (this->remaining_bytes == this->b && !this->zero)
138 {
139 /* a) If the blocksize of M[n] is 128 bits:
140 * XOR M[n] with E[n-1] and Key K2, then encrypt the result with
141 * Key K1, yielding E[n].
142 */
143 memxor(this->e, this->remaining, this->b);
144 memxor(this->e, this->k2, this->b);
145 this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL);
146 }
147 else
148 {
149 /* b) If the blocksize of M[n] is less than 128 bits:
150 *
151 * i) Pad M[n] with a single "1" bit, followed by the number of
152 * "0" bits (possibly none) required to increase M[n]'s
153 * blocksize to 128 bits.
154 */
155 if (this->remaining_bytes < this->b)
156 {
157 this->remaining[this->remaining_bytes] = 0x80;
158 while (++this->remaining_bytes < this->b)
159 {
160 this->remaining[this->remaining_bytes] = 0x00;
161 }
162 }
163 /* ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result
164 * with Key K1, yielding E[n].
165 */
166 memxor(this->e, this->remaining, this->b);
167 memxor(this->e, this->k3, this->b);
168 this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL);
169 }
170
171 memcpy(out, this->e, this->b);
172
173 /* (2) Define E[0] = 0x00000000000000000000000000000000 */
174 memset(this->e, 0, this->b);
175 this->remaining_bytes = 0;
176 this->zero = TRUE;
177 }
178
179 /**
180 * Implementation of xcbc_t.get_mac.
181 */
182 static void get_mac(private_xcbc_t *this, chunk_t data, u_int8_t *out)
183 {
184 /* update E, do not process last block */
185 update(this, data);
186
187 if (out)
188 { /* if not in append mode, process last block and output result */
189 final(this, out);
190 }
191 }
192
193 /**
194 * Implementation of xcbc_t.get_block_size.
195 */
196 static size_t get_block_size(private_xcbc_t *this)
197 {
198 return this->b;
199 }
200
201 /**
202 * Implementation of xcbc_t.set_key.
203 */
204 static void set_key(private_xcbc_t *this, chunk_t key)
205 {
206 chunk_t iv, k1, lengthened;
207
208 /* we support variable keys from RFC4434 */
209 if (key.len == this->b)
210 {
211 lengthened = key;
212 }
213 else if (key.len < this->b)
214 { /* pad short keys */
215 lengthened = chunk_alloca(this->b);
216 memset(lengthened.ptr, 0, lengthened.len);
217 memcpy(lengthened.ptr, key.ptr, key.len);
218 }
219 else
220 { /* shorten key using xcbc */
221 lengthened = chunk_alloca(this->b);
222 memset(lengthened.ptr, 0, lengthened.len);
223 set_key(this, lengthened);
224 get_mac(this, key, lengthened.ptr);
225 }
226
227 k1 = chunk_alloca(this->b);
228 iv = chunk_alloca(this->b);
229 memset(iv.ptr, 0, iv.len);
230
231 /*
232 * (1) Derive 3 128-bit keys (K1, K2 and K3) from the 128-bit secret
233 * key K, as follows:
234 * K1 = 0x01010101010101010101010101010101 encrypted with Key K
235 * K2 = 0x02020202020202020202020202020202 encrypted with Key K
236 * K3 = 0x03030303030303030303030303030303 encrypted with Key K
237 */
238 this->k1->set_key(this->k1, lengthened);
239 memset(this->k2, 0x02, this->b);
240 this->k1->encrypt(this->k1, chunk_create(this->k2, this->b), iv, NULL);
241 memset(this->k3, 0x03, this->b);
242 this->k1->encrypt(this->k1, chunk_create(this->k3, this->b), iv, NULL);
243 memset(k1.ptr, 0x01, this->b);
244 this->k1->encrypt(this->k1, k1, iv, NULL);
245 this->k1->set_key(this->k1, k1);
246 }
247
248 /**
249 * Implementation of xcbc_t.destroy.
250 */
251 static void destroy(private_xcbc_t *this)
252 {
253 this->k1->destroy(this->k1);
254 free(this->k2);
255 free(this->k3);
256 free(this->e);
257 free(this->remaining);
258 free(this);
259 }
260
261 /*
262 * Described in header
263 */
264 xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size)
265 {
266 private_xcbc_t *this;
267 crypter_t *crypter;
268
269 crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size);
270 if (!crypter)
271 {
272 return NULL;
273 }
274 /* input and output of crypter must be equal for xcbc */
275 if (crypter->get_block_size(crypter) != key_size)
276 {
277 crypter->destroy(crypter);
278 return NULL;
279 }
280
281 this = malloc_thing(private_xcbc_t);
282 this->xcbc.get_mac = (void (*)(xcbc_t *,chunk_t,u_int8_t*))get_mac;
283 this->xcbc.get_block_size = (size_t (*)(xcbc_t *))get_block_size;
284 this->xcbc.set_key = (void (*)(xcbc_t *,chunk_t))set_key;
285 this->xcbc.destroy = (void (*)(xcbc_t *))destroy;
286
287 this->b = crypter->get_block_size(crypter);
288 this->k1 = crypter;
289 this->k2 = malloc(this->b);
290 this->k3 = malloc(this->b);
291 this->e = malloc(this->b);
292 memset(this->e, 0, this->b);
293 this->remaining = malloc(this->b);
294 this->remaining_bytes = 0;
295 this->zero = TRUE;
296
297 return &this->xcbc;
298 }
299