libipsec: Wrap traditional algorithms in AEAD wrapper
authorTobias Brunner <tobias@strongswan.org>
Thu, 18 Apr 2013 15:02:41 +0000 (17:02 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 3 May 2013 13:13:57 +0000 (15:13 +0200)
src/libipsec/esp_context.c
src/libipsec/esp_context.h
src/libipsec/esp_packet.c

index 44b1117..86e8dd0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2013 Tobias Brunner
  * Copyright (C) 2012 Giuliano Grassi
  * Copyright (C) 2012 Ralf Sager
  * Hochschule fuer Technik Rapperswil
@@ -22,8 +22,6 @@
 
 #include <library.h>
 #include <utils/debug.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
 
 /**
  * Should be a multiple of 8
@@ -43,14 +41,9 @@ struct private_esp_context_t {
        esp_context_t public;
 
        /**
-        * Crypter used to encrypt/decrypt ESP packets
+        * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
         */
-       crypter_t *crypter;
-
-       /**
-        * Signer to authenticate ESP packets
-        */
-       signer_t *signer;
+       aead_t *aead;
 
        /**
         * The highest sequence number that was successfully verified
@@ -197,95 +190,106 @@ METHOD(esp_context_t, next_seqno, bool,
        return TRUE;
 }
 
-METHOD(esp_context_t, get_signer, signer_t *,
-               private_esp_context_t *this)
-{
-       return this->signer;
-}
-
-METHOD(esp_context_t, get_crypter, crypter_t *,
-               private_esp_context_t *this)
+METHOD(esp_context_t, get_aead, aead_t*,
+       private_esp_context_t *this)
 {
-       return this->crypter;
+       return this->aead;
 }
 
 METHOD(esp_context_t, destroy, void,
-               private_esp_context_t *this)
+       private_esp_context_t *this)
 {
        chunk_free(&this->window);
-       DESTROY_IF(this->crypter);
-       DESTROY_IF(this->signer);
+       DESTROY_IF(this->aead);
        free(this);
 }
 
 /**
- * Described in header.
+ * Create AEAD wrapper around traditional encryption/integrity algorithms
  */
-esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
-                                                                 int int_alg, chunk_t int_key, bool inbound)
+static bool create_traditional(private_esp_context_t *this, int enc_alg,
+                                                          chunk_t enc_key, int int_alg, chunk_t int_key)
 {
-       private_esp_context_t *this;
+       crypter_t *crypter = NULL;
+       signer_t *signer = NULL;
 
-       INIT(this,
-               .public = {
-                       .get_crypter = _get_crypter,
-                       .get_signer = _get_signer,
-                       .get_seqno = _get_seqno,
-                       .next_seqno = _next_seqno,
-                       .verify_seqno = _verify_seqno,
-                       .set_authenticated_seqno = _set_authenticated_seqno,
-                       .destroy = _destroy,
-               },
-               .inbound = inbound,
-               .window_size = ESP_DEFAULT_WINDOW_SIZE,
-       );
-
-       switch(enc_alg)
+       switch (enc_alg)
        {
                case ENCR_AES_CBC:
-                       this->crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
-                                                                                                               enc_key.len);
+                       crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
+                                                                                                 enc_key.len);
                        break;
                default:
                        break;
        }
-       if (!this->crypter)
+       if (!crypter)
        {
                DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
                         "algorithm");
-               destroy(this);
-               return NULL;
+               goto failed;
        }
-       if (!this->crypter->set_key(this->crypter, enc_key))
+       if (!crypter->set_key(crypter, enc_key))
        {
                DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
                         "failed");
-               destroy(this);
-               return NULL;
+               goto failed;
        }
 
-       switch(int_alg)
+       switch (int_alg)
        {
                case AUTH_HMAC_SHA1_96:
                case AUTH_HMAC_SHA2_256_128:
                case AUTH_HMAC_SHA2_384_192:
                case AUTH_HMAC_SHA2_512_256:
-                       this->signer = lib->crypto->create_signer(lib->crypto, int_alg);
+                       signer = lib->crypto->create_signer(lib->crypto, int_alg);
                        break;
                default:
                        break;
        }
