mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-09 00:00:53 -04:00
encrypted_payload: Extract some utility functions
This commit is contained in:
parent
41751a70d9
commit
44996b5866
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2011-2014 Tobias Brunner
|
||||||
* Copyright (C) 2005-2010 Martin Willi
|
* Copyright (C) 2005-2010 Martin Willi
|
||||||
* Copyright (C) 2010 revosec AG
|
* Copyright (C) 2010 revosec AG
|
||||||
* Copyright (C) 2011 Tobias Brunner
|
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@ -179,6 +179,23 @@ METHOD(payload_t, set_next_type, void,
|
|||||||
this->next_payload = type;
|
this->next_payload = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Compute the length of the whole payload
|
||||||
*/
|
*/
|
||||||
@ -186,7 +203,7 @@ static void compute_length(private_encrypted_payload_t *this)
|
|||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
payload_t *payload;
|
payload_t *payload;
|
||||||
size_t bs, length = 0;
|
size_t length = 0;
|
||||||
|
|
||||||
if (this->encrypted.len)
|
if (this->encrypted.len)
|
||||||
{
|
{
|
||||||
@ -203,13 +220,7 @@ static void compute_length(private_encrypted_payload_t *this)
|
|||||||
|
|
||||||
if (this->aead)
|
if (this->aead)
|
||||||
{
|
{
|
||||||
/* append padding */
|
length += compute_overhead(this->aead, length);
|
||||||
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 += get_header_length(this);
|
length += get_header_length(this);
|
||||||
@ -304,44 +315,36 @@ static chunk_t append_header(private_encrypted_payload_t *this, chunk_t assoc)
|
|||||||
return chunk_cat("cc", assoc, chunk_from_thing(header));
|
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;
|
chunk_t iv, padding, icv, crypt;
|
||||||
generator_t *generator;
|
|
||||||
iv_gen_t *iv_gen;
|
iv_gen_t *iv_gen;
|
||||||
rng_t *rng;
|
rng_t *rng;
|
||||||
size_t bs;
|
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);
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
if (!rng)
|
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;
|
return NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
iv_gen = this->aead->get_iv_gen(this->aead);
|
iv_gen = aead->get_iv_gen(aead);
|
||||||
if (!iv_gen)
|
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;
|
return NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
assoc = append_header(this, assoc);
|
bs = aead->get_block_size(aead);
|
||||||
|
|
||||||
generator = generator_create();
|
|
||||||
plain = generate(this, generator);
|
|
||||||
bs = this->aead->get_block_size(this->aead);
|
|
||||||
/* we need at least one byte padding to store the padding length */
|
/* we need at least one byte padding to store the padding length */
|
||||||
padding.len = bs - (plain.len % bs);
|
padding.len = bs - (plain.len % bs);
|
||||||
iv.len = this->aead->get_iv_size(this->aead);
|
iv.len = aead->get_iv_size(aead);
|
||||||
icv.len = this->aead->get_icv_size(this->aead);
|
icv.len = aead->get_icv_size(aead);
|
||||||
|
|
||||||
/* prepare data to authenticate-encrypt:
|
/* prepare data to authenticate-encrypt:
|
||||||
* | IV | plain | padding | ICV |
|
* | IV | plain | padding | ICV |
|
||||||
@ -350,47 +353,64 @@ METHOD(encrypted_payload_t, encrypt, status_t,
|
|||||||
* v /
|
* v /
|
||||||
* assoc -> + ------->/
|
* assoc -> + ------->/
|
||||||
*/
|
*/
|
||||||
free(this->encrypted.ptr);
|
*encrypted = chunk_alloc(iv.len + plain.len + padding.len + icv.len);
|
||||||
this->encrypted = chunk_alloc(iv.len + plain.len + padding.len + icv.len);
|
iv.ptr = encrypted->ptr;
|
||||||
iv.ptr = this->encrypted.ptr;
|
|
||||||
memcpy(iv.ptr + iv.len, plain.ptr, plain.len);
|
memcpy(iv.ptr + iv.len, plain.ptr, plain.len);
|
||||||
plain.ptr = iv.ptr + iv.len;
|
plain.ptr = iv.ptr + iv.len;
|
||||||
padding.ptr = plain.ptr + plain.len;
|
padding.ptr = plain.ptr + plain.len;
|
||||||
icv.ptr = padding.ptr + padding.len;
|
icv.ptr = padding.ptr + padding.len;
|
||||||
crypt = chunk_create(plain.ptr, plain.len + 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) ||
|
if (!iv_gen->get_iv(iv_gen, mid, iv.len, iv.ptr) ||
|
||||||
!rng->get_bytes(rng, padding.len - 1, padding.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);
|
rng->destroy(rng);
|
||||||
free(assoc.ptr);
|
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
padding.ptr[padding.len - 1] = padding.len - 1;
|
padding.ptr[padding.len - 1] = padding.len - 1;
|
||||||
rng->destroy(rng);
|
rng->destroy(rng);
|
||||||
|
|
||||||
DBG3(DBG_ENC, "encrypted payload encryption:");
|
DBG3(DBG_ENC, "%s encryption:", label);
|
||||||
DBG3(DBG_ENC, "IV %B", &iv);
|
DBG3(DBG_ENC, "IV %B", &iv);
|
||||||
DBG3(DBG_ENC, "plain %B", &plain);
|
DBG3(DBG_ENC, "plain %B", &plain);
|
||||||
DBG3(DBG_ENC, "padding %B", &padding);
|
DBG3(DBG_ENC, "padding %B", &padding);
|
||||||
DBG3(DBG_ENC, "assoc %B", &assoc);
|
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;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG3(DBG_ENC, "encrypted %B", &crypt);
|
DBG3(DBG_ENC, "encrypted %B", &crypt);
|
||||||
DBG3(DBG_ENC, "ICV %B", &icv);
|
DBG3(DBG_ENC, "ICV %B", &icv);
|
||||||
|
|
||||||
free(assoc.ptr);
|
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
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,
|
METHOD(encrypted_payload_t, encrypt_v1, status_t,
|
||||||
private_encrypted_payload_t *this, u_int64_t mid, chunk_t iv)
|
private_encrypted_payload_t *this, u_int64_t mid, chunk_t iv)
|
||||||
{
|
{
|
||||||
@ -476,18 +496,16 @@ static status_t parse(private_encrypted_payload_t *this, chunk_t plain)
|
|||||||
return SUCCESS;
|
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;
|
size_t bs;
|
||||||
|
|
||||||
if (this->aead == NULL)
|
|
||||||
{
|
|
||||||
DBG1(DBG_ENC, "decrypting encrypted payload failed, transform missing");
|
|
||||||
return INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare data to authenticate-decrypt:
|
/* prepare data to authenticate-decrypt:
|
||||||
* | IV | plain | padding | ICV |
|
* | IV | plain | padding | ICV |
|
||||||
* \____crypt______/ ^
|
* \____crypt______/ ^
|
||||||
@ -495,52 +513,70 @@ METHOD(encrypted_payload_t, decrypt, status_t,
|
|||||||
* v /
|
* v /
|
||||||
* assoc -> + ------->/
|
* assoc -> + ------->/
|
||||||
*/
|
*/
|
||||||
|
bs = aead->get_block_size(aead);
|
||||||
bs = this->aead->get_block_size(this->aead);
|
iv.len = aead->get_iv_size(aead);
|
||||||
iv.len = this->aead->get_iv_size(this->aead);
|
iv.ptr = encrypted.ptr;
|
||||||
iv.ptr = this->encrypted.ptr;
|
icv.len = aead->get_icv_size(aead);
|
||||||
icv.len = this->aead->get_icv_size(this->aead);
|
icv.ptr = encrypted.ptr + encrypted.len - icv.len;
|
||||||
icv.ptr = this->encrypted.ptr + this->encrypted.len - icv.len;
|
|
||||||
crypt.ptr = iv.ptr + iv.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)
|
(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;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
assoc = append_header(this, assoc);
|
DBG3(DBG_ENC, "%s decryption:", label);
|
||||||
|
|
||||||
DBG3(DBG_ENC, "encrypted payload decryption:");
|
|
||||||
DBG3(DBG_ENC, "IV %B", &iv);
|
DBG3(DBG_ENC, "IV %B", &iv);
|
||||||
DBG3(DBG_ENC, "encrypted %B", &crypt);
|
DBG3(DBG_ENC, "encrypted %B", &crypt);
|
||||||
DBG3(DBG_ENC, "ICV %B", &icv);
|
DBG3(DBG_ENC, "ICV %B", &icv);
|
||||||
DBG3(DBG_ENC, "assoc %B", &assoc);
|
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");
|
DBG1(DBG_ENC, "verifying %s integrity failed", label);
|
||||||
free(assoc.ptr);
|
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
free(assoc.ptr);
|
|
||||||
|
|
||||||
plain = chunk_create(crypt.ptr, crypt.len - icv.len);
|
*plain = chunk_create(crypt.ptr, crypt.len - icv.len);
|
||||||
padding.len = plain.ptr[plain.len - 1] + 1;
|
padding.len = plain->ptr[plain->len - 1] + 1;
|
||||||
if (padding.len > plain.len)
|
if (padding.len > plain->len)
|
||||||
{
|
{
|
||||||
DBG1(DBG_ENC, "decrypting encrypted payload failed, "
|
DBG1(DBG_ENC, "decrypting %s failed, padding invalid %B", label,
|
||||||
"padding invalid %B", &crypt);
|
&crypt);
|
||||||
return PARSE_ERROR;
|
return PARSE_ERROR;
|
||||||
}
|
}
|
||||||
plain.len -= padding.len;
|
plain->len -= padding.len;
|
||||||
padding.ptr = plain.ptr + plain.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);
|
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);
|
return parse(this, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user