ikev2: Include fragment number into message ID passed to IV gen
[strongswan.git] / src / libcharon / encoding / payloads / encrypted_payload.c
index d71f514..d1a2678 100644 (file)
@@ -1,7 +1,7 @@
 /*
+ * Copyright (C) 2011-2014 Tobias Brunner
  * Copyright (C) 2005-2010 Martin Willi
  * Copyright (C) 2010 revosec AG
- * Copyright (C) 2011 Tobias Brunner
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
 #include <string.h>
 
 #include "encrypted_payload.h"
+#include "encrypted_fragment_payload.h"
 
 #include <daemon.h>
 #include <encoding/payloads/encodings.h>
 #include <collections/linked_list.h>
-#include <encoding/generator.h>
 #include <encoding/parser.h>
 
 typedef struct private_encrypted_payload_t private_encrypted_payload_t;
+typedef struct private_encrypted_fragment_payload_t private_encrypted_fragment_payload_t;
 
 struct private_encrypted_payload_t {
 
@@ -75,6 +76,56 @@ struct private_encrypted_payload_t {
        payload_type_t type;
 };
 
+struct private_encrypted_fragment_payload_t {
+
+       /**
+        * Public interface.
+        */
+       encrypted_fragment_payload_t public;
+
+       /**
+        * The first fragment contains the type of the first payload contained in
+        * the original encrypted payload, for all other fragments it MUST be set
+        * to zero.
+        */
+       u_int8_t next_payload;
+
+       /**
+        * Flags, including reserved bits
+        */
+       u_int8_t flags;
+
+       /**
+        * Length of this payload
+        */
+       u_int16_t payload_length;
+
+       /**
+        * Chunk containing the IV, plain, padding and ICV.
+        */
+       chunk_t encrypted;
+
+       /**
+        * Fragment number
+        */
+       u_int16_t fragment_number;
+
+       /**
+        * Total fragments
+        */
+       u_int16_t total_fragments;
+
+       /**
+        * AEAD transform to use
+        */
+       aead_t *aead;
+
+       /**
+        * Chunk containing the plain packet data.
+        */
+       chunk_t plain;
+};
+
 /**
  * Encoding rules to parse or generate a IKEv2-Encrypted Payload.
  *
@@ -132,6 +183,47 @@ static encoding_rule_t encodings_v1[] = {
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
 
+/**
+ * Encoding rules to parse or generate an IKEv2-Encrypted Fragment Payload.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_encrypted_payload_t.
+ */
+static encoding_rule_t encodings_fragment[] = {
+       /* 1 Byte next payload type, stored in the field next_payload */
+       { U_INT_8,                      offsetof(private_encrypted_fragment_payload_t, next_payload)    },
+       /* Critical and 7 reserved bits, all stored for reconstruction */
+       { U_INT_8,                      offsetof(private_encrypted_fragment_payload_t, flags)                   },
+       /* Length of the whole encryption payload*/
+       { PAYLOAD_LENGTH,       offsetof(private_encrypted_fragment_payload_t, payload_length)  },
+       /* Fragment number */
+       { U_INT_16,                     offsetof(private_encrypted_fragment_payload_t, fragment_number) },
+       /* Total number of fragments */
+       { U_INT_16,                     offsetof(private_encrypted_fragment_payload_t, total_fragments) },
+       /* encrypted data, stored in a chunk. contains iv, data, padding */
+       { CHUNK_DATA,           offsetof(private_encrypted_fragment_payload_t, encrypted)               },
+};
+
+/*
+                           1                   2                   3
+       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
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      ! Next Payload  !C!  RESERVED   !         Payload Length        !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !        Fragment Number        |        Total Fragments        !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !                     Initialization Vector                     !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !                    Encrypted IKE Payloads                     !
+      +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !               !             Padding (0-255 octets)            !
+      +-+-+-+-+-+-+-+-+                               +-+-+-+-+-+-+-+-+
+      !                                               !  Pad Length   !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      ~                    Integrity Checksum Data                    ~
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
 METHOD(payload_t, verify, status_t,
        private_encrypted_payload_t *this)
 {
@@ -180,13 +272,30 @@ METHOD(payload_t, set_next_type, void,
 }
 
 /**
+ * Get length of encryption/integrity overhead for the given plaintext length
+ */
+static size_t compute_overhead(aead_t *aead, size_t len)
+{
+       size_t bs, overhead;
+
+       /* padding */
+       bs = aead->get_block_size(aead);
+       overhead = bs - (len % bs);
+       /* add iv */
+       overhead += aead->get_iv_size(aead);
+       /* add icv */
+       overhead += aead->get_icv_size(aead);
+       return overhead;
+}
+
+/**
  * Compute the length of the whole payload
  */
 static void compute_length(private_encrypted_payload_t *this)
 {
        enumerator_t *enumerator;
        payload_t *payload;
-       size_t bs, length = 0;
+       size_t length = 0;
 
        if (this->encrypted.len)
        {
@@ -203,13 +312,7 @@ static void compute_length(private_encrypted_payload_t *this)
 
                if (this->aead)
                {
-                       /* append padding */
-                       bs = this->aead->get_block_size(this->aead);
-                       length += bs - (length % bs);
-                       /* add iv */
-                       length += this->aead->get_iv_size(this->aead);
-                       /* add icv */
-                       length += this->aead->get_icv_size(this->aead);
+                       length += compute_overhead(this->aead, length);
                }
        }
        length += get_header_length(this);
@@ -287,6 +390,12 @@ static chunk_t generate(private_encrypted_payload_t *this,
        return chunk;
 }
 
+METHOD(encrypted_payload_t, generate_payloads, void,
+       private_encrypted_payload_t *this, generator_t *generator)
+{
+       generate(this, generator);
+}
+
 /**
  * Append the encrypted payload header to the associated data
  */
@@ -304,44 +413,36 @@ static chunk_t append_header(private_encrypted_payload_t *this, chunk_t assoc)
        return chunk_cat("cc", assoc, chunk_from_thing(header));
 }
 
