2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 #include "encryption_payload.h"
24 #include <encoding/payloads/encodings.h>
25 #include <utils/linked_list.h>
26 #include <encoding/generator.h>
27 #include <encoding/parser.h>
29 typedef struct private_encryption_payload_t private_encryption_payload_t
;
32 * Private data of an encryption_payload_t' Object.
35 struct private_encryption_payload_t
{
38 * Public encryption_payload_t interface.
40 encryption_payload_t
public;
43 * There is no next payload for an encryption payload,
44 * since encryption payload MUST be the last one.
45 * next_payload means here the first payload of the
46 * contained, encrypted payload.
48 u_int8_t next_payload
;
51 * Flags, including reserved bits
56 * Length of this payload
58 u_int16_t payload_length
;
61 * Chunk containing the IV, plain, padding and ICV.
66 * AEAD transform to use
73 linked_list_t
*payloads
;
77 * Encoding rules to parse or generate a IKEv2-Encryption Payload.
79 * The defined offsets are the positions in a object of type
80 * private_encryption_payload_t.
82 static encoding_rule_t encodings
[] = {
83 /* 1 Byte next payload type, stored in the field next_payload */
84 { U_INT_8
, offsetof(private_encryption_payload_t
, next_payload
) },
85 /* Critical and 7 reserved bits, all stored for reconstruction */
86 { U_INT_8
, offsetof(private_encryption_payload_t
, flags
) },
87 /* Length of the whole encryption payload*/
88 { PAYLOAD_LENGTH
, offsetof(private_encryption_payload_t
, payload_length
) },
89 /* encrypted data, stored in a chunk. contains iv, data, padding */
90 { ENCRYPTED_DATA
, offsetof(private_encryption_payload_t
, encrypted
) },
95 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
96 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 ! Next Payload !C! RESERVED ! Payload Length !
98 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 ! Initialization Vector !
100 ! (length is block size for encryption algorithm) !
101 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 ! Encrypted IKE Payloads !
103 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 ! ! Padding (0-255 octets) !
105 +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
107 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108 ~ Integrity Checksum Data ~
109 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112 METHOD(payload_t
, verify
, status_t
,
113 private_encryption_payload_t
*this)
118 METHOD(payload_t
, get_encoding_rules
, int,
119 private_encryption_payload_t
*this, encoding_rule_t
**rules
)
122 return countof(encodings
);
125 METHOD(payload_t
, get_type
, payload_type_t
,
126 private_encryption_payload_t
*this)
131 METHOD(payload_t
, get_next_type
, payload_type_t
,
132 private_encryption_payload_t
*this)
134 return this->next_payload
;
137 METHOD(payload_t
, set_next_type
, void,
138 private_encryption_payload_t
*this, payload_type_t type
)
140 /* the next payload is set during add */
144 * Compute the length of the whole payload
146 static void compute_length(private_encryption_payload_t
*this)
148 enumerator_t
*enumerator
;
150 size_t bs
, length
= 0;
152 if (this->encrypted
.len
)
154 length
= this->encrypted
.len
;
158 enumerator
= this->payloads
->create_enumerator(this->payloads
);
159 while (enumerator
->enumerate(enumerator
, &payload
))
161 length
+= payload
->get_length(payload
);
163 enumerator
->destroy(enumerator
);
168 bs
= this->aead
->get_block_size(this->aead
);
169 length
+= bs
- (length
% bs
);
171 length
+= this->aead
->get_iv_size(this->aead
);
173 length
+= this->aead
->get_icv_size(this->aead
);
176 length
+= ENCRYPTION_PAYLOAD_HEADER_LENGTH
;
177 this->payload_length
= length
;
180 METHOD2(payload_t
, encryption_payload_t
, get_length
, size_t,
181 private_encryption_payload_t
*this)
183 compute_length(this);
184 return this->payload_length
;
187 METHOD(encryption_payload_t
, add_payload
, void,
188 private_encryption_payload_t
*this, payload_t
*payload
)
190 payload_t
*last_payload
;
192 if (this->payloads
->get_count(this->payloads
) > 0)
194 this->payloads
->get_last(this->payloads
, (void **)&last_payload
);
195 last_payload
->set_next_type(last_payload
, payload
->get_type(payload
));
199 this->next_payload
= payload
->get_type(payload
);
201 payload
->set_next_type(payload
, NO_PAYLOAD
);
202 this->payloads
->insert_last(this->payloads
, payload
);
203 compute_length(this);
206 METHOD(encryption_payload_t
, remove_payload
, payload_t
*,
207 private_encryption_payload_t
*this)
211 if (this->payloads
->remove_first(this->payloads
,
212 (void**)&payload
) == SUCCESS
)
220 * Generate payload before encryption
222 static chunk_t
generate(private_encryption_payload_t
*this,
223 generator_t
*generator
)
225 payload_t
*current
, *next
;
226 enumerator_t
*enumerator
;
228 chunk_t chunk
= chunk_empty
;
230 enumerator
= this->payloads
->create_enumerator(this->payloads
);
231 if (enumerator
->enumerate(enumerator
, ¤t
))
233 this->next_payload
= current
->get_type(current
);
235 while (enumerator
->enumerate(enumerator
, &next
))
237 current
->set_next_type(current
, next
->get_type(next
));
238 generator
->generate_payload(generator
, current
);
241 current
->set_next_type(current
, NO_PAYLOAD
);
242 generator
->generate_payload(generator
, current
);
244 chunk
= generator
->get_chunk(generator
, &lenpos
);
245 DBG2(DBG_ENC
, "generated content in encryption payload");
247 enumerator
->destroy(enumerator
);
252 * Append the encryption payload header to the associated data
254 static chunk_t
append_header(private_encryption_payload_t
*this, chunk_t assoc
)
257 u_int8_t next_payload
;
260 } __attribute__((packed
)) header
= {
261 .next_payload
= this->next_payload
,
262 .flags
= this->flags
,
263 .length
= htons(get_length(this)),
265 return chunk_cat("cc", assoc
, chunk_from_thing(header
));
268 METHOD(encryption_payload_t
, encrypt
, bool,
269 private_encryption_payload_t
*this, chunk_t assoc
)
271 chunk_t iv
, plain
, padding
, icv
, crypt
;
272 generator_t
*generator
;
276 if (this->aead
== NULL
)
278 DBG1(DBG_ENC
, "encrypting encryption payload failed, transform missing");
282 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
285 DBG1(DBG_ENC
, "encrypting encryption payload failed, no RNG found");
289 assoc
= append_header(this, assoc
);
291 generator
= generator_create();
292 plain
= generate(this, generator
);
293 bs
= this->aead
->get_block_size(this->aead
);
294 /* we need at least one byte padding to store the padding length */
295 padding
.len
= bs
- (plain
.len
% bs
);
296 iv
.len
= this->aead
->get_iv_size(this->aead
);
297 icv
.len
= this->aead
->get_icv_size(this->aead
);
299 /* prepare data to authenticate-encrypt:
300 * | IV | plain | padding | ICV |
301 * \____crypt______/ ^
304 * assoc -> + ------->/
306 free(this->encrypted
.ptr
);
307 this->encrypted
= chunk_alloc(iv
.len
+ plain
.len
+ padding
.len
+ icv
.len
);
308 iv
.ptr
= this->encrypted
.ptr
;
309 memcpy(iv
.ptr
+ iv
.len
, plain
.ptr
, plain
.len
);
310 plain
.ptr
= iv
.ptr
+ iv
.len
;
311 padding
.ptr
= plain
.ptr
+ plain
.len
;
312 icv
.ptr
= padding
.ptr
+ padding
.len
;
313 crypt
= chunk_create(plain
.ptr
, plain
.len
+ padding
.len
);
314 generator
->destroy(generator
);
316 rng
->get_bytes(rng
, iv
.len
, iv
.ptr
);
317 rng
->get_bytes(rng
, padding
.len
- 1, padding
.ptr
);
318 padding
.ptr
[padding
.len
- 1] = padding
.len
- 1;
321 DBG3(DBG_ENC
, "encryption payload encryption:");
322 DBG3(DBG_ENC
, "IV %B", &iv
);
323 DBG3(DBG_ENC
, "plain %B", &plain
);
324 DBG3(DBG_ENC
, "padding %B", &padding
);
325 DBG3(DBG_ENC
, "assoc %B", &assoc
);
327 this->aead
->encrypt(this->aead
, crypt
, assoc
, iv
, NULL
);
329 DBG3(DBG_ENC
, "encrypted %B", &crypt
);
330 DBG3(DBG_ENC
, "ICV %B", &icv
);
338 * Parse the payloads after decryption.
340 static status_t
parse(private_encryption_payload_t
*this, chunk_t plain
)
345 parser
= parser_create(plain
);
346 type
= this->next_payload
;
347 while (type
!= NO_PAYLOAD
)
351 if (parser
->parse_payload(parser
, type
, &payload
) != SUCCESS
)
353 parser
->destroy(parser
);
356 if (payload
->verify(payload
) != SUCCESS
)
358 DBG1(DBG_ENC
, "%N verification failed",
359 payload_type_names
, payload
->get_type(payload
));
360 payload
->destroy(payload
);
361 parser
->destroy(parser
);
364 type
= payload
->get_next_type(payload
);
365 this->payloads
->insert_last(this->payloads
, payload
);
367 parser
->destroy(parser
);
368 DBG2(DBG_ENC
, "parsed content of encryption payload");
372 METHOD(encryption_payload_t
, decrypt
, status_t
,
373 private_encryption_payload_t
*this, chunk_t assoc
)
375 chunk_t iv
, plain
, padding
, icv
, crypt
;
378 if (this->aead
== NULL
)
380 DBG1(DBG_ENC
, "decrypting encryption payload failed, transform missing");
381 return INVALID_STATE
;
384 /* prepare data to authenticate-decrypt:
385 * | IV | plain | padding | ICV |
386 * \____crypt______/ ^
389 * assoc -> + ------->/
392 bs
= this->aead
->get_block_size(this->aead
);
393 iv
.len
= this->aead
->get_iv_size(this->aead
);
394 iv
.ptr
= this->encrypted
.ptr
;
395 icv
.len
= this->aead
->get_icv_size(this->aead
);
396 icv
.ptr
= this->encrypted
.ptr
+ this->encrypted
.len
- icv
.len
;
397 crypt
.ptr
= iv
.ptr
+ iv
.len
;
398 crypt
.len
= this->encrypted
.len
- iv
.len
;
400 if (iv
.len
+ icv
.len
> this->encrypted
.len
||
401 (crypt
.len
- icv
.len
) % bs
)
403 DBG1(DBG_ENC
, "decrypting encryption payload failed, invalid length");
407 assoc
= append_header(this, assoc
);
409 DBG3(DBG_ENC
, "encryption payload decryption:");
410 DBG3(DBG_ENC
, "IV %B", &iv
);
411 DBG3(DBG_ENC
, "encrypted %B", &crypt
);
412 DBG3(DBG_ENC
, "ICV %B", &icv
);
413 DBG3(DBG_ENC
, "assoc %B", &assoc
);
415 if (!this->aead
->decrypt(this->aead
, crypt
, assoc
, iv
, NULL
))
417 DBG1(DBG_ENC
, "verifying encryption payload integrity failed");
423 plain
= chunk_create(crypt
.ptr
, crypt
.len
- icv
.len
);
424 padding
.len
= plain
.ptr
[plain
.len
- 1] + 1;
425 if (padding
.len
> plain
.len
)
427 DBG1(DBG_ENC
, "decrypting encryption payload failed, "
428 "padding invalid %B", &crypt
);
431 plain
.len
-= padding
.len
;
432 padding
.ptr
= plain
.ptr
+ plain
.len
;
434 DBG3(DBG_ENC
, "plain %B", &plain
);
435 DBG3(DBG_ENC
, "padding %B", &padding
);
437 return parse(this, plain
);
440 METHOD(encryption_payload_t
, set_transform
, void,
441 private_encryption_payload_t
*this, aead_t
* aead
)
446 METHOD2(payload_t
, encryption_payload_t
, destroy
, void,
447 private_encryption_payload_t
*this)
449 this->payloads
->destroy_offset(this->payloads
, offsetof(payload_t
, destroy
));
450 free(this->encrypted
.ptr
);
455 * Described in header
457 encryption_payload_t
*encryption_payload_create()
459 private_encryption_payload_t
*this;
463 .payload_interface
= {
465 .get_encoding_rules
= _get_encoding_rules
,
466 .get_length
= _get_length
,
467 .get_next_type
= _get_next_type
,
468 .set_next_type
= _set_next_type
,
469 .get_type
= _get_type
,
472 .get_length
= _get_length
,
473 .add_payload
= _add_payload
,
474 .remove_payload
= _remove_payload
,
475 .set_transform
= _set_transform
,
480 .next_payload
= NO_PAYLOAD
,
481 .payload_length
= ENCRYPTION_PAYLOAD_HEADER_LENGTH
,
482 .payloads
= linked_list_create(),
485 return &this->public;