-       if (!this->signer)
+       if (!signer)
        {
                DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
                         "algorithm");
-               destroy(this);
-               return NULL;
+               goto failed;
        }
-       if (!this->signer->set_key(this->signer, int_key))
+       if (!signer->set_key(signer, int_key))
        {
                DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
                         "failed");
+               goto failed;
+       }
+       this->aead = aead_create(crypter, signer);
+       return TRUE;
+
+failed:
+       DESTROY_IF(crypter);
+       DESTROY_IF(signer);
+       return FALSE;
+}
+
+/**
+ * Described in header.
+ */
+esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
+                                                                 int int_alg, chunk_t int_key, bool inbound)
+{
+       private_esp_context_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_aead = _get_aead,
+                       .get_seqno = _get_seqno,
+                       .next_seqno = _next_seqno,
+                       .verify_seqno = _verify_seqno,
+                       .set_authenticated_seqno = _set_authenticated_seqno,
+                       .destroy = _destroy,
+               },
+               .inbound = inbound,
+               .window_size = ESP_DEFAULT_WINDOW_SIZE,
+       );
+
+       if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
+       {
                destroy(this);
                return NULL;
        }
@@ -297,5 +301,3 @@ esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
        }
        return &this->public;
 }
-
-
index db247dc..b33daf5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2013 Tobias Brunner
  * Copyright (C) 2012 Giuliano Grassi
  * Copyright (C) 2012 Ralf Sager
  * Hochschule fuer Technik Rapperswil
@@ -24,8 +24,7 @@
 #define ESP_CONTEXT_H_
 
 #include <library.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
+#include <crypto/aead.h>
 
 typedef struct esp_context_t esp_context_t;
 