-METHOD(encrypted_payload_t, encrypt, status_t,
-       private_encrypted_payload_t *this, u_int64_t mid, chunk_t assoc)
+/**
+ * Encrypts the data in plain and returns it in an allocated chunk.
+ */
+static status_t encrypt_content(char *label, aead_t *aead, u_int64_t mid,
+                                                       chunk_t plain, chunk_t assoc, chunk_t *encrypted)
 {
-       chunk_t iv, plain, padding, icv, crypt;
-       generator_t *generator;
+       chunk_t iv, padding, icv, crypt;
        iv_gen_t *iv_gen;
        rng_t *rng;
        size_t bs;
 
-       if (this->aead == NULL)
-       {
-               DBG1(DBG_ENC, "encrypting encrypted payload failed, transform missing");
-               return INVALID_STATE;
-       }
-
        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
        if (!rng)
        {
-               DBG1(DBG_ENC, "encrypting encrypted payload failed, no RNG found");
+               DBG1(DBG_ENC, "encrypting %s failed, no RNG found", label);
                return NOT_SUPPORTED;
        }
 
-       iv_gen = this->aead->get_iv_gen(this->aead);
+       iv_gen = aead->get_iv_gen(aead);
        if (!iv_gen)
        {
-               DBG1(DBG_ENC, "encrypting encrypted payload failed, no IV generator");
+               DBG1(DBG_ENC, "encrypting %s failed, no IV generator", label);
                return NOT_SUPPORTED;
        }
 
-       assoc = append_header(this, assoc);
-
-       generator = generator_create();
-       plain = generate(this, generator);
-       bs = this->aead->get_block_size(this->aead);
+       bs = aead->get_block_size(aead);
        /* we need at least one byte padding to store the padding length */
        padding.len = bs - (plain.len % bs);
-       iv.len = this->aead->get_iv_size(this->aead);
-       icv.len = this->aead->get_icv_size(this->aead);
+       iv.len = aead->get_iv_size(aead);
+       icv.len = aead->get_icv_size(aead);
 
        /* prepare data to authenticate-encrypt:
         * | IV | plain | padding | ICV |
@@ -350,45 +451,64 @@ METHOD(encrypted_payload_t, encrypt, status_t,
         *              v          /
         *     assoc -> + ------->/
         */
-       free(this->encrypted.ptr);
-       this->encrypted = chunk_alloc(iv.len + plain.len + padding.len + icv.len);
-       iv.ptr = this->encrypted.ptr;
+       *encrypted = chunk_alloc(iv.len + plain.len + padding.len + icv.len);
+       iv.ptr = encrypted->ptr;
        memcpy(iv.ptr + iv.len, plain.ptr, plain.len);
        plain.ptr = iv.ptr + iv.len;
        padding.ptr = plain.ptr + plain.len;
        icv.ptr = padding.ptr + padding.len;
        crypt = chunk_create(plain.ptr, plain.len + padding.len);
-       generator->destroy(generator);
 
        if (!iv_gen->get_iv(iv_gen, mid, iv.len, iv.ptr) ||
                !rng->get_bytes(rng, padding.len - 1, padding.ptr))
        {
-               DBG1(DBG_ENC, "encrypting encrypted payload failed, no IV or padding");
+               DBG1(DBG_ENC, "encrypting %s failed, no IV or padding", label);
                rng->destroy(rng);
-               free(assoc.ptr);
+
                return FAILED;
        }
        padding.ptr[padding.len - 1] = padding.len - 1;
        rng->destroy(rng);
 
-       DBG3(DBG_ENC, "encrypted payload encryption:");
+       DBG3(DBG_ENC, "%s encryption:", label);
        DBG3(DBG_ENC, "IV %B", &iv);
        DBG3(DBG_ENC, "plain %B", &plain);
        DBG3(DBG_ENC, "padding %B", &padding);
        DBG3(DBG_ENC, "assoc %B", &assoc);
 
-       if (!this->aead->encrypt(this->aead, crypt, assoc, iv, NULL))
+       if (!aead->encrypt(aead, crypt, assoc, iv, NULL))
        {
-               free(assoc.ptr);
                return FAILED;
        }
-
        DBG3(DBG_ENC, "encrypted %B", &crypt);
        DBG3(DBG_ENC, "ICV %B", &icv);
+       return SUCCESS;
+}
 
