From patchwork Fri Jun 6 14:35:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robbie King X-Patchwork-Id: 31490 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f197.google.com (mail-vc0-f197.google.com [209.85.220.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0E0B620CAD for ; Fri, 6 Jun 2014 14:36:01 +0000 (UTC) Received: by mail-vc0-f197.google.com with SMTP id hq11sf11928014vcb.0 for ; Fri, 06 Jun 2014 07:36:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:subject :precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:mime-version:errors-to:sender :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=PpzQPs4u9+Bd3+Zl3jEIeXbDAh3XRpVqp3bP8HSasDY=; b=KDSYleKcKfFtgI6UgPPoMsTpz5RDYD3lkvWc5ZJlFMbsPIYC0ERXBHovKcc4H8y3iM V9x+1DFVuDwTjZAvIg2mX+cgyieHljPl4MNPZP7f/iZodECC9J8+l+KTJrKjonAb9Jwq Ec4JCxmysJDkucgqUps8O0r2MnisRkSTFNG5xUB5PIq3QdPlw+ejLkNpxi5AS2pV+FvD PtNDnXpbCFUvL1VcW+AcI+4PopDclgBRnU0+jXlwSRf5Lc+xVqb1MHFEZZIouYrMhyFY HtquZQn09af/qbiTZgEUBzh7LyVjyOHScSIJmrDR4WxOdItimOXQ+xBaCM3u7yeuMobx m9Xw== X-Gm-Message-State: ALoCoQmcYVEpIZja6LYXAbguOms/uUXOWGpYY2IEM3r3mP3Bxs7OaUa/VqzM7BRj839jLNjjWpwb X-Received: by 10.52.36.211 with SMTP id s19mr2856013vdj.7.1402065361802; Fri, 06 Jun 2014 07:36:01 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.23.7 with SMTP id 7ls719072qgo.60.gmail; Fri, 06 Jun 2014 07:36:01 -0700 (PDT) X-Received: by 10.220.133.197 with SMTP id g5mr5918612vct.20.1402065361598; Fri, 06 Jun 2014 07:36:01 -0700 (PDT) Received: from mail-ve0-x22d.google.com (mail-ve0-x22d.google.com [2607:f8b0:400c:c01::22d]) by mx.google.com with ESMTPS id dp9si6475624veb.24.2014.06.06.07.36.01 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 06 Jun 2014 07:36:01 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2607:f8b0:400c:c01::22d as permitted sender) client-ip=2607:f8b0:400c:c01::22d; Received: by mail-ve0-f173.google.com with SMTP id pa12so3257644veb.4 for ; Fri, 06 Jun 2014 07:36:01 -0700 (PDT) X-Received: by 10.220.53.72 with SMTP id l8mr5968086vcg.16.1402065361483; Fri, 06 Jun 2014 07:36:01 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.54.6 with SMTP id vs6csp106641vcb; Fri, 6 Jun 2014 07:36:00 -0700 (PDT) X-Received: by 10.58.30.1 with SMTP id o1mr4041382veh.37.1402065360431; Fri, 06 Jun 2014 07:36:00 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id j8si5199478vcr.60.2014.06.06.07.35.59 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 06 Jun 2014 07:36:00 -0700 (PDT) Received-SPF: none (google.com: lng-odp-bounces@lists.linaro.org does not designate permitted sender hosts) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1WsvE1-0005sz-9y; Fri, 06 Jun 2014 14:34:33 +0000 Received: from alln-iport-2.cisco.com ([173.37.142.89]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1WsvDu-0005sm-6A for lng-odp@lists.linaro.org; Fri, 06 Jun 2014 14:34:26 +0000 X-IronPort-AV: E=Sophos;i="4.98,989,1392163200"; d="scan'208";a="50859900" Received: from rcdn-core-12.cisco.com ([173.37.93.148]) by alln-iport-2.cisco.com with ESMTP; 06 Jun 2014 14:35:47 +0000 Received: from cpp-rtpbld-55.cisco.com (cpp-rtpbld-55.cisco.com [172.18.5.199]) by rcdn-core-12.cisco.com (8.14.5/8.14.5) with ESMTP id s56EZjOD007578 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 6 Jun 2014 14:35:46 GMT Received: from cpp-rtpbld-55.cisco.com (localhost.localdomain [127.0.0.1]) by cpp-rtpbld-55.cisco.com (8.13.8/8.13.8) with ESMTP id s56EZjKQ018487; Fri, 6 Jun 2014 10:35:45 -0400 Received: (from robking@localhost) by cpp-rtpbld-55.cisco.com (8.13.8/8.13.8/Submit) id s56EZjfV018486; Fri, 6 Jun 2014 10:35:45 -0400 From: Robbie King To: lng-odp@lists.linaro.org Date: Fri, 6 Jun 2014 10:35:40 -0400 Message-Id: <1402065340-18443-1-git-send-email-robking@cisco.com> X-Mailer: git-send-email 1.9.2 X-Topics: crypto patch Subject: [lng-odp] [PATCHv3] linux-generic crypto X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: lng-odp-bounces@lists.linaro.org X-Original-Sender: robking@cisco.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2607:f8b0:400c:c01::22d as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org; dkim=fail header.i=@cisco.com Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 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 --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 +#include +#include +#include +#include + +/** 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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#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(¶ms->cipher_key->des.k1, &session->cipher.data.des.ks1); + DES_set_key(¶ms->cipher_key->des.k2, &session->cipher.data.des.ks2); + DES_set_key(¶ms->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; +}