@@ -35,18 +34,11 @@ typedef struct esp_context_t esp_context_t;
 struct esp_context_t {
 
        /**
-        * Get the crypter.
+        * Get AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets.
         *
-        * @return                              crypter
+        * @return                              AEAD wrapper of method
         */
-       crypter_t *(*get_crypter)(esp_context_t *this);
-
-       /**
-        * Get the signer.
-        *
-        * @return                              signer
-        */
-       signer_t *(*get_signer)(esp_context_t *this);
+       aead_t *(*get_aead)(esp_context_t *this);
 
        /**
         * Get the current outbound ESP sequence number or the highest authenticated
index 43a3c2a..61389da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2013 Tobias Brunner
  * Copyright (C) 2012 Giuliano Grassi
  * Copyright (C) 2012 Ralf Sager
  * Hochschule fuer Technik Rapperswil
@@ -212,28 +212,27 @@ METHOD(esp_packet_t, decrypt, status_t,
 {
        bio_reader_t *reader;
        u_int32_t spi, seq;
-       chunk_t data, iv, icv, ciphertext, plaintext;
-       crypter_t *crypter;
-       signer_t *signer;
+       chunk_t data, iv, icv, aad, ciphertext, plaintext;
+       aead_t *aead;
 
        DESTROY_IF(this->payload);
        this->payload = NULL;
 
        data = this->packet->get_data(this->packet);
-       crypter = esp_context->get_crypter(esp_context);
-       signer = esp_context->get_signer(esp_context);
+       aead = esp_context->get_aead(esp_context);
 
        reader = bio_reader_create(data);
        if (!reader->read_uint32(reader, &spi) ||
                !reader->read_uint32(reader, &seq) ||
-               !reader->read_data(reader, crypter->get_iv_size(crypter), &iv) ||
-               !reader->read_data_end(reader, signer->get_block_size(signer), &icv) ||
-               reader->remaining(reader) % crypter->get_block_size(crypter))
+               !reader->read_data(reader, aead->get_iv_size(aead), &iv) ||
+               !reader->read_data_end(reader, aead->get_icv_size(aead), &icv) ||
+               reader->remaining(reader) % aead->get_block_size(aead))
        {
                DBG1(DBG_ESP, "ESP decryption failed: invalid length");
                return PARSE_ERROR;
        }
        ciphertext = reader->peek(reader);
+       ciphertext.len += icv.len;
        reader->destroy(reader);
 
        if (!esp_context->verify_seqno(esp_context, seq))
@@ -246,20 +245,15 @@ METHOD(esp_packet_t, decrypt, status_t,
        DBG3(DBG_ESP, "ESP decryption:\n  SPI %.8x [seq %u]\n  IV %B\n  "
                 "encrypted %B\n  ICV %B", spi, seq, &iv, &ciphertext, &icv);
 
-       if (!signer->get_signature(signer, chunk_create(data.ptr, 8), NULL) ||
-               !signer->get_signature(signer, iv, NULL) ||
-               !signer->verify_signature(signer, ciphertext, icv))
-       {
-               DBG1(DBG_ESP, "ICV verification failed!");
-               return FAILED;
-       }
-       esp_context->set_authenticated_seqno(esp_context, seq);
+       /* aad = spi + seq */
+       aad = chunk_create(data.ptr, 8);
 
-       if (!crypter->decrypt(crypter, ciphertext, iv, &plaintext))
+       if (!aead->decrypt(aead, ciphertext, aad, iv, &plaintext))
        {
-               DBG1(DBG_ESP, "ESP decryption failed");
+               DBG1(DBG_ESP, "ESP decryption or ICV verification failed");
                return FAILED;
        }
+       esp_context->set_authenticated_seqno(esp_context, seq);
 
        if (!remove_padding(this, plaintext))
        {
@@ -284,12 +278,11 @@ static void generate_padding(chunk_t padding)
 METHOD(esp_packet_t, encrypt, status_t,
        private_esp_packet_t *this, esp_context_t *esp_context, u_int32_t spi)
 {
-       chunk_t iv, icv, padding, payload, ciphertext, auth_data;
+       chunk_t iv, icv, aad, padding, payload, ciphertext;
        bio_writer_t *writer;
        u_int32_t next_seqno;
        size_t blocksize, plainlen;
-       crypter_t *crypter;
-       signer_t *signer;
+       aead_t *aead;
        rng_t *rng;
 
        this->packet->set_data(this->packet, chunk_empty);
@@ -306,12 +299,11 @@ METHOD(esp_packet_t, encrypt, status_t,
                DBG1(DBG_ESP, "ESP encryption failed: could not find RNG");
                return NOT_FOUND;
        }
-       crypter = esp_context->get_crypter(esp_context);
-       signer = esp_context->get_signer(esp_context);
+       aead = esp_context->get_aead(esp_context);
 
-       blocksize = crypter->get_block_size(crypter);
-       iv.len = crypter->get_iv_size(crypter);
-       icv.len = signer->get_block_size(signer);
+       blocksize = aead->get_block_size(aead);
+       iv.len = aead->get_iv_size(aead);
+       icv.len = aead->get_icv_size(aead);
 
        /* plaintext = payload, padding, pad_length, next_header */
        payload = this->payload ? this->payload->get_encoding(this->payload)
@@ -349,24 +341,19 @@ METHOD(esp_packet_t, encrypt, status_t,
        writer->write_uint8(writer, padding.len);
        writer->write_uint8(writer, this->next_header);
 
+       /* aad = spi + seq */
+       aad = writer->get_buf(writer);
+       aad.len = 8;
+       icv = writer->skip(writer, icv.len);
+
        DBG3(DBG_ESP, "ESP before encryption:\n  payload = %B\n  padding = %B\n  "
                 "padding length = %hhu, next header = %hhu", &payload, &padding,
                 (u_int8_t)padding.len, this->next_header);
 
-       /* encrypt the content inline */
-       if (!crypter->encrypt(crypter, ciphertext, iv, NULL))
-       {
-               DBG1(DBG_ESP, "ESP encryption failed");
-               writer->destroy(writer);
-               return FAILED;
-       }
-
-       /* calculate signature */
-       auth_data = writer->get_buf(writer);
-       icv = writer->skip(writer, icv.len);
-       if (!signer->get_signature(signer, auth_data, icv.ptr))
+       /* encrypt/authenticate the content inline */
+       if (!aead->encrypt(aead, ciphertext, aad, iv, NULL))
        {
-               DBG1(DBG_ESP, "ESP encryption failed: signature generation failed");
+               DBG1(DBG_ESP, "ESP encryption or ICV generation failed");
                writer->destroy(writer);
                return FAILED;
        }