2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
15 * $Id: xcbc.c 3589 2008-03-13 14:14:44Z martin $
24 typedef struct private_xcbc_t private_xcbc_t
;
27 * Private data of a xcbc_t object.
29 * The variable names are the same as in the RFC.
31 struct private_xcbc_t
{
33 * Public xcbc_t interface.
38 * Block size, in bytes
63 * remaining, unprocessed bytes in append mode
68 * number of bytes in remaining
73 * TRUE if we have zero bytes to xcbc in final()
79 * xcbc supplied data, but do not run final operation
81 static void update(private_xcbc_t
*this, chunk_t data
)
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
;
97 iv
= chunk_alloca(this->b
);
98 memset(iv
.ptr
, 0, iv
.len
);
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,
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
);
112 /* process blocks M[2] ... M[n-1] */
113 while (data
.len
> this->b
)
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
);
121 /* store remaining bytes of block M[n] */
122 memcpy(this->remaining
, data
.ptr
, data
.len
);
123 this->remaining_bytes
= data
.len
;
127 * run last round, data is in this->e
129 static void final(private_xcbc_t
*this, u_int8_t
*out
)
133 iv
= chunk_alloca(this->b
);
134 memset(iv
.ptr
, 0, iv
.len
);
136 /* (4) For block M[n]: */
137 if (this->remaining_bytes
== this->b
&& !this->zero
)
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].
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
);
149 /* b) If the blocksize of M[n] is less than 128 bits:
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.
155 if (this->remaining_bytes
< this->b
)
157 this->remaining
[this->remaining_bytes
] = 0x80;
158 while (++this->remaining_bytes
< this->b
)
160 this->remaining
[this->remaining_bytes
] = 0x00;
163 /* ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result
164 * with Key K1, yielding E[n].
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
);
171 memcpy(out
, this->e
, this->b
);
173 /* (2) Define E[0] = 0x00000000000000000000000000000000 */
174 memset(this->e
, 0, this->b
);
175 this->remaining_bytes
= 0;
180 * Implementation of xcbc_t.get_mac.
182 static void get_mac(private_xcbc_t
*this, chunk_t data
, u_int8_t
*out
)
184 /* update E, do not process last block */
188 { /* if not in append mode, process last block and output result */
194 * Implementation of xcbc_t.get_block_size.
196 static size_t get_block_size(private_xcbc_t
*this)
202 * Implementation of xcbc_t.set_key.
204 static void set_key(private_xcbc_t
*this, chunk_t key
)
206 chunk_t iv
, k1
, lengthened
;
208 /* we support variable keys from RFC4434 */
209 if (key
.len
== this->b
)
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
);
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
);
227 k1
= chunk_alloca(this->b
);
228 iv
= chunk_alloca(this->b
);
229 memset(iv
.ptr
, 0, iv
.len
);
232 * (1) Derive 3 128-bit keys (K1, K2 and K3) from the 128-bit secret
234 * K1 = 0x01010101010101010101010101010101 encrypted with Key K
235 * K2 = 0x02020202020202020202020202020202 encrypted with Key K
236 * K3 = 0x03030303030303030303030303030303 encrypted with Key K
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
);
249 * Implementation of xcbc_t.destroy.
251 static void destroy(private_xcbc_t
*this)
253 this->k1
->destroy(this->k1
);
257 free(this->remaining
);
262 * Described in header
264 xcbc_t
*xcbc_create(encryption_algorithm_t algo
, size_t key_size
)
266 private_xcbc_t
*this;
269 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, algo
, key_size
);
274 /* input and output of crypter must be equal for xcbc */
275 if (crypter
->get_block_size(crypter
) != key_size
)
277 crypter
->destroy(crypter
);
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
;
287 this->b
= crypter
->get_block_size(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;