Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gcm pager #1959

Merged
merged 7 commits into from
Nov 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 90 additions & 37 deletions core/arch/arm/crypto/aes-gcm-ce.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,37 @@ static void put_be_block(void *dst, const void *src)
put_be64((uint8_t *)dst + 8, s[0]);
}

TEE_Result internal_aes_gcm_set_key(struct internal_aes_gcm_ctx *ctx,
const void *key, size_t key_len)
void internal_aes_gcm_set_key(struct internal_aes_gcm_state *state,
const struct internal_aes_gcm_key *enc_key)
{
uint64_t k[2];
uint64_t a;
uint64_t b;

if (aes_setup(key, key_len, 0, &ctx->skey))
return TEE_ERROR_BAD_PARAMETERS;

internal_aes_gcm_encrypt_block(ctx, ctx->ctr, ctx->hash_subkey);
internal_aes_gcm_encrypt_block(enc_key, state->ctr, state->hash_subkey);

/* Store hash key in little endian and multiply by 'x' */
b = get_be64(ctx->hash_subkey);
a = get_be64(ctx->hash_subkey + 8);
b = get_be64(state->hash_subkey);
a = get_be64(state->hash_subkey + 8);
k[0] = (a << 1) | (b >> 63);
k[1] = (b << 1) | (a >> 63);
if (b >> 63)
k[1] ^= 0xc200000000000000UL;

memcpy(ctx->hash_subkey, k, TEE_AES_BLOCK_SIZE);
return TEE_SUCCESS;
memcpy(state->hash_subkey, k, TEE_AES_BLOCK_SIZE);
}

void internal_aes_gcm_ghash_update(struct internal_aes_gcm_ctx *ctx,
void internal_aes_gcm_ghash_update(struct internal_aes_gcm_state *state,
const void *head, const void *data,
size_t num_blocks)
size_t num_blocks)
{
uint32_t vfp_state;
uint64_t dg[2];
uint64_t *k;

get_be_block(dg, ctx->hash_state);
get_be_block(dg, state->hash_state);

k = (void *)ctx->hash_subkey;
k = (void *)state->hash_subkey;

vfp_state = thread_kernel_enable_vfp();

Expand All @@ -74,56 +70,113 @@ void internal_aes_gcm_ghash_update(struct internal_aes_gcm_ctx *ctx,
#endif
thread_kernel_disable_vfp(vfp_state);

put_be_block(ctx->hash_state, dg);
put_be_block(state->hash_state, dg);
}

#ifdef ARM64
void internal_aes_gcm_encrypt_block(struct internal_aes_gcm_ctx *ctx,
static uint32_t ror32(uint32_t word, unsigned int shift)
{
return (word >> shift) | (word << (32 - shift));
}

TEE_Result internal_aes_gcm_expand_enc_key(const void *key, size_t key_len,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ARM64 only?

I understand you're copying code from core/lib/libtomcrypt/src/ciphers/ (aes_armv8a_ce.c and aes_modes_armv8a_ce_a64.S) into core/arch/arm/crypto/ (aes-gcm-ce.c and ghash-ce-core_a64.S) to cut that dependency on LTC so that pager can use accelerated code. Two things:

  1. You should clearly say where the code comes from in the commit log
  2. Why not update similarly ghash-ce-core_a32.S using code from aes_modes_armv8a_ce_a32.S(function ce_aes_sub()) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes, I'll update the commit message
  2. We don't have any AES routines for ARM32 yet so there's nothing to be done in this area for ARM32 yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core/lib/libtomcrypt/src/ciphers/aes_modes_armv8a_ce_a32.S?

Copy link
Contributor Author

@jenswi-linaro jenswi-linaro Nov 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I wasn't clear. In ARM64 we have an implementation with AES and GHASH fused, which gives a good speedup. In ARM32 we don't have such an implementation (yet, ever?) so instead we're using the AES API in the cryptolib.

What we could do, is to extract the CE AES implementation from LTC and supply it to LTC similarly to how GHASH is supplied. The advantage is that we can get rid of some redundancy and have easier access to the routines. This however is not in that scope of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've got it now.

struct internal_aes_gcm_key *enc_key)
{
/* The AES key schedule round constants */
static uint8_t const rcon[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
};
uint32_t vfp_state;
uint32_t kwords = key_len / sizeof(uint32_t);
void *p = enc_key->data;
uint32_t *k = p;
unsigned int i;

if (key_len != 16 && key_len != 24 && key_len != 32)
return TEE_ERROR_BAD_PARAMETERS;

memcpy(k, key, key_len);
/*
* # of rounds specified by AES:
* 128 bit key 10 rounds
* 192 bit key 12 rounds
* 256 bit key 14 rounds
* => n byte key => 6 + (n/4) rounds
*/
enc_key->rounds = 6 + key_len / 4;

vfp_state = thread_kernel_enable_vfp();
for (i = 0; i < sizeof(rcon); i++) {
uint32_t *rki = k + (i * kwords);
uint32_t *rko = rki + kwords;

rko[0] = ror32(pmull_gcm_aes_sub(rki[kwords - 1]), 8) ^
rcon[i] ^ rki[0];
rko[1] = rko[0] ^ rki[1];
rko[2] = rko[1] ^ rki[2];
rko[3] = rko[2] ^ rki[3];

if (key_len == 24) {
if (i >= 7)
break;
rko[4] = rko[3] ^ rki[4];
rko[5] = rko[4] ^ rki[5];
} else if (key_len == 32) {
if (i >= 6)
break;
rko[4] = pmull_gcm_aes_sub(rko[3]) ^ rki[4];
rko[5] = rko[4] ^ rki[5];
rko[6] = rko[5] ^ rki[6];
rko[7] = rko[6] ^ rki[7];
}
}

thread_kernel_disable_vfp(vfp_state);
return TEE_SUCCESS;
}

void internal_aes_gcm_encrypt_block(const struct internal_aes_gcm_key *ek,
const void *src, void *dst)
{
uint32_t vfp_state;
void *enc_key = ctx->skey.rijndael.eK;
size_t rounds = ctx->skey.rijndael.Nr;

vfp_state = thread_kernel_enable_vfp();

pmull_gcm_load_round_keys(enc_key, rounds);
pmull_gcm_encrypt_block(dst, src, rounds);
pmull_gcm_load_round_keys(ek->data, ek->rounds);
pmull_gcm_encrypt_block(dst, src, ek->rounds);

thread_kernel_disable_vfp(vfp_state);
}

void
internal_aes_gcm_update_payload_block_aligned(struct internal_aes_gcm_ctx *ctx,
TEE_OperationMode m,
const void *src,
size_t num_blocks, void *dst)
void internal_aes_gcm_update_payload_block_aligned(
struct internal_aes_gcm_state *state,
const struct internal_aes_gcm_key *ek,
TEE_OperationMode mode, const void *src,
size_t num_blocks, void *dst)
{
uint32_t vfp_state;
uint64_t dg[2];
uint64_t ctr[2];
uint64_t *k;
void *enc_key = ctx->skey.rijndael.eK;
size_t rounds = ctx->skey.rijndael.Nr;

get_be_block(dg, ctx->hash_state);
get_be_block(ctr, ctx->ctr);
get_be_block(dg, state->hash_state);
get_be_block(ctr, state->ctr);

k = (void *)ctx->hash_subkey;
k = (void *)state->hash_subkey;

vfp_state = thread_kernel_enable_vfp();

pmull_gcm_load_round_keys(enc_key, rounds);
pmull_gcm_load_round_keys(ek->data, ek->rounds);

if (m == TEE_MODE_ENCRYPT)
pmull_gcm_encrypt(num_blocks, dg, dst, src, k, ctr, rounds,
ctx->buf_cryp);
if (mode == TEE_MODE_ENCRYPT)
pmull_gcm_encrypt(num_blocks, dg, dst, src, k, ctr, ek->rounds,
state->buf_cryp);
else
pmull_gcm_decrypt(num_blocks, dg, dst, src, k, ctr, rounds);
pmull_gcm_decrypt(num_blocks, dg, dst, src, k, ctr, ek->rounds);

thread_kernel_disable_vfp(vfp_state);

put_be_block(ctx->ctr, ctr);
put_be_block(ctx->hash_state, dg);
put_be_block(state->ctr, ctr);
put_be_block(state->hash_state, dg);
}
#endif /*ARM64*/
14 changes: 14 additions & 0 deletions core/arch/arm/crypto/ghash-ce-core_a64.S
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,17 @@ ENTRY(pmull_gcm_load_round_keys)
load_round_keys w1, x0
ret
ENDPROC(pmull_gcm_load_round_keys)

/*
* uint32_t pmull_gcm_aes_sub(uint32_t input)
*
* use the aese instruction to perform the AES sbox substitution
* on each byte in 'input'
*/
ENTRY(pmull_gcm_aes_sub)
dup v1.4s, w0
movi v0.16b, #0
aese v0.16b, v1.16b
umov w0, v0.4s[0]
ret
ENDPROC(pmull_gcm_aes_sub)
4 changes: 3 additions & 1 deletion core/arch/arm/include/crypto/ghash-ce-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void pmull_ghash_update_p64(int blocks, uint64_t dg[2], const uint8_t *src,
void pmull_ghash_update_p8(int blocks, uint64_t dg[2], const uint8_t *src,
const uint64_t k[2], const uint8_t *head);

void pmull_gcm_load_round_keys(uint64_t rk[30], int rounds);
void pmull_gcm_load_round_keys(const uint64_t rk[30], int rounds);

void pmull_gcm_encrypt(int blocks, uint64_t dg[2], uint8_t dst[],
const uint8_t src[], const uint64_t k[2],
Expand All @@ -26,6 +26,8 @@ void pmull_gcm_decrypt(int blocks, uint64_t dg[2], uint8_t dst[],
const uint8_t src[], const uint64_t k[2],
uint64_t ctr[], int rounds);

uint32_t pmull_gcm_aes_sub(uint32_t input);

void pmull_gcm_encrypt_block(uint8_t dst[], const uint8_t src[], int rounds);

#endif /*__GHASH_CE_CORE_H*/
Loading