libipsec: Wrap traditional algorithms in AEAD wrapper
This commit is contained in:
parent
61fb3267b2
commit
24a8d1253f
|
@ -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,27 +190,83 @@ METHOD(esp_context_t, next_seqno, bool,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, get_signer, signer_t *,
|
||||
private_esp_context_t *this)
|
||||
METHOD(esp_context_t, get_aead, aead_t*,
|
||||
private_esp_context_t *this)
|
||||
{
|
||||
return this->signer;
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, get_crypter, crypter_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create AEAD wrapper around traditional encryption/integrity algorithms
|
||||
*/
|
||||
static bool create_traditional(private_esp_context_t *this, int enc_alg,
|
||||
chunk_t enc_key, int int_alg, chunk_t int_key)
|
||||
{
|
||||
crypter_t *crypter = NULL;
|
||||
signer_t *signer = NULL;
|
||||
|
||||
switch (enc_alg)
|
||||
{
|
||||
case ENCR_AES_CBC:
|
||||
crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
|
||||
enc_key.len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!crypter)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
|
||||
"algorithm");
|
||||
goto failed;
|
||||
}
|
||||
if (!crypter->set_key(crypter, enc_key))
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
|
||||
"failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
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:
|
||||
signer = lib->crypto->create_signer(lib->crypto, int_alg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!signer)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
|
||||
"algorithm");
|
||||
goto failed;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
@ -228,8 +277,7 @@ esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
|
|||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_crypter = _get_crypter,
|
||||
.get_signer = _get_signer,
|
||||
.get_aead = _get_aead,
|
||||
.get_seqno = _get_seqno,
|
||||
.next_seqno = _next_seqno,
|
||||
.verify_seqno = _verify_seqno,
|
||||
|
@ -240,52 +288,8 @@ esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
|
|||
.window_size = ESP_DEFAULT_WINDOW_SIZE,
|
||||
);
|
||||
|
||||
switch(enc_alg)
|
||||
if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
|
||||
{
|
||||
case ENCR_AES_CBC:
|
||||
this->crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
|
||||
enc_key.len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!this->crypter)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
|
||||
"algorithm");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (!this->crypter->set_key(this->crypter, enc_key))
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
|
||||
"failed");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!this->signer)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
|
||||
"algorithm");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (!this->signer->set_key(this->signer, int_key))
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
|
||||
"failed");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -297,5 +301,3 @@ esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
|
|||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,21 +245,16 @@ 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))
|
||||
/* aad = spi + seq */
|
||||
aad = chunk_create(data.ptr, 8);
|
||||
|
||||
if (!aead->decrypt(aead, ciphertext, aad, iv, &plaintext))
|
||||
{
|
||||
DBG1(DBG_ESP, "ICV verification failed!");
|
||||
DBG1(DBG_ESP, "ESP decryption or ICV verification failed");
|
||||
return FAILED;
|
||||
}
|
||||
esp_context->set_authenticated_seqno(esp_context, seq);
|
||||
|
||||
if (!crypter->decrypt(crypter, ciphertext, iv, &plaintext))
|
||||
{
|
||||
DBG1(DBG_ESP, "ESP decryption failed");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (!remove_padding(this, plaintext))
|
||||
{
|
||||
return PARSE_ERROR;
|
||||
|
@ -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))
|
||||
/* encrypt/authenticate the content inline */
|
||||
if (!aead->encrypt(aead, ciphertext, aad, 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))
|
||||
{
|
||||
DBG1(DBG_ESP, "ESP encryption failed: signature generation failed");
|
||||
DBG1(DBG_ESP, "ESP encryption or ICV generation failed");
|
||||
writer->destroy(writer);
|
||||
return FAILED;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue