On 2014-08-11 14:23, Robbie King wrote: > Signed-off-by: Robbie King <[email protected]>
Reviewed-by: Anders Roxell <[email protected]> > --- > platform/linux-generic/Makefile.am | 2 + > .../linux-generic/include/odp_crypto_internal.h | 86 ++++ > platform/linux-generic/odp_crypto.c | 469 > ++++++++++++++++++++ > 3 files changed, 557 insertions(+), 0 deletions(-) > create mode 100644 platform/linux-generic/include/odp_crypto_internal.h > create mode 100644 platform/linux-generic/odp_crypto.c > > diff --git a/platform/linux-generic/Makefile.am > b/platform/linux-generic/Makefile.am > index 41458d8..e4087c7 100644 > --- a/platform/linux-generic/Makefile.am > +++ b/platform/linux-generic/Makefile.am > @@ -16,6 +16,7 @@ include_HEADERS = \ > $(top_srcdir)/include/odp_compiler.h \ > $(top_srcdir)/include/odp_config.h \ > $(top_srcdir)/include/odp_coremask.h \ > + $(top_srcdir)/include/odp_crypto.h \ > $(top_srcdir)/include/odp_debug.h \ > $(top_srcdir)/include/odp_hints.h \ > $(top_srcdir)/include/odp_init.h \ > @@ -54,6 +55,7 @@ __LIB__libodp_la_SOURCES = \ > odp_buffer.c \ > odp_buffer_pool.c \ > odp_coremask.c \ > + odp_crypto.c \ > odp_init.c \ > odp_linux.c \ > odp_packet.c \ > diff --git a/platform/linux-generic/include/odp_crypto_internal.h > b/platform/linux-generic/include/odp_crypto_internal.h > new file mode 100644 > index 0000000..04db333 > --- /dev/null > +++ b/platform/linux-generic/include/odp_crypto_internal.h > @@ -0,0 +1,86 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#ifndef ODP_CRYPTO_INTERNAL_H_ > +#define ODP_CRYPTO_INTERNAL_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include <openssl/des.h> > + > +#define OP_RESULT_MAGIC 0x91919191 > + > +/** Forward declaration of session structure */ > +typedef struct odp_crypto_generic_session odp_crypto_generic_session_t; > + > +/** > + * Algorithm handler function prototype > + */ > +typedef > +enum crypto_alg_err (*crypto_func_t)(odp_crypto_op_params_t *params, > + odp_crypto_generic_session_t *session); > + > +/** > + * Per crypto session data structure > + */ > +struct odp_crypto_generic_session { > + uint32_t index; > + enum odp_crypto_op op; > + bool do_cipher_first; > + odp_queue_t compl_queue; > + odp_buffer_pool_t output_pool; > + struct { > + enum odp_cipher_alg alg; > + struct { > + uint8_t *data; > + size_t len; > + } iv; > + union { > + struct { > + DES_key_schedule ks1; > + DES_key_schedule ks2; > + DES_key_schedule ks3; > + } des; > + } data; > + crypto_func_t func; > + } cipher; > + struct { > + enum odp_auth_alg alg; > + union { > + struct { > + uint8_t key[16]; > + uint32_t bytes; > + } md5; > + } data; > + crypto_func_t func; > + } auth; > + > +}; > + > +/** > + * Per packet operation result > + */ > +typedef struct odp_crypto_generic_op_result { > + uint32_t magic; > + odp_crypto_compl_status_t cipher; > + odp_crypto_compl_status_t auth; > +} odp_crypto_generic_op_result_t; > + > +/** > + * Per session creation operation result > + */ > +typedef struct odp_crypto_generic_session_result { > + enum odp_crypto_ses_create_err rc; > + odp_crypto_session_t session; > +} odp_crypto_generic_session_result_t; > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif > diff --git a/platform/linux-generic/odp_crypto.c > b/platform/linux-generic/odp_crypto.c > new file mode 100644 > index 0000000..7d5a23b > --- /dev/null > +++ b/platform/linux-generic/odp_crypto.c > @@ -0,0 +1,469 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#include <odp_crypto.h> > +#include <odp_internal.h> > +#include <odp_atomic.h> > +#include <odp_spinlock.h> > +#include <odp_sync.h> > +#include <odp_debug.h> > +#include <odp_align.h> > +#include <odp_shared_memory.h> > +#include <odp_crypto_internal.h> > +#include <odp_hints.h> > +#include <helper/odp_packet_helper.h> > + > +#include <string.h> > + > +#include <openssl/des.h> > +#include <openssl/rand.h> > +#include <openssl/hmac.h> > +#include <openssl/evp.h> > + > +#define MAX_SESSIONS 32 > + > +typedef struct { > + odp_atomic_u32_t next; > + uint32_t max; > + odp_crypto_generic_session_t sessions[0]; > +} odp_crypto_global_t; > + > +static odp_crypto_global_t *global; > + > +/* > + * @todo This is a serious hack to allow us to use packet buffer to convey > + * crypto operation results by placing them at the very end of the > + * packet buffer. The issue should be resolved shortly once the issue > + * of packets versus events on completion queues is closed. > + */ > +static > +odp_crypto_generic_op_result_t *get_op_result_from_buffer(odp_buffer_t buf) > +{ > + uint8_t *temp; > + odp_crypto_generic_op_result_t *result; > + > + temp = odp_buffer_addr(buf); > + temp += odp_buffer_size(buf); > + temp -= sizeof(*result); > + result = (odp_crypto_generic_op_result_t *)(void *)temp; > + return result; > +} > + > +static > +odp_crypto_generic_session_t *alloc_session(void) > +{ > + uint32_t idx; > + odp_crypto_generic_session_t *session = NULL; > + > + idx = odp_atomic_fetch_inc_u32(&global->next); > + if (idx < global->max) { > + session = &global->sessions[idx]; > + session->index = idx; > + } > + return session; > +} > + > +static > +enum crypto_alg_err null_crypto_routine( > + odp_crypto_op_params_t *params ODP_UNUSED, > + odp_crypto_generic_session_t *session ODP_UNUSED) > +{ > + return ODP_CRYPTO_ALG_ERR_NONE; > +} > + > +static > +enum crypto_alg_err md5_gen(odp_crypto_op_params_t *params, > + odp_crypto_generic_session_t *session) > +{ > + uint8_t *data = odp_packet_buf_addr(params->out_pkt); > + uint8_t *icv = data; > + uint32_t len = params->auth_range.length; > + uint8_t hash[EVP_MAX_MD_SIZE]; > + > + /* Adjust pointer for beginning of area to auth */ > + data += params->auth_range.offset; > + icv += params->hash_result_offset; > + > + /* Hash it */ > + HMAC(EVP_md5(), > + session->auth.data.md5.key, > + 16, > + data, > + len, > + hash, > + NULL); > + > + /* Copy to the output location */ > + memcpy(icv, hash, session->auth.data.md5.bytes); > + > + return ODP_CRYPTO_ALG_ERR_NONE; > +} > + > +static > +enum crypto_alg_err md5_check(odp_crypto_op_params_t *params, > + odp_crypto_generic_session_t *session) > +{ > + uint8_t *data = odp_packet_buf_addr(params->out_pkt); > + uint8_t *icv = data; > + uint32_t len = params->auth_range.length; > + uint32_t bytes = session->auth.data.md5.bytes; > + uint8_t hash_in[EVP_MAX_MD_SIZE]; > + uint8_t hash_out[EVP_MAX_MD_SIZE]; > + > + /* Adjust pointer for beginning of area to auth */ > + data += params->auth_range.offset; > + icv += params->hash_result_offset; > + > + /* Copy current value out and clear it before authentication */ > + memset(hash_in, 0, sizeof(hash_in)); > + memcpy(hash_in, icv, bytes); > + memset(icv, 0, bytes); > + memset(hash_out, 0, sizeof(hash_out)); > + > + /* Hash it */ > + HMAC(EVP_md5(), > + session->auth.data.md5.key, > + 16, > + data, > + len, > + hash_out, > + NULL); > + > + /* Verify match */ > + if (0 != memcmp(hash_in, hash_out, bytes)) > + return ODP_CRYPTO_ALG_ERR_ICV_CHECK; > + > + /* Matched */ > + return ODP_CRYPTO_ALG_ERR_NONE; > +} > + > +static > +enum crypto_alg_err des_encrypt(odp_crypto_op_params_t *params, > + odp_crypto_generic_session_t *session) > +{ > + uint8_t *data = odp_packet_buf_addr(params->out_pkt); > + uint32_t len = params->cipher_range.length; > + DES_cblock *iv; > + DES_cblock iv_temp; > + > + /* > + * Create a copy of the IV. The DES library modifies IV > + * and if we are processing packets on parallel threads > + * we could get corruption. > + */ > + memcpy(iv_temp, session->cipher.iv.data, sizeof(iv_temp)); > + iv = &iv_temp; > + > + /* Adjust pointer for beginning of area to cipher */ > + data += params->cipher_range.offset; > + > + /* Override IV if requested */ > + if (params->override_iv_ptr) > + iv = (DES_cblock *)params->override_iv_ptr; > + > + /* Encrypt it */ > + DES_ede3_cbc_encrypt(data, > + data, > + len, > + &session->cipher.data.des.ks1, > + &session->cipher.data.des.ks2, > + &session->cipher.data.des.ks3, > + iv, > + 1); > + > + return ODP_CRYPTO_ALG_ERR_NONE; > +} > + > +static > +enum crypto_alg_err des_decrypt(odp_crypto_op_params_t *params, > + odp_crypto_generic_session_t *session) > +{ > + uint8_t *data = odp_packet_buf_addr(params->out_pkt); > + uint32_t len = params->cipher_range.length; > + DES_cblock *iv = (DES_cblock *)session->cipher.iv.data; > + > + /* Adjust pointer for beginning of area to cipher */ > + data += params->cipher_range.offset; > + > + /* Override IV if requested */ > + if (params->override_iv_ptr) > + iv = (DES_cblock *)params->override_iv_ptr; > + > + /* Decrypt it */ > + DES_ede3_cbc_encrypt(data, > + data, > + len, > + &session->cipher.data.des.ks1, > + &session->cipher.data.des.ks2, > + &session->cipher.data.des.ks3, > + iv, > + 0); > + > + return ODP_CRYPTO_ALG_ERR_NONE; > +} > + > +static > +int process_des_params(odp_crypto_generic_session_t *session, > + odp_crypto_session_params_t *params) > +{ > + /* Verify IV len is either 0 or 8 */ > + if (!((0 == params->iv.length) || (8 == params->iv.length))) > + return -1; > + > + /* Verify IV pointer */ > + if (params->iv.length && !params->iv.data) > + return -1; > + > + /* Set function */ > + if (ODP_CRYPTO_OP_ENCODE == params->op) > + session->cipher.func = des_encrypt; > + else > + session->cipher.func = des_decrypt; > + > + /* Convert keys */ > + DES_set_key((DES_cblock *)¶ms->cipher_key.data[0], > + &session->cipher.data.des.ks1); > + DES_set_key((DES_cblock *)¶ms->cipher_key.data[8], > + &session->cipher.data.des.ks2); > + DES_set_key((DES_cblock *)¶ms->cipher_key.data[16], > + &session->cipher.data.des.ks3); > + > + return 0; > +} > + > +static > +int process_md5_params(odp_crypto_generic_session_t *session, > + odp_crypto_session_params_t *params, > + uint32_t bits) > +{ > + /* Set function */ > + if (ODP_CRYPTO_OP_ENCODE == params->op) > + session->auth.func = md5_gen; > + else > + session->auth.func = md5_check; > + > + /* Number of valid bytes */ > + session->auth.data.md5.bytes = bits / 8; > + > + /* Convert keys */ > + memcpy(session->auth.data.md5.key, params->auth_key.data, 16); > + > + return 0; > +} > + > +int > +odp_crypto_session_create(odp_crypto_session_params_t *params, > + odp_crypto_session_t *session_out, > + enum odp_crypto_ses_create_err *status) > +{ > + int rc; > + odp_crypto_generic_session_t *session; > + > + /* Default to successful result */ > + *status = ODP_CRYPTO_SES_CREATE_ERR_NONE; > + > + /* Allocate memory for this session */ > + session = alloc_session(); > + if (NULL == session) { > + *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM; > + return -1; > + } > + > + /* Derive order */ > + if (ODP_CRYPTO_OP_ENCODE == params->op) > + session->do_cipher_first = params->auth_cipher_text; > + else > + session->do_cipher_first = !params->auth_cipher_text; > + > + /* Copy stuff over */ > + session->op = params->op; > + session->compl_queue = params->compl_queue; > + session->cipher.alg = params->cipher_alg; > + session->cipher.iv.data = params->iv.data; > + session->cipher.iv.len = params->iv.length; > + session->auth.alg = params->auth_alg; > + session->output_pool = params->output_pool; > + > + /* Process based on cipher */ > + switch (params->cipher_alg) { > + case ODP_CIPHER_ALG_NULL: > + session->cipher.func = null_crypto_routine; > + rc = 0; > + break; > + case ODP_CIPHER_ALG_DES: > + case ODP_CIPHER_ALG_3DES_CBC: > + rc = process_des_params(session, params); > + break; > + default: > + rc = -1; > + } > + > + /* Check result */ > + if (rc) { > + *status = ODP_CRYPTO_SES_CREATE_ERR_INV_CIPHER; > + return -1; > + } > + > + /* Process based on auth */ > + switch (params->auth_alg) { > + case ODP_AUTH_ALG_NULL: > + session->auth.func = null_crypto_routine; > + rc = 0; > + break; > + case ODP_AUTH_ALG_MD5_96: > + rc = process_md5_params(session, params, 96); > + break; > + default: > + rc = -1; > + } > + > + /* Check result */ > + if (rc) { > + *status = ODP_CRYPTO_SES_CREATE_ERR_INV_AUTH; > + return -1; > + } > + > + /* We're happy */ > + *session_out = (intptr_t)session; > + return 0; > +} > + > +int > +odp_crypto_session_create_async(odp_crypto_session_params_t *params, > + odp_buffer_t completion_event, > + odp_queue_t completion_queue) > +{ > + odp_crypto_generic_session_result_t *result; > + > + result = odp_buffer_addr(completion_event); > + if (odp_crypto_session_create(params, &result->session, &result->rc)) > + return -1; > + odp_queue_enq(completion_queue, completion_event); > + return 0; > +} > + > +int > +odp_crypto_operation(odp_crypto_op_params_t *params, > + bool *posted, > + odp_buffer_t completion_event) > +{ > + enum crypto_alg_err rc_cipher = ODP_CRYPTO_ALG_ERR_NONE; > + enum crypto_alg_err rc_auth = ODP_CRYPTO_ALG_ERR_NONE; > + odp_crypto_generic_session_t *session; > + odp_crypto_generic_op_result_t *result; > + > + *posted = 0; > + session = (odp_crypto_generic_session_t *)(intptr_t)params->session; > + > + /* Resolve output buffer */ > + if (ODP_PACKET_INVALID == params->out_pkt) > + if (ODP_BUFFER_POOL_INVALID != session->output_pool) > + params->out_pkt = > + odp_buffer_alloc(session->output_pool); > + if (params->pkt != params->out_pkt) { > + if (odp_unlikely(ODP_PACKET_INVALID == params->out_pkt)) > + abort(); > + odp_packet_copy(params->out_pkt, params->pkt); > + if (completion_event == odp_buffer_from_packet(params->pkt)) > + completion_event = > + odp_buffer_from_packet(params->out_pkt); > + odp_packet_free(params->pkt); > + params->pkt = ODP_PACKET_INVALID; > + } > + > + /* Invoke the functions */ > + if (session->do_cipher_first) { > + rc_cipher = session->cipher.func(params, session); > + rc_auth = session->auth.func(params, session); > + } else { > + rc_auth = session->auth.func(params, session); > + rc_cipher = session->cipher.func(params, session); > + } > + > + /* Build Result (no HW so no errors) */ > + result = get_op_result_from_buffer(completion_event); > + result->magic = OP_RESULT_MAGIC; > + result->cipher.alg_err = rc_cipher; > + result->cipher.hw_err = ODP_CRYPTO_HW_ERR_NONE; > + result->auth.alg_err = rc_auth; > + result->auth.hw_err = ODP_CRYPTO_HW_ERR_NONE; > + > + /* If specified during creation post event to completion queue */ > + if (ODP_QUEUE_INVALID != session->compl_queue) { > + odp_queue_enq(session->compl_queue, completion_event); > + *posted = 1; > + } > + return 0; > +} > + > +int > +odp_crypto_init(uint32_t max_sessions) > +{ > + size_t mem_size; > + > + /* Force down to our limit */ > + if (MAX_SESSIONS < max_sessions) > + max_sessions = MAX_SESSIONS; > + > + /* Calculate the memory size we need */ > + mem_size = sizeof(*global); > + mem_size += (max_sessions * sizeof(odp_crypto_generic_session_t)); > + > + /* Allocate our globally shared memory */ > + global = odp_shm_reserve("crypto_pool", mem_size, ODP_CACHE_LINE_SIZE); > + > + /* Clear it out */ > + memset(global, 0, mem_size); > + > + /* Initialize it */ > + global->max = max_sessions; > + > + return 0; > +} > + > +int > +odp_hw_random_get(uint8_t *buf, size_t *len, bool use_entropy ODP_UNUSED) > +{ > + int rc; > + rc = RAND_bytes(buf, *len); > + return ((1 == rc) ? 0 : -1); > +} > + > +void > +odp_crypto_get_operation_compl_status(odp_buffer_t completion_event, > + odp_crypto_compl_status_t *auth, > + odp_crypto_compl_status_t *cipher) > +{ > + odp_crypto_generic_op_result_t *result; > + > + result = get_op_result_from_buffer(completion_event); > + > + if (OP_RESULT_MAGIC != result->magic) > + abort(); > + > + memcpy(auth, &result->auth, sizeof(*auth)); > + memcpy(cipher, &result->cipher, sizeof(*cipher)); > +} > + > +void > +odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, > + enum odp_crypto_ses_create_err *status) > +{ > + odp_crypto_generic_session_result_t *result; > + > + result = odp_buffer_addr(completion_event); > + *status = result->rc; > +} > + > +void > +odp_crypto_get_ses_create_compl_session(odp_buffer_t completion_event, > + odp_crypto_session_t *session) > +{ > + odp_crypto_generic_session_result_t *result; > + > + result = odp_buffer_addr(completion_event); > + *session = result->session; > +} > -- > 1.7.7.6 > > > _______________________________________________ > lng-odp mailing list > [email protected] > http://lists.linaro.org/mailman/listinfo/lng-odp _______________________________________________ lng-odp mailing list [email protected] http://lists.linaro.org/mailman/listinfo/lng-odp