-       free(assoc.ptr);
+METHOD(encrypted_payload_t, encrypt, status_t,
+       private_encrypted_payload_t *this, u_int64_t mid, chunk_t assoc)
+{
+       generator_t *generator;
+       chunk_t plain;
+       status_t status;
 
-       return SUCCESS;
+       if (this->aead == NULL)
+       {
+               DBG1(DBG_ENC, "encrypting encrypted payload failed, transform missing");
+               return INVALID_STATE;
+       }
+
+       free(this->encrypted.ptr);
+       generator = generator_create();
+       plain = generate(this, generator);
+       assoc = append_header(this, assoc);
+       /* lower 32-bits are for fragment number, if used */
+       mid <<= 32;
+       status = encrypt_content("encrypted payload", this->aead, mid, plain, assoc,
+                                                        &this->encrypted);
+       generator->destroy(generator);
+       free(assoc.ptr);
+       return status;
 }
 
 METHOD(encrypted_payload_t, encrypt_v1, status_t,
@@ -443,6 +563,7 @@ static status_t parse(private_encrypted_payload_t *this, chunk_t plain)
        payload_type_t type;
 
        parser = parser_create(plain);
+       parser->set_major_version(parser, this->type == PLV1_ENCRYPTED ? 1 : 2);
        type = this->next_payload;
        while (type != PL_NONE)
        {
@@ -476,18 +597,16 @@ static status_t parse(private_encrypted_payload_t *this, chunk_t plain)
        return SUCCESS;
 }
 
-METHOD(encrypted_payload_t, decrypt, status_t,
-       private_encrypted_payload_t *this, chunk_t assoc)
+/**
+ * Decrypts the given data in-place and returns a chunk pointing to the
+ * resulting plaintext.
+ */
+static status_t decrypt_content(char *label, aead_t *aead, chunk_t encrypted,
+                                                               chunk_t assoc, chunk_t *plain)
 {
-       chunk_t iv, plain, padding, icv, crypt;
+       chunk_t iv, padding, icv, crypt;
        size_t bs;
 
-       if (this->aead == NULL)
-       {
-               DBG1(DBG_ENC, "decrypting encrypted payload failed, transform missing");
-               return INVALID_STATE;
-       }
-
        /* prepare data to authenticate-decrypt:
         * | IV | plain | padding | ICV |
         *       \____crypt______/   ^
@@ -495,55 +614,83 @@ METHOD(encrypted_payload_t, decrypt, status_t,
         *              v          /
         *     assoc -> + ------->/
         */
-
-       bs = this->aead->get_block_size(this->aead);
-       iv.len = this->aead->get_iv_size(this->aead);
-       iv.ptr = this->encrypted.ptr;
-       icv.len = this->aead->get_icv_size(this->aead);
-       icv.ptr = this->encrypted.ptr + this->encrypted.len - icv.len;
+       bs = aead->get_block_size(aead);
+       iv.len = aead->get_iv_size(aead);
+       iv.ptr = encrypted.ptr;
+       icv.len = aead->get_icv_size(aead);
+       icv.ptr = encrypted.ptr + encrypted.len - icv.len;
        crypt.ptr = iv.ptr + iv.len;
-       crypt.len = this->encrypted.len - iv.len;
+       crypt.len = encrypted.len - iv.len;
 
-       if (iv.len + icv.len > this->encrypted.len ||
+       if (iv.len + icv.len > encrypted.len ||
                (crypt.len - icv.len) % bs)
        {
-               DBG1(DBG_ENC, "decrypting encrypted payload failed, invalid length");
+               DBG1(DBG_ENC, "decrypting %s payload failed, invalid length", label);
                return FAILED;
        }
 
-       assoc = append_header(this, assoc);
-
-       DBG3(DBG_ENC, "encrypted payload decryption:");
+       DBG3(DBG_ENC, "%s decryption:", label);
        DBG3(DBG_ENC, "IV %B", &iv);
        DBG3(DBG_ENC, "encrypted %B", &crypt);
        DBG3(DBG_ENC, "ICV %B", &icv);
        DBG3(DBG_ENC, "assoc %B", &assoc);
 
-       if (!this->aead->decrypt(this->aead, crypt, assoc, iv, NULL))
+       if (!aead->decrypt(aead, crypt, assoc, iv, NULL))
        {
-               DBG1(DBG_ENC, "verifying encrypted payload integrity failed");
-               free(assoc.ptr);
+               DBG1(DBG_ENC, "verifying %s integrity failed", label);
                return FAILED;
        }
-       free(assoc.ptr);
 
-       plain = chunk_create(crypt.ptr, crypt.len - icv.len);
-       padding.len = plain.ptr[plain.len - 1] + 1;
-       if (padding.len > plain.len)
+       *plain = chunk_create(crypt.ptr, crypt.len - icv.len);
+       padding.len = plain->ptr[plain->len - 1] + 1;
+       if (padding.len > plain->len)
        {
-               DBG1(DBG_ENC, "decrypting encrypted payload failed, "
-                        "padding invalid %B", &crypt);
+               DBG1(DBG_ENC, "decrypting %s failed, padding invalid %B", label,
+                        &crypt);
                return PARSE_ERROR;
        }
-       plain.len -= padding.len;
-       padding.ptr = plain.ptr + plain.len;
+       plain->len -= padding.len;
+       padding.ptr = plain->ptr + plain->len;
 
-       DBG3(DBG_ENC, "plain %B", &plain);
+       DBG3(DBG_ENC, "plain %B", plain);
        DBG3(DBG_ENC, "padding %B", &padding);
+       return SUCCESS;
+}
 
+METHOD(encrypted_payload_t, decrypt, status_t,
+       private_encrypted_payload_t *this, chunk_t assoc)
+{
+       chunk_t plain;
+       status_t status;
+
+       if (this->aead == NULL)
+       {
+               DBG1(DBG_ENC, "decrypting encrypted payload failed, transform missing");
+               return INVALID_STATE;
+       }
+
+       assoc = append_header(this, assoc);
+       status = decrypt_content("encrypted payload", this->aead, this->encrypted,
+                                                        assoc, &plain);
+       free(assoc.ptr);
+
+       if (status != SUCCESS)
+       {
+               return status;
+       }
        return parse(this, plain);
 }
 
+METHOD(encrypted_payload_t, decrypt_plain, status_t,
+       private_encrypted_payload_t *this, chunk_t assoc)
+{
+       if (!this->encrypted.ptr)
+       {
+               return FAILED;
+       }
+       return parse(this, this->encrypted);
+}
+
 METHOD(encrypted_payload_t, decrypt_v1, status_t,
        private_encrypted_payload_t *this, chunk_t iv)
 {
@@ -610,6 +757,7 @@ encrypted_payload_t *encrypted_payload_create(payload_type_t type)
                        .get_length = _get_length,
                        .add_payload = _add_payload,
                        .remove_payload = _remove_payload,
+                       .generate_payloads = _generate_payloads,
                        .set_transform = _set_transform,
                        .encrypt = _encrypt,
                        .decrypt = _decrypt,
@@ -629,3 +777,252 @@ encrypted_payload_t *encrypted_payload_create(payload_type_t type)
 
        return &this->public;
 }
+
+/*
+ * Described in header
+ */
+encrypted_payload_t *encrypted_payload_create_from_plain(payload_type_t next,
+                                                                                                                chunk_t plain)
+{
+       private_encrypted_payload_t *this;
+
+       this = (private_encrypted_payload_t*)encrypted_payload_create(PLV2_ENCRYPTED);
+       this->public.decrypt = _decrypt_plain;
+       this->next_payload = next;
+       this->encrypted = plain;
+       compute_length(this);
+
+       return &this->public;
+}
+
+METHOD(payload_t, frag_verify, status_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       if (!this->fragment_number || !this->total_fragments ||
+               this->fragment_number > this->total_fragments)
+       {
+               DBG1(DBG_ENC, "invalid fragment number (%u) or total fragments (%u)",
+                        this->fragment_number, this->total_fragments);
+               return FAILED;
+       }
+       if (this->fragment_number > 1 && this->next_payload != 0)
+       {
+               DBG1(DBG_ENC, "invalid next payload (%u) for fragment %u, ignored",
+                        this->next_payload, this->fragment_number);
+               this->next_payload = 0;
+       }
+       return SUCCESS;
+}
+
+METHOD(payload_t, frag_get_encoding_rules, int,
+       private_encrypted_fragment_payload_t *this, encoding_rule_t **rules)
+{
+       *rules = encodings_fragment;
+       return countof(encodings_fragment);
+}
+
+METHOD(payload_t, frag_get_header_length, int,
+       private_encrypted_fragment_payload_t *this)
+{
+       return 8;
+}
+
+METHOD(payload_t, frag_get_type, payload_type_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       return PLV2_FRAGMENT;
+}
+
+METHOD(payload_t, frag_get_next_type, payload_type_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       return this->next_payload;
+}
+
+METHOD(payload_t, frag_set_next_type, void,
+       private_encrypted_fragment_payload_t *this, payload_type_t type)
+{
+       if (this->fragment_number == 1 && this->next_payload == PL_NONE)
+       {
+               this->next_payload = type;
+       }
+}
+
+METHOD2(payload_t, encrypted_payload_t, frag_get_length, size_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       if (this->encrypted.len)
+       {
+               this->payload_length = this->encrypted.len;
+       }
+       else
+       {
+               this->payload_length = this->plain.len;
+
+               if (this->aead)
+               {
+                       this->payload_length += compute_overhead(this->aead,
+                                                                                                        this->payload_length);
+               }
+       }
+       this->payload_length += frag_get_header_length(this);
+       return this->payload_length;
+}
+
+METHOD(encrypted_fragment_payload_t, get_fragment_number, u_int16_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       return this->fragment_number;
+}
+
+METHOD(encrypted_fragment_payload_t, get_total_fragments, u_int16_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       return this->total_fragments;
+}
+
+METHOD(encrypted_fragment_payload_t, frag_get_content, chunk_t,
+       private_encrypted_fragment_payload_t *this)
+{
+       return this->plain;
+}
+
+METHOD(encrypted_payload_t, frag_add_payload, void,
+       private_encrypted_fragment_payload_t *this, payload_t* payload)
+{
+       payload->destroy(payload);
+}
+
+METHOD(encrypted_payload_t, frag_set_transform, void,
+       private_encrypted_fragment_payload_t *this, aead_t* aead)
+{
+       this->aead = aead;
+}
+
+/**
+ * Append the encrypted fragment payload header to the associated data
+ */
+static chunk_t append_header_frag(private_encrypted_fragment_payload_t *this,
+                                                                 chunk_t assoc)
+{
+       struct {
+               u_int8_t next_payload;
+               u_int8_t flags;
+               u_int16_t length;
+               u_int16_t fragment_number;
+               u_int16_t total_fragments;
+       } __attribute__((packed)) header = {
+               .next_payload = this->next_payload,
+               .flags = this->flags,
+               .length = htons(frag_get_length(this)),
+               .fragment_number = htons(this->fragment_number),
+               .total_fragments = htons(this->total_fragments),
+       };
+       return chunk_cat("cc", assoc, chunk_from_thing(header));
+}
+
+METHOD(encrypted_payload_t, frag_encrypt, status_t,
+       private_encrypted_fragment_payload_t *this, u_int64_t mid, chunk_t assoc)
+{
+       status_t status;
+
+       if (!this->aead)
+       {
+               DBG1(DBG_ENC, "encrypting encrypted fragment payload failed, "
+                        "transform missing");
+               return INVALID_STATE;
+       }
+       free(this->encrypted.ptr);
+       assoc = append_header_frag(this, assoc);
+       /* IKEv2 message IDs are not unique if fragmentation is used, hence include
+        * the fragment number to make it unique */
+       mid = mid << 32 | this->fragment_number;
+       status = encrypt_content("encrypted fragment payload", this->aead, mid,
+                                                        this->plain, assoc, &this->encrypted);
+       free(assoc.ptr);
+       return status;
+}
+
+METHOD(encrypted_payload_t, frag_decrypt, status_t,
+       private_encrypted_fragment_payload_t *this, chunk_t assoc)
+{
+       status_t status;
+
+       if (!this->aead)
+       {
+               DBG1(DBG_ENC, "decrypting encrypted fragment payload failed, "
+                        "transform missing");
+               return INVALID_STATE;
+       }
+       free(this->plain.ptr);
+       assoc = append_header_frag(this, assoc);
+       status = decrypt_content("encrypted fragment payload", this->aead,
+                                                        this->encrypted, assoc, &this->plain);
+       this->plain = chunk_clone(this->plain);
+       free(assoc.ptr);
+       return status;
+}
+
+METHOD2(payload_t, encrypted_payload_t, frag_destroy, void,
+       private_encrypted_fragment_payload_t *this)
+{
+       free(this->encrypted.ptr);
+       free(this->plain.ptr);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+encrypted_fragment_payload_t *encrypted_fragment_payload_create()
+{
+       private_encrypted_fragment_payload_t *this;
+
+       INIT(this,
+               .public = {
+                       .encrypted = {
+                               .payload_interface = {
+                                       .verify = _frag_verify,
+                                       .get_encoding_rules = _frag_get_encoding_rules,
+                                       .get_header_length = _frag_get_header_length,
+                                       .get_length = _frag_get_length,
+                                       .get_next_type = _frag_get_next_type,
+                                       .set_next_type = _frag_set_next_type,
+                                       .get_type = _frag_get_type,
+                                       .destroy = _frag_destroy,
+                               },
+                               .get_length = _frag_get_length,
+                               .add_payload = _frag_add_payload,
+                               .remove_payload = (void*)return_null,
+                               .generate_payloads = nop,
+                               .set_transform = _frag_set_transform,
+                               .encrypt = _frag_encrypt,
+                               .decrypt = _frag_decrypt,
+                               .destroy = _frag_destroy,
+                       },
+                       .get_fragment_number = _get_fragment_number,
+                       .get_total_fragments = _get_total_fragments,
+                       .get_content = _frag_get_content,
+               },
+               .next_payload = PL_NONE,
+       );
+       this->payload_length = frag_get_header_length(this);
+
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
+encrypted_fragment_payload_t *encrypted_fragment_payload_create_from_data(
+                                                               u_int16_t num, u_int16_t total, chunk_t plain)
+{
+       private_encrypted_fragment_payload_t *this;
+
+       this = (private_encrypted_fragment_payload_t*)encrypted_fragment_payload_create();
+       this->fragment_number = num;
+       this->total_fragments = total;
+       this->plain = chunk_clone(plain);
+
+       return &this->public;
+}