diff mbox

[PATCHv3] linux-generic crypto

Message ID 1402065340-18443-1-git-send-email-robking@cisco.com
State New
Headers show

Commit Message

Robbie King June 6, 2014, 2:35 p.m. UTC
Several functional fixes for issues found when adding standalone
mode of operation.  More changes to come post sprint, so please
do not consider these ready for GIT.  Just want to get these out
to anyone working with the patches.

Note that due to crypto library calls we now have four camel case
warnings.  Using the crypto library directly allows us to verify
HW crypto functionallity.
---
 include/odp_crypto.h                               | 295 +++++++++++++
 platform/linux-generic/Makefile                    |   1 +
 .../linux-generic/include/odp_crypto_internal.h    |  86 ++++
 platform/linux-generic/source/odp_crypto.c         | 459 +++++++++++++++++++++
 4 files changed, 841 insertions(+)
 create mode 100644 include/odp_crypto.h
 create mode 100644 platform/linux-generic/include/odp_crypto_internal.h
 create mode 100644 platform/linux-generic/source/odp_crypto.c
diff mbox

Patch

diff --git a/include/odp_crypto.h b/include/odp_crypto.h
new file mode 100644
index 0000000..725e8f1
--- /dev/null
+++ b/include/odp_crypto.h
@@ -0,0 +1,295 @@ 
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+
+/**
+ * @file
+ *
+ * ODP crypto
+ */
+
+#ifndef ODP_CRYPTO_H_
+#define ODP_CRYPTO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_std_types.h>
+#include <odp_buffer.h>
+#include <odp_buffer_pool.h>
+#include <odp_queue.h>
+#include <odp_packet.h>
+
+/** Invalid session handle */
+#define ODP_CRYPTO_SESSION_INVALID (-1ULL)
+
+/**
+ * Crypto API opaque session handle
+ */
+typedef uint64_t odp_crypto_session_t;
+
+/**
+ * Crypto API operation mode
+ */
+enum odp_crypto_op_mode {
+	ODP_CRYPTO_SYNC,    /**< Synchronous, return results immediately */
+	ODP_CRYPTO_ASYNC,   /**< Aynchronous, return results via posted event */
+};
+
+/**
+ * Crypto API operation type
+ */
+enum odp_crypto_op {
+	ODP_CRYPTO_OP_ENCODE, /**< Encrypt and/or compute authentication ICV */
+	ODP_CRYPTO_OP_DECODE  /**< Decrypt and/or verify authentication ICV */
+};
+
+/**
+ * Crypto API cipher algorithm
+ */
+enum  odp_cipher_alg {
+	ODP_CIPHER_ALG_NULL,     /**< No cipher algorithm specified */
+	ODP_CIPHER_ALG_DES,      /**< DES */
+	ODP_CIPHER_ALG_3DES_CBC, /**< Triple DES with cipher block chaining */
+};
+
+/**
+ * Crypto API authentication algorithm
+ */
+enum odp_auth_alg {
+	ODP_AUTH_ALG_NULL,   /**< No authentication algorithm specified */
+	ODP_AUTH_ALG_MD5_96, /**< HMAC-MD5 with 96 bit key */
+};
+
+/**
+ * Crypto API operation order
+ */
+enum odp_crypto_combination {
+	ODP_CRYPTO_CIPHER_ONLY,     /**< Only perform cipher */
+	ODP_CRYPTO_AUTH_ONLY,       /**< Only perform authentication */
+	ODP_CRYPTO_AUTH_CIPHERTEXT  /**< Cipher then authentication on encode */
+};
+
+/**
+ * Crypto API key
+ */
+typedef struct odp_key_s {
+	union  {
+		/** DES/3DES key definition (set all same for DES) */
+		struct {
+			uint8_t k1[8]; /**< First key */
+			uint8_t k2[8]; /**< Second key */
+			uint8_t k3[8]; /**< Third key */
+		} des;
+		/** MD5 key */
+		struct {
+			uint8_t key[16];  /**< Key up to 128 bits */
+		} md5;
+	};
+} odp_key_t;
+
+/**
+ * Crypto API data range specifier
+ */
+struct odp_data_range {
+	uint16_t offset;  /**< Offset from beginning of buffer (chain) */
+	uint16_t length;  /**< Length of data to operate on */
+};
+
+/**
+ * Crypto API session creation paramters
+ *
+ * TODO: add "odp_session_proc_info_t"
+ */
+struct odp_crypto_session_params {
+	enum odp_crypto_op op;             /**< Encode versus decode */
+	enum odp_crypto_combination comb;  /**< Operation order */
+	enum odp_crypto_op_mode pref_mode; /**< Preferred sync vs async */
+	enum odp_cipher_alg cipher_alg;    /**< Cipher algorithm */
+	odp_key_t *cipher_key;             /**< Cipher key */
+	uint8_t *iv;                   /**< Cipher Initialization Vector (IV) */
+	size_t iv_len;                 /**< Cipher IV length */
+	enum odp_auth_alg auth_alg;    /**< Authentication algorithm */
+	odp_key_t *auth_key;           /**< Authentication key */
+	odp_queue_t compl_queue;       /**< Async mode completion event queue */
+};
+
+/**
+ * Crypto API per packet operation parameters
+ */
+struct odp_crypto_op_params {
+	odp_crypto_session_t session;   /**< Session handle from creation */
+	odp_packet_t pkt;               /**< Input packet buffer */
+	odp_packet_t out_pkt;           /**< Output packet buffer (optional) */
+	uint8_t *override_iv_ptr;       /**< Override session IV pointer */
+	unsigned hash_result_offset;    /**< Offset from start of packet buffer for hash result */
+	struct odp_data_range cipher_range;   /**< Data range to apply cipher */
+	struct odp_data_range auth_range;     /**< Data range to authenticate */
+};
+
+/**
+ * Crypto API session creation return code
+ *
+ * TODO: seems confusing, maybe _rc instead
+ */
+enum odp_crypto_ses_create_err {
+	ODP_CRYPTO_SES_CREATE_NONE,  /**< No session created? need to clarify */
+	ODP_CRYPTO_SES_CREATE_OK,    /**< Session created successfully */
+};
+
+/**
+ * Crypto API algorithm return code
+ */
+enum crypto_alg_err {
+	ODP_CRYPTO_ALG_ERR_NONE,      /**< Algorithm successful */
+	ODP_CRYPTO_ALG_ERR_DATA_SIZE, /**< Invalid data block size */
+	ODP_CRYPTO_ALG_ERR_KEY_SIZE,  /**< Key size invalid for algorithm */
+	ODP_CRYPTO_ALG_ERR_ICV_CHECK, /**< Computed ICV value mismatch */
+};
+
+/**
+ * Crypto API operation return code
+ */
+typedef enum odp_crypto_rc {
+	ODP_CRYPTO_OP_OK,      /**< Operation completed, results are valid */
+	ODP_CRYPTO_OP_POSTED,  /**< Operation was posted, results delivered via completion queue */
+	ODP_CRYPTO_OP_ERROR,   /**< Operation failed */
+} odp_crypto_rc_e;
+
+/**
+ * Crypto API hardware centric return code
+ */
+enum crypto_hw_err {
+	ODP_CRYPTO_HW_ERR_NONE,         /**< Operation completed successfully */
+	ODP_CRYPTO_HW_ERR_DMA,          /**< Error detected during DMA of data */
+	ODP_CRYPTO_HW_ERR_BP_DEPLETED,  /**< Operation failed due to buffer pool depletion */
+};
+
+/**
+ * Crypto API algorithm (cipher or authentication)
+ */
+typedef union odp_crypto_alg_u {
+	enum odp_cipher_alg cipher;   /**< Cipher algorithm */
+	enum odp_auth_alg   auth;     /**< Authentication algorithm */
+} odp_crypto_alg_t;
+
+/**
+ * Cryto API per packet operation completion status
+ */
+struct odp_crypto_compl_status {
+	odp_crypto_alg_t    alg;      /**< Requested algorithm */
+	enum crypto_alg_err alg_err;  /**< Algorithm specific return code */
+	enum crypto_hw_err  hw_err;   /**< Hardware specific return code */
+};
+
+
+/**
+ * Crypto session creation
+ *
+ * Create a crypto session.  Operation occurs asynchronously if a completion
+ * queue is specified else synchronously.
+ *
+ * @param params            Session parameters
+ * @param completion_event  Event by which the session creation results are
+ *                          delivered.
+ * @param completion_queue  Queue by which the completion event will be
+ *                          delivered.  Ignored if ODP_QUEUE_INVALID.
+ *
+ * @return Operation return code indicating success or failure for
+ *         when synchronous operation requested, else POSTED when
+ *         asynchronous operation is requested.
+ */
+odp_crypto_rc_e
+odp_crypto_session_create(struct odp_crypto_session_params *params,
+			  odp_buffer_t completion_event,
+			  odp_queue_t completion_queue);
+
+
+/**
+ * Crypto session creation completion status
+ *
+ * Accessor function for obtaining creation status from the completion event.
+ *
+ * @param completion_event  Event containing operation results
+ * @param status            Pointer to store creation return code
+ */
+void
+odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event,
+				       enum odp_crypto_ses_create_err *status);
+
+/**
+ * Crypto session creation completion return value
+ *
+ * Accessor function for obtaining handle for newly created session.
+ *
+ * @param completion_event  Event containing operation results
+ * @param session           Pointer to store session handle
+ */
+void
+odp_crypto_get_ses_create_compl_session(odp_buffer_t completion_event,
+					odp_crypto_session_t *session);
+
+/**
+ * Crypto per packet operation
+ *
+ * Performs the cryptographic operations specified during session creation
+ * on the packet.
+ *
+ * @param params            Operation parameters
+ * @param completion_event  Event by which the session creation results are
+ *                          delivered.
+ *
+ * @return Operation return code indicating success or failure when session
+ *         indicates synchronous operation, else POSTED for asynchronous
+ *         operation.
+ */
+odp_crypto_rc_e
+odp_crypto_operation(struct odp_crypto_op_params *params,
+		     odp_buffer_t completion_event);
+
+
+/**
+ * Crypto per packet operation completion status
+ *
+ * Accessor function for obtaining operation status from the completion event.
+ *
+ * @param completion_event  Event containing operation results
+ * @param auth              Pointer to store authentication results
+ * @param cipher            Pointer to store cipher results
+ */
+void
+odp_crypto_get_operation_compl_status(odp_buffer_t completion_event,
+				      struct odp_crypto_compl_status *auth,
+				      struct odp_crypto_compl_status *cipher);
+
+/**
+ * Generate random byte string
+ *
+ * @param buf          Pointer to store result
+ * @param len          Pointer to input length value as well as return value
+ * @param use_entropy  (TODO: needs description)
+ *
+ * @return 0 if succesful
+ */
+int
+odp_hw_random_get(uint8_t *buf, size_t *len, bool use_entropy);
+
+/**
+ * Initialize the crypto subsystem, called once from main thread
+ *
+ * @param max_sessions  Maximum number of sessions to support
+ *
+ * @return 0 if succesful
+ */
+int
+odp_crypto_init(uint32_t max_sessions);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/Makefile b/platform/linux-generic/Makefile
index ec5d4a7..57f6d18 100644
--- a/platform/linux-generic/Makefile
+++ b/platform/linux-generic/Makefile
@@ -72,6 +72,7 @@  OBJS    += $(OBJ_DIR)/odp_time.o
 OBJS    += $(OBJ_DIR)/odp_timer.o
 OBJS    += $(OBJ_DIR)/odp_ring.o
 OBJS    += $(OBJ_DIR)/odp_rwlock.o
+OBJS    += $(OBJ_DIR)/odp_crypto.o
 ifeq ($(ODP_HAVE_NETMAP),yes)
 OBJS    += $(OBJ_DIR)/odp_packet_netmap.o
 endif
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..e558864
--- /dev/null
+++ b/platform/linux-generic/include/odp_crypto_internal.h
@@ -0,0 +1,86 @@ 
+/* Copyright (c) 2013, 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 */
+struct odp_crypto_session_s;
+
+/**
+ * Algorithm handler function prototype
+ */
+typedef
+enum crypto_alg_err (*crypto_func_t)(struct odp_crypto_op_params *params,
+				     struct odp_crypto_session_s *session);
+
+/**
+ * Per crypto session data structure
+ */
+struct odp_crypto_session_s {
+	uint32_t index;
+	enum odp_crypto_op op;
+	enum odp_crypto_combination comb;
+	odp_queue_t compl_queue;
+	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];
+			} md5;
+		} data;
+		crypto_func_t func;
+	} auth;
+
+};
+
+/**
+ * Per packet operation result
+ */
+struct odp_operation_result_s {
+	uint32_t magic;
+	struct odp_crypto_compl_status cipher;
+	struct odp_crypto_compl_status auth;
+};
+
+/**
+ * Per session creation operation result
+ */
+struct odp_session_result_s {
+	enum odp_crypto_ses_create_err rc;
+	odp_crypto_session_t           session;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/source/odp_crypto.c b/platform/linux-generic/source/odp_crypto.c
new file mode 100644
index 0000000..8040e7b
--- /dev/null
+++ b/platform/linux-generic/source/odp_crypto.c
@@ -0,0 +1,459 @@ 
+/* Copyright (c) 2013, 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 <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;
+	struct odp_crypto_session_s 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.
+ */
+static
+struct odp_operation_result_s *get_op_result_from_buffer(odp_buffer_t buf)
+{
+	uint8_t   *temp;
+	struct odp_operation_result_s *result;
+
+	temp  = odp_buffer_addr(buf);
+	temp += odp_buffer_size(buf);
+	temp -= sizeof(*result);
+	result = (struct odp_operation_result_s *)(void *)temp;
+	return result;
+}
+
+static
+struct odp_crypto_session_s *alloc_session(void)
+{
+	uint32_t idx;
+	struct odp_crypto_session_s *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(
+	struct odp_crypto_op_params *params ODP_UNUSED,
+	struct odp_crypto_session_s *session ODP_UNUSED)
+{
+	return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static
+enum crypto_alg_err md5_gen(struct odp_crypto_op_params *params,
+			    struct odp_crypto_session_s *session)
+{
+	uint8_t *data  = odp_packet_buf_addr(params->pkt);
+	uint8_t *icv   = data;
+	uint32_t len   = params->auth_range.length;
+	uint8_t  hash[EVP_MAX_MD_SIZE];
+	uint32_t hlen = 12;
+
+	/* 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,
+	     &hlen);
+
+	/* Copy to the output location */
+	memcpy(icv, hash, 12);
+
+	return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+
+static
+enum crypto_alg_err md5_check(struct odp_crypto_op_params *params,
+			      struct odp_crypto_session_s *session)
+{
+	uint8_t *data  = odp_packet_buf_addr(params->pkt);
+	uint8_t *icv   = data;
+	uint32_t len   = params->auth_range.length;
+	uint8_t  hash_in[EVP_MAX_MD_SIZE];
+	uint8_t  hash_out[EVP_MAX_MD_SIZE];
+	uint32_t hlen = 12;
+
+	/* 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, hlen);
+	memset(icv, 0, hlen);
+	memset(hash_out, 0, sizeof(hash_out));
+
+	/* Hash it */
+	HMAC(EVP_md5(),
+	     session->auth.data.md5.key,
+	     16,
+	     data,
+	     len,
+	     hash_out,
+	     &hlen);
+
+	/* Verify match */
+	if (0 != memcmp(hash_in, hash_out, 12))
+		return ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+
+	/* Matched */
+	return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static
+enum crypto_alg_err des_encrypt(struct odp_crypto_op_params *params,
+				struct odp_crypto_session_s *session)
+{
+	uint8_t *data  = odp_packet_buf_addr(params->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(struct odp_crypto_op_params *params,
+				struct odp_crypto_session_s *session)
+{
+	uint8_t *data  = odp_packet_buf_addr(params->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(struct odp_crypto_session_s *session,
+		       struct odp_crypto_session_params *params)
+{
+	/* Verify IV len is either 0 or 8 */
+	if (!((0 == params->iv_len) || (8 == params->iv_len)))
+		return -1;
+
+	/* Verify IV pointer */
+	if (params->iv_len && !params->iv)
+		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(&params->cipher_key->des.k1, &session->cipher.data.des.ks1);
+	DES_set_key(&params->cipher_key->des.k2, &session->cipher.data.des.ks2);
+	DES_set_key(&params->cipher_key->des.k3, &session->cipher.data.des.ks3);
+
+	return 0;
+}
+
+static
+int process_md5_params(struct odp_crypto_session_s *session,
+		       struct odp_crypto_session_params *params)
+{
+	/* Set function */
+	if (ODP_CRYPTO_OP_ENCODE == params->op)
+		session->auth.func = md5_gen;
+	else
+		session->auth.func = md5_check;
+
+	/* Convert keys */
+	memcpy(session->auth.data.md5.key, params->auth_key->md5.key, 16);
+
+	return 0;
+}
+
+odp_crypto_rc_e
+odp_crypto_session_create(struct odp_crypto_session_params *params,
+			  odp_buffer_t completion_event,
+			  odp_queue_t completion_queue)
+{
+	int rc;
+	struct odp_crypto_session_s *session;
+	struct odp_session_result_s *result = odp_buffer_addr(completion_event);
+
+	/* Default to failure result */
+	result->rc = ODP_CRYPTO_SES_CREATE_NONE;
+	result->session = ODP_CRYPTO_SESSION_INVALID;
+
+	/* Allocate memory for this session */
+	session = alloc_session();
+	if (NULL == session)
+		return ODP_CRYPTO_OP_ERROR;
+
+	/* Copy stuff over */
+	session->op          = params->op;
+	session->comb        = params->comb;
+	session->compl_queue = params->compl_queue;
+	session->cipher.alg  = params->cipher_alg;
+	session->cipher.iv.data = params->iv;
+	session->cipher.iv.len  = params->iv_len;
+	session->auth.alg  = params->auth_alg;
+
+	/* 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)
+		return ODP_CRYPTO_OP_ERROR;
+
+	/* 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);
+		break;
+	default:
+		rc = -1;
+	}
+
+	/* Check result */
+	if (rc)
+		return ODP_CRYPTO_OP_ERROR;
+
+	/* We're happy */
+	result->rc = ODP_CRYPTO_SES_CREATE_OK;
+	result->session = (intptr_t)session;
+
+	/* If there is a queue post else we're good */
+	if (ODP_QUEUE_INVALID != completion_queue) {
+		odp_queue_enq(completion_queue, completion_event);
+		return ODP_CRYPTO_OP_POSTED;
+	}
+
+	return ODP_CRYPTO_OP_OK;
+}
+
+
+odp_crypto_rc_e
+odp_crypto_operation(struct odp_crypto_op_params *params,
+		     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;
+	struct odp_crypto_session_s *session;
+	struct odp_operation_result_s *result;
+
+	session = (struct odp_crypto_session_s *)(intptr_t)params->session;
+
+	/*
+	 * robking: need to understand infrastructure for scattered packets
+	 *          for now just don't support them
+	 */
+	if (odp_buffer_is_scatter(odp_buffer_from_packet(params->pkt)))
+		return ODP_CRYPTO_OP_ERROR;
+
+	/*
+	 * robking: for now we are only going to support in place
+	 */
+	if (params->pkt != params->out_pkt)
+		return ODP_CRYPTO_OP_ERROR;
+
+	/* Invoke the functions */
+	switch (session->comb) {
+	case ODP_CRYPTO_CIPHER_ONLY:
+		rc_cipher = session->cipher.func(params, session);
+		break;
+	case ODP_CRYPTO_AUTH_ONLY:
+		rc_auth = session->auth.func(params, session);
+		break;
+	case ODP_CRYPTO_AUTH_CIPHERTEXT:
+		if (ODP_CRYPTO_OP_ENCODE == session->op) {
+			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);
+		}
+		break;
+	}
+
+	/* Build Result (no HW so no errors) */
+	result = get_op_result_from_buffer(completion_event);
+	result->magic = OP_RESULT_MAGIC;
+	result->cipher.alg.cipher = session->cipher.alg;
+	result->cipher.alg_err = rc_cipher;
+	result->cipher.hw_err = ODP_CRYPTO_HW_ERR_NONE;
+	result->auth.alg.auth = session->auth.alg;
+	result->auth.alg_err = rc_auth;
+	result->auth.hw_err = ODP_CRYPTO_HW_ERR_NONE;
+
+	/*
+	 * robking: a) the queue is supposed to come from session
+	 *          b) ordering question asks whether we must
+	 *             use the packet to return status
+	 */
+	if (ODP_QUEUE_INVALID != session->compl_queue) {
+		odp_queue_enq(session->compl_queue, completion_event);
+		return ODP_CRYPTO_OP_POSTED;
+	}
+
+	return ODP_CRYPTO_OP_OK;
+}
+
+
+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(struct odp_crypto_session_s));
+
+	/* 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,
+				      struct odp_crypto_compl_status *auth,
+				      struct odp_crypto_compl_status *cipher)
+{
+	struct odp_operation_result_s *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)
+{
+	struct odp_session_result_s *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)
+{
+	struct odp_session_result_s *result;
+
+	result = odp_buffer_addr(completion_event);
+	*session = result->session;
+}