diff options
author | 2024-12-16 09:06:42 +0000 | |
---|---|---|
committer | 2024-12-18 12:34:55 +0000 | |
commit | 0cf4eef73a4c1bd2831a4618af50939a2aab01c6 (patch) | |
tree | 809caae588fa1e12556cb180bc4b253120627134 /src/crypto_engines/native | |
parent | 4358a18dea319b590da5b64e263439136bd8f806 (diff) |
crypto: move crypto engines outside of plugins
This is first step in process of making crypto engine binaries
less dependant on specific VPP version.
Type: improvement
Change-Id: Ib08135688be409049b660e2b2ac435578b63be65
Signed-off-by: Damjan Marion <dmarion@me.com>
Diffstat (limited to 'src/crypto_engines/native')
-rw-r--r-- | src/crypto_engines/native/CMakeLists.txt | 50 | ||||
-rw-r--r-- | src/crypto_engines/native/FEATURE.yaml | 13 | ||||
-rw-r--r-- | src/crypto_engines/native/aes_cbc.c | 188 | ||||
-rw-r--r-- | src/crypto_engines/native/aes_ctr.c | 130 | ||||
-rw-r--r-- | src/crypto_engines/native/aes_gcm.c | 166 | ||||
-rw-r--r-- | src/crypto_engines/native/crypto_native.h | 83 | ||||
-rw-r--r-- | src/crypto_engines/native/main.c | 113 | ||||
-rw-r--r-- | src/crypto_engines/native/sha2.c | 198 |
8 files changed, 941 insertions, 0 deletions
diff --git a/src/crypto_engines/native/CMakeLists.txt b/src/crypto_engines/native/CMakeLists.txt new file mode 100644 index 00000000000..d9d72aff58e --- /dev/null +++ b/src/crypto_engines/native/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (c) 2018 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*") + list(APPEND VARIANTS "slm\;-march=silvermont -maes") + list(APPEND VARIANTS "hsw\;-march=haswell -maes") + if(compiler_flag_march_skylake_avx512 AND compiler_flag_mprefer_vector_width_256) + list(APPEND VARIANTS "skx\;-march=skylake-avx512 -mprefer-vector-width=256") + endif() + if(compiler_flag_march_icelake_client AND compiler_flag_mprefer_vector_width_512) + list(APPEND VARIANTS "icl\;-march=icelake-client -mprefer-vector-width=512") + endif() + if(compiler_flag_march_alderlake) + list(APPEND VARIANTS "adl\;-march=alderlake -mprefer-vector-width=256") + endif() +endif() + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") + list(APPEND VARIANTS "armv8\;-march=armv8.1-a+crc+crypto") +endif() + +set (COMPILE_FILES aes_cbc.c aes_gcm.c aes_ctr.c sha2.c) +set (COMPILE_OPTS -Wall -fno-common) + +if (NOT VARIANTS) + return() +endif() + +add_vpp_crypto_engine(native SOURCES main.c) + +foreach(VARIANT ${VARIANTS}) + list(GET VARIANT 0 v) + list(GET VARIANT 1 f) + set(l native_crypto_engine_${v}) + add_library(${l} OBJECT ${COMPILE_FILES}) + set_target_properties(${l} PROPERTIES POSITION_INDEPENDENT_CODE ON) + separate_arguments(f) + target_compile_options(${l} PUBLIC ${f} ${COMPILE_OPTS}) + target_sources(native_crypto_engine PRIVATE $<TARGET_OBJECTS:${l}>) +endforeach() diff --git a/src/crypto_engines/native/FEATURE.yaml b/src/crypto_engines/native/FEATURE.yaml new file mode 100644 index 00000000000..d54816d673f --- /dev/null +++ b/src/crypto_engines/native/FEATURE.yaml @@ -0,0 +1,13 @@ +--- +name: IPSec crypto engine provided by native implementation +maintainer: Damjan Marion <damarion@cisco.com> +features: + - CBC(128, 192, 256) + - GCM(128, 192, 256) + - CTR(128, 192, 256) + - SHA(224, 256) + - HMAC-SHA(224, 256) + +description: "An implementation of a native crypto-engine" +state: production +properties: [API, CLI, MULTITHREAD] diff --git a/src/crypto_engines/native/aes_cbc.c b/src/crypto_engines/native/aes_cbc.c new file mode 100644 index 00000000000..b4ed2b3493d --- /dev/null +++ b/src/crypto_engines/native/aes_cbc.c @@ -0,0 +1,188 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vnet/crypto/crypto.h> +#include <native/crypto_native.h> +#include <vppinfra/crypto/aes_cbc.h> + +#if __GNUC__ > 4 && !__clang__ && CLIB_DEBUG == 0 +#pragma GCC optimize ("O3") +#endif + +#define CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE 256 + +static_always_inline u32 +aes_ops_enc_aes_cbc (vlib_main_t * vm, vnet_crypto_op_t * ops[], + u32 n_ops, aes_key_size_t ks) +{ + crypto_native_main_t *cm = &crypto_native_main; + u32 i, n_left = n_ops; + uword key_indices[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {}; + u8 *plaintext[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {}; + uword oplen[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {}; + u8 *iv[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {}; + u8 *ciphertext[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {}; + + while (n_left) + { + i = 0; + while (n_left && i < CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE) + { + key_indices[i] = ops[0]->key_index; + plaintext[i] = ops[0]->src; + ciphertext[i] = ops[0]->dst; + oplen[i] = ops[0]->len; + iv[i] = ops[0]->iv; + ops[0]->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + + ops++; + n_left--; + i++; + } + clib_aes_cbc_encrypt_multi ((aes_cbc_key_data_t **) cm->key_data, + key_indices, plaintext, oplen, iv, ks, + ciphertext, i); + } + return n_ops; +} + + +static_always_inline u32 +aes_ops_dec_aes_cbc (vlib_main_t * vm, vnet_crypto_op_t * ops[], + u32 n_ops, aes_key_size_t ks) +{ + crypto_native_main_t *cm = &crypto_native_main; + int rounds = AES_KEY_ROUNDS (ks); + vnet_crypto_op_t *op = ops[0]; + aes_cbc_key_data_t *kd = (aes_cbc_key_data_t *) cm->key_data[op->key_index]; + u32 n_left = n_ops; + + ASSERT (n_ops >= 1); + +decrypt: +#if defined(__VAES__) && defined(__AVX512F__) + aes4_cbc_dec (kd->decrypt_key, (u8x64u *) op->src, (u8x64u *) op->dst, + (u8x16u *) op->iv, op->len, rounds); +#elif defined(__VAES__) + aes2_cbc_dec (kd->decrypt_key, (u8x32u *) op->src, (u8x32u *) op->dst, + (u8x16u *) op->iv, op->len, rounds); +#else + aes_cbc_dec (kd->decrypt_key, (u8x16u *) op->src, (u8x16u *) op->dst, + (u8x16u *) op->iv, op->len, rounds); +#endif + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + + if (--n_left) + { + op += 1; + kd = (aes_cbc_key_data_t *) cm->key_data[op->key_index]; + goto decrypt; + } + + return n_ops; +} + +static int +aes_cbc_cpu_probe () +{ +#if defined(__VAES__) && defined(__AVX512F__) + if (clib_cpu_supports_vaes () && clib_cpu_supports_avx512f ()) + return 50; +#elif defined(__VAES__) + if (clib_cpu_supports_vaes ()) + return 40; +#elif defined(__AVX512F__) + if (clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__AVX2__) + if (clib_cpu_supports_avx2 ()) + return 20; +#elif __AES__ + if (clib_cpu_supports_aes ()) + return 10; +#elif __aarch64__ + if (clib_cpu_supports_aarch64_aes ()) + return 10; +#endif + return -1; +} + +static void * +aes_cbc_key_exp_128 (vnet_crypto_key_t *key) +{ + aes_cbc_key_data_t *kd; + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + clib_aes128_cbc_key_expand (kd, key->data); + return kd; +} + +static void * +aes_cbc_key_exp_192 (vnet_crypto_key_t *key) +{ + aes_cbc_key_data_t *kd; + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + clib_aes192_cbc_key_expand (kd, key->data); + return kd; +} + +static void * +aes_cbc_key_exp_256 (vnet_crypto_key_t *key) +{ + aes_cbc_key_data_t *kd; + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + clib_aes256_cbc_key_expand (kd, key->data); + return kd; +} + +#define foreach_aes_cbc_handler_type _ (128) _ (192) _ (256) + +#define _(x) \ + static u32 aes_ops_enc_aes_cbc_##x (vlib_main_t *vm, \ + vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return aes_ops_enc_aes_cbc (vm, ops, n_ops, AES_KEY_##x); \ + } \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##x##_cbc_enc) = { \ + .op_id = VNET_CRYPTO_OP_AES_##x##_CBC_ENC, \ + .fn = aes_ops_enc_aes_cbc_##x, \ + .probe = aes_cbc_cpu_probe, \ + }; \ + \ + static u32 aes_ops_dec_aes_cbc_##x (vlib_main_t *vm, \ + vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return aes_ops_dec_aes_cbc (vm, ops, n_ops, AES_KEY_##x); \ + } \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##x##_cbc_dec) = { \ + .op_id = VNET_CRYPTO_OP_AES_##x##_CBC_DEC, \ + .fn = aes_ops_dec_aes_cbc_##x, \ + .probe = aes_cbc_cpu_probe, \ + }; \ + \ + CRYPTO_NATIVE_KEY_HANDLER (aes_##x##_cbc) = { \ + .alg_id = VNET_CRYPTO_ALG_AES_##x##_CBC, \ + .key_fn = aes_cbc_key_exp_##x, \ + .probe = aes_cbc_cpu_probe, \ + }; + +foreach_aes_cbc_handler_type; +#undef _ + diff --git a/src/crypto_engines/native/aes_ctr.c b/src/crypto_engines/native/aes_ctr.c new file mode 100644 index 00000000000..d39b1c83842 --- /dev/null +++ b/src/crypto_engines/native/aes_ctr.c @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2024 Cisco Systems, Inc. + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vnet/crypto/crypto.h> +#include <native/crypto_native.h> +#include <vppinfra/crypto/aes_ctr.h> + +#if __GNUC__ > 4 && !__clang__ && CLIB_DEBUG == 0 +#pragma GCC optimize("O3") +#endif + +static_always_inline u32 +aes_ops_aes_ctr (vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops, + vnet_crypto_op_chunk_t *chunks, aes_key_size_t ks, + int maybe_chained) +{ + crypto_native_main_t *cm = &crypto_native_main; + vnet_crypto_op_t *op = ops[0]; + aes_ctr_key_data_t *kd; + aes_ctr_ctx_t ctx; + u32 n_left = n_ops; + +next: + kd = (aes_ctr_key_data_t *) cm->key_data[op->key_index]; + + clib_aes_ctr_init (&ctx, kd, op->iv, ks); + if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS) + { + vnet_crypto_op_chunk_t *chp = chunks + op->chunk_index; + for (int j = 0; j < op->n_chunks; j++, chp++) + clib_aes_ctr_transform (&ctx, chp->src, chp->dst, chp->len, ks); + } + else + clib_aes_ctr_transform (&ctx, op->src, op->dst, op->len, ks); + + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + + if (--n_left) + { + op += 1; + goto next; + } + + return n_ops; +} + +static_always_inline void * +aes_ctr_key_exp (vnet_crypto_key_t *key, aes_key_size_t ks) +{ + aes_ctr_key_data_t *kd; + + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + + clib_aes_ctr_key_expand (kd, key->data, ks); + + return kd; +} + +#define foreach_aes_ctr_handler_type _ (128) _ (192) _ (256) + +#define _(x) \ + static u32 aes_ops_aes_ctr_##x (vlib_main_t *vm, vnet_crypto_op_t *ops[], \ + u32 n_ops) \ + { \ + return aes_ops_aes_ctr (vm, ops, n_ops, 0, AES_KEY_##x, 0); \ + } \ + static u32 aes_ops_aes_ctr_##x##_chained ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, \ + u32 n_ops) \ + { \ + return aes_ops_aes_ctr (vm, ops, n_ops, chunks, AES_KEY_##x, 1); \ + } \ + static void *aes_ctr_key_exp_##x (vnet_crypto_key_t *key) \ + { \ + return aes_ctr_key_exp (key, AES_KEY_##x); \ + } + +foreach_aes_ctr_handler_type; +#undef _ + +static int +probe () +{ +#if defined(__VAES__) && defined(__AVX512F__) + if (clib_cpu_supports_vaes () && clib_cpu_supports_avx512f ()) + return 50; +#elif defined(__VAES__) + if (clib_cpu_supports_vaes ()) + return 40; +#elif defined(__AVX512F__) + if (clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__AVX2__) + if (clib_cpu_supports_avx2 ()) + return 20; +#elif __AES__ + if (clib_cpu_supports_aes ()) + return 10; +#elif __aarch64__ + if (clib_cpu_supports_aarch64_aes ()) + return 10; +#endif + return -1; +} + +#define _(b) \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_ctr_enc) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_CTR_ENC, \ + .fn = aes_ops_aes_ctr_##b, \ + .cfn = aes_ops_aes_ctr_##b##_chained, \ + .probe = probe, \ + }; \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_ctr_dec) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_CTR_DEC, \ + .fn = aes_ops_aes_ctr_##b, \ + .cfn = aes_ops_aes_ctr_##b##_chained, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_KEY_HANDLER (aes_##b##_ctr) = { \ + .alg_id = VNET_CRYPTO_ALG_AES_##b##_CTR, \ + .key_fn = aes_ctr_key_exp_##b, \ + .probe = probe, \ + }; + +_ (128) _ (192) _ (256) +#undef _ diff --git a/src/crypto_engines/native/aes_gcm.c b/src/crypto_engines/native/aes_gcm.c new file mode 100644 index 00000000000..57eee17f3d0 --- /dev/null +++ b/src/crypto_engines/native/aes_gcm.c @@ -0,0 +1,166 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vnet/crypto/crypto.h> +#include <native/crypto_native.h> +#include <vppinfra/crypto/aes_gcm.h> + +#if __GNUC__ > 4 && !__clang__ && CLIB_DEBUG == 0 +#pragma GCC optimize("O3") +#endif + +static_always_inline u32 +aes_ops_enc_aes_gcm (vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops, + aes_key_size_t ks) +{ + crypto_native_main_t *cm = &crypto_native_main; + vnet_crypto_op_t *op = ops[0]; + aes_gcm_key_data_t *kd; + u32 n_left = n_ops; + +next: + kd = (aes_gcm_key_data_t *) cm->key_data[op->key_index]; + aes_gcm (op->src, op->dst, op->aad, (u8 *) op->iv, op->tag, op->len, + op->aad_len, op->tag_len, kd, AES_KEY_ROUNDS (ks), + AES_GCM_OP_ENCRYPT); + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + + if (--n_left) + { + op += 1; + goto next; + } + + return n_ops; +} + +static_always_inline u32 +aes_ops_dec_aes_gcm (vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops, + aes_key_size_t ks) +{ + crypto_native_main_t *cm = &crypto_native_main; + vnet_crypto_op_t *op = ops[0]; + aes_gcm_key_data_t *kd; + u32 n_left = n_ops; + int rv; + +next: + kd = (aes_gcm_key_data_t *) cm->key_data[op->key_index]; + rv = aes_gcm (op->src, op->dst, op->aad, (u8 *) op->iv, op->tag, op->len, + op->aad_len, op->tag_len, kd, AES_KEY_ROUNDS (ks), + AES_GCM_OP_DECRYPT); + + if (rv) + { + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + } + else + { + op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; + n_ops--; + } + + if (--n_left) + { + op += 1; + goto next; + } + + return n_ops; +} + +static_always_inline void * +aes_gcm_key_exp (vnet_crypto_key_t *key, aes_key_size_t ks) +{ + aes_gcm_key_data_t *kd; + + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + + clib_aes_gcm_key_expand (kd, key->data, ks); + + return kd; +} + +#define foreach_aes_gcm_handler_type _ (128) _ (192) _ (256) + +#define _(x) \ + static u32 aes_ops_dec_aes_gcm_##x (vlib_main_t *vm, \ + vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return aes_ops_dec_aes_gcm (vm, ops, n_ops, AES_KEY_##x); \ + } \ + static u32 aes_ops_enc_aes_gcm_##x (vlib_main_t *vm, \ + vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return aes_ops_enc_aes_gcm (vm, ops, n_ops, AES_KEY_##x); \ + } \ + static void *aes_gcm_key_exp_##x (vnet_crypto_key_t *key) \ + { \ + return aes_gcm_key_exp (key, AES_KEY_##x); \ + } + +foreach_aes_gcm_handler_type; +#undef _ + +static int +probe () +{ +#if defined(__VAES__) && defined(__AVX512F__) + if (clib_cpu_supports_vpclmulqdq () && clib_cpu_supports_vaes () && + clib_cpu_supports_avx512f ()) + return 50; +#elif defined(__VAES__) + if (clib_cpu_supports_vpclmulqdq () && clib_cpu_supports_vaes ()) + return 40; +#elif defined(__AVX512F__) + if (clib_cpu_supports_pclmulqdq () && clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__AVX2__) + if (clib_cpu_supports_pclmulqdq () && clib_cpu_supports_avx2 ()) + return 20; +#elif __AES__ + if (clib_cpu_supports_pclmulqdq () && clib_cpu_supports_aes ()) + return 10; +#elif __aarch64__ + if (clib_cpu_supports_aarch64_aes ()) + return 10; +#endif + return -1; +} + +#define _(b) \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_gcm_enc) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_GCM_ENC, \ + .fn = aes_ops_enc_aes_gcm_##b, \ + .probe = probe, \ + }; \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_gcm_dec) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_GCM_DEC, \ + .fn = aes_ops_dec_aes_gcm_##b, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_KEY_HANDLER (aes_##b##_gcm) = { \ + .alg_id = VNET_CRYPTO_ALG_AES_##b##_GCM, \ + .key_fn = aes_gcm_key_exp_##b, \ + .probe = probe, \ + }; + +_ (128) _ (192) _ (256) +#undef _ diff --git a/src/crypto_engines/native/crypto_native.h b/src/crypto_engines/native/crypto_native.h new file mode 100644 index 00000000000..0fcb6a99524 --- /dev/null +++ b/src/crypto_engines/native/crypto_native.h @@ -0,0 +1,83 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#ifndef __crypto_native_h__ +#define __crypto_native_h__ + +typedef void *(crypto_native_key_fn_t) (vnet_crypto_key_t * key); +typedef int (crypto_native_variant_probe_t) (); + +typedef struct crypto_native_op_handler +{ + struct crypto_native_op_handler *next; + vnet_crypto_op_id_t op_id; + vnet_crypto_ops_handler_t *fn; + vnet_crypto_chained_ops_handler_t *cfn; + crypto_native_variant_probe_t *probe; + int priority; +} crypto_native_op_handler_t; + +typedef struct crypto_native_key_handler +{ + struct crypto_native_key_handler *next; + vnet_crypto_alg_t alg_id; + crypto_native_key_fn_t *key_fn; + crypto_native_variant_probe_t *probe; + int priority; +} crypto_native_key_handler_t; + +typedef struct +{ + crypto_native_key_fn_t *key_fn[VNET_CRYPTO_N_ALGS]; + void **key_data; + crypto_native_op_handler_t *op_handlers; + crypto_native_key_handler_t *key_handlers; +} crypto_native_main_t; + +extern crypto_native_main_t crypto_native_main; + +#define CRYPTO_NATIVE_OP_HANDLER(x) \ + static crypto_native_op_handler_t __crypto_native_op_handler_##x; \ + static void __clib_constructor __crypto_native_op_handler_cb_##x (void) \ + { \ + crypto_native_main_t *cm = &crypto_native_main; \ + int priority = __crypto_native_op_handler_##x.probe (); \ + if (priority >= 0) \ + { \ + __crypto_native_op_handler_##x.priority = priority; \ + __crypto_native_op_handler_##x.next = cm->op_handlers; \ + cm->op_handlers = &__crypto_native_op_handler_##x; \ + } \ + } \ + static crypto_native_op_handler_t __crypto_native_op_handler_##x + +#define CRYPTO_NATIVE_KEY_HANDLER(x) \ + static crypto_native_key_handler_t __crypto_native_key_handler_##x; \ + static void __clib_constructor __crypto_native_key_handler_cb_##x (void) \ + { \ + crypto_native_main_t *cm = &crypto_native_main; \ + int priority = __crypto_native_key_handler_##x.probe (); \ + if (priority >= 0) \ + { \ + __crypto_native_key_handler_##x.priority = priority; \ + __crypto_native_key_handler_##x.next = cm->key_handlers; \ + cm->key_handlers = &__crypto_native_key_handler_##x; \ + } \ + } \ + static crypto_native_key_handler_t __crypto_native_key_handler_##x +#endif /* __crypto_native_h__ */ + diff --git a/src/crypto_engines/native/main.c b/src/crypto_engines/native/main.c new file mode 100644 index 00000000000..e9e71b6fb6d --- /dev/null +++ b/src/crypto_engines/native/main.c @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Cisco Systems, Inc. + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vnet/crypto/crypto.h> +#include <vnet/crypto/engine.h> +#include <native/crypto_native.h> + +crypto_native_main_t crypto_native_main; +vnet_crypto_engine_op_handlers_t op_handlers[24], *ophp = op_handlers; + +static void +crypto_native_key_handler (vnet_crypto_key_op_t kop, + vnet_crypto_key_index_t idx) +{ + vnet_crypto_key_t *key = vnet_crypto_get_key (idx); + crypto_native_main_t *cm = &crypto_native_main; + + /** TODO: add linked alg support **/ + if (key->type == VNET_CRYPTO_KEY_TYPE_LINK) + return; + + if (cm->key_fn[key->alg] == 0) + return; + + if (kop == VNET_CRYPTO_KEY_OP_DEL) + { + if (idx >= vec_len (cm->key_data)) + return; + + if (cm->key_data[idx] == 0) + return; + + clib_mem_free_s (cm->key_data[idx]); + cm->key_data[idx] = 0; + return; + } + + vec_validate_aligned (cm->key_data, idx, CLIB_CACHE_LINE_BYTES); + + if (kop == VNET_CRYPTO_KEY_OP_MODIFY && cm->key_data[idx]) + { + clib_mem_free_s (cm->key_data[idx]); + } + + cm->key_data[idx] = cm->key_fn[key->alg] (key); +} + +static char * +crypto_native_init (vnet_crypto_engine_registration_t *r) +{ + crypto_native_main_t *cm = &crypto_native_main; + + if (cm->op_handlers == 0) + return 0; + + crypto_native_op_handler_t *oh = cm->op_handlers; + crypto_native_key_handler_t *kh = cm->key_handlers; + crypto_native_op_handler_t **best_by_op_id = 0; + crypto_native_key_handler_t **best_by_alg_id = 0; + + while (oh) + { + vec_validate (best_by_op_id, oh->op_id); + + if (best_by_op_id[oh->op_id] == 0 || + best_by_op_id[oh->op_id]->priority < oh->priority) + best_by_op_id[oh->op_id] = oh; + + oh = oh->next; + } + + while (kh) + { + vec_validate (best_by_alg_id, kh->alg_id); + + if (best_by_alg_id[kh->alg_id] == 0 || + best_by_alg_id[kh->alg_id]->priority < kh->priority) + best_by_alg_id[kh->alg_id] = kh; + + kh = kh->next; + } + + vec_foreach_pointer (oh, best_by_op_id) + if (oh) + { + *ophp = (vnet_crypto_engine_op_handlers_t){ .opt = oh->op_id, + .fn = oh->fn, + .cfn = oh->cfn }; + ophp++; + ASSERT ((ophp - op_handlers) < ARRAY_LEN (op_handlers)); + } + + vec_foreach_pointer (kh, best_by_alg_id) + if (kh) + cm->key_fn[kh->alg_id] = kh->key_fn; + + vec_free (best_by_op_id); + vec_free (best_by_alg_id); + + return 0; +} + +VNET_CRYPTO_ENGINE_REGISTRATION () = { + .name = "native", + .desc = "Native ISA Optimized Crypto", + .prio = 100, + .init_fn = crypto_native_init, + .key_handler = crypto_native_key_handler, + .op_handlers = op_handlers, +}; diff --git a/src/crypto_engines/native/sha2.c b/src/crypto_engines/native/sha2.c new file mode 100644 index 00000000000..b61a5f08060 --- /dev/null +++ b/src/crypto_engines/native/sha2.c @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2024 Cisco Systems, Inc. + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vnet/crypto/crypto.h> +#include <native/crypto_native.h> +#include <vppinfra/crypto/sha2.h> + +static_always_inline u32 +crypto_native_ops_hash_sha2 (vlib_main_t *vm, vnet_crypto_op_t *ops[], + u32 n_ops, vnet_crypto_op_chunk_t *chunks, + clib_sha2_type_t type, int maybe_chained) +{ + vnet_crypto_op_t *op = ops[0]; + clib_sha2_ctx_t ctx; + u32 n_left = n_ops; + +next: + if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS) + { + vnet_crypto_op_chunk_t *chp = chunks + op->chunk_index; + clib_sha2_init (&ctx, type); + for (int j = 0; j < op->n_chunks; j++, chp++) + clib_sha2_update (&ctx, chp->src, chp->len); + clib_sha2_final (&ctx, op->digest); + } + else + clib_sha2 (type, op->src, op->len, op->digest); + + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + + if (--n_left) + { + op += 1; + goto next; + } + + return n_ops; +} + +static_always_inline u32 +crypto_native_ops_hmac_sha2 (vlib_main_t *vm, vnet_crypto_op_t *ops[], + u32 n_ops, vnet_crypto_op_chunk_t *chunks, + clib_sha2_type_t type) +{ + crypto_native_main_t *cm = &crypto_native_main; + vnet_crypto_op_t *op = ops[0]; + u32 n_left = n_ops; + clib_sha2_hmac_ctx_t ctx; + u8 buffer[64]; + u32 sz, n_fail = 0; + + for (; n_left; n_left--, op++) + { + clib_sha2_hmac_init ( + &ctx, type, (clib_sha2_hmac_key_data_t *) cm->key_data[op->key_index]); + if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS) + { + vnet_crypto_op_chunk_t *chp = chunks + op->chunk_index; + for (int j = 0; j < op->n_chunks; j++, chp++) + clib_sha2_hmac_update (&ctx, chp->src, chp->len); + } + else + clib_sha2_hmac_update (&ctx, op->src, op->len); + + clib_sha2_hmac_final (&ctx, buffer); + + if (op->digest_len) + { + sz = op->digest_len; + if (op->flags & VNET_CRYPTO_OP_FLAG_HMAC_CHECK) + { + if ((memcmp (op->digest, buffer, sz))) + { + n_fail++; + op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; + continue; + } + } + else + clib_memcpy_fast (op->digest, buffer, sz); + } + else + { + sz = clib_sha2_variants[type].digest_size; + if (op->flags & VNET_CRYPTO_OP_FLAG_HMAC_CHECK) + { + if ((memcmp (op->digest, buffer, sz))) + { + n_fail++; + op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; + continue; + } + } + else + clib_memcpy_fast (op->digest, buffer, sz); + } + + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + } + + return n_ops - n_fail; +} + +static void * +sha2_key_add (vnet_crypto_key_t *key, clib_sha2_type_t type) +{ + clib_sha2_hmac_key_data_t *kd; + + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + clib_sha2_hmac_key_data (type, key->data, vec_len (key->data), kd); + + return kd; +} + +static int +probe () +{ +#if defined(__x86_64__) + +#if defined(__SHA__) && defined(__AVX512F__) + if (clib_cpu_supports_sha () && clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__SHA__) && defined(__AVX2__) + if (clib_cpu_supports_sha () && clib_cpu_supports_avx2 ()) + return 20; +#elif defined(__SHA__) + if (clib_cpu_supports_sha ()) + return 10; +#endif + +#elif defined(__aarch64__) +#if defined(__ARM_FEATURE_SHA2) + if (clib_cpu_supports_sha2 ()) + return 10; +#endif +#endif + return -1; +} + +#define _(b) \ + static u32 crypto_native_ops_hash_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return crypto_native_ops_hash_sha2 (vm, ops, n_ops, 0, CLIB_SHA2_##b, 0); \ + } \ + \ + static u32 crypto_native_ops_chained_hash_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, \ + u32 n_ops) \ + { \ + return crypto_native_ops_hash_sha2 (vm, ops, n_ops, chunks, \ + CLIB_SHA2_##b, 1); \ + } \ + \ + static u32 crypto_native_ops_hmac_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return crypto_native_ops_hmac_sha2 (vm, ops, n_ops, 0, CLIB_SHA2_##b); \ + } \ + \ + static u32 crypto_native_ops_chained_hmac_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, \ + u32 n_ops) \ + { \ + return crypto_native_ops_hmac_sha2 (vm, ops, n_ops, chunks, \ + CLIB_SHA2_##b); \ + } \ + \ + static void *sha2_##b##_key_add (vnet_crypto_key_t *k) \ + { \ + return sha2_key_add (k, CLIB_SHA2_##b); \ + } \ + \ + CRYPTO_NATIVE_OP_HANDLER (crypto_native_hash_sha##b) = { \ + .op_id = VNET_CRYPTO_OP_SHA##b##_HASH, \ + .fn = crypto_native_ops_hash_sha##b, \ + .cfn = crypto_native_ops_chained_hash_sha##b, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_OP_HANDLER (crypto_native_hmac_sha##b) = { \ + .op_id = VNET_CRYPTO_OP_SHA##b##_HMAC, \ + .fn = crypto_native_ops_hmac_sha##b, \ + .cfn = crypto_native_ops_chained_hmac_sha##b, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_KEY_HANDLER (crypto_native_hmac_sha##b) = { \ + .alg_id = VNET_CRYPTO_ALG_HMAC_SHA##b, \ + .key_fn = sha2_##b##_key_add, \ + .probe = probe, \ + }; + +_ (224) +_ (256) + +#undef _ |