Signed-off-by: Nicolas Morey-Chaisemartin <nmo...@kalray.eu>
---
 include/odp/api/crypto.h                           |   4 +
 .../linux-generic/include/odp_crypto_internal.h    |   3 +
 platform/linux-generic/odp_crypto.c                | 183 +++++++++++++++++++++
 3 files changed, 190 insertions(+)

diff --git a/include/odp/api/crypto.h b/include/odp/api/crypto.h
index c62021e..41beedb 100644
--- a/include/odp/api/crypto.h
+++ b/include/odp/api/crypto.h
@@ -70,6 +70,8 @@ typedef enum {
        ODP_CIPHER_ALG_3DES_CBC,
        /** AES128 with cipher block chaining */
        ODP_CIPHER_ALG_AES128_CBC,
+       /** AES128 in Galois/Counter Mode */
+       ODP_CIPHER_ALG_AES128_GCM,
 } odp_cipher_alg_t;
 
 /**
@@ -82,6 +84,8 @@ typedef enum {
        ODP_AUTH_ALG_MD5_96,
        /** SHA256 with 128 bit key */
        ODP_AUTH_ALG_SHA256_128,
+       /** AES128 in Galois/Counter Mode */
+       ODP_AUTH_ALG_AES128_GCM,
 } odp_auth_alg_t;
 
 /**
diff --git a/platform/linux-generic/include/odp_crypto_internal.h 
b/platform/linux-generic/include/odp_crypto_internal.h
index b9128a4..7b104af 100644
--- a/platform/linux-generic/include/odp_crypto_internal.h
+++ b/platform/linux-generic/include/odp_crypto_internal.h
@@ -50,6 +50,9 @@ struct odp_crypto_generic_session {
                        struct {
                                AES_KEY key;
                        } aes;
+                       struct {
+                               EVP_CIPHER_CTX *ctx;
+                       } aes_gcm;
                } data;
                crypto_func_t func;
        } cipher;
diff --git a/platform/linux-generic/odp_crypto.c 
b/platform/linux-generic/odp_crypto.c
index 17fced9..65e8503 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -292,6 +292,170 @@ int process_aes_params(odp_crypto_generic_session_t 
*session,
 }
 
 static
+odp_crypto_alg_err_t aes_gcm_encrypt(odp_crypto_op_params_t *params,
+                                    odp_crypto_generic_session_t *session)
+{
+       uint8_t *data  = odp_packet_data(params->out_pkt);
+       uint32_t plain_len   = params->cipher_range.length;
+       uint8_t *aad_head = data + params->auth_range.offset;
+       uint8_t *aad_tail = data + params->cipher_range.offset +
+               params->cipher_range.length;
+       uint32_t auth_len = params->auth_range.length;
+       unsigned char iv_enc[AES_BLOCK_SIZE];
+       void *iv_ptr;
+       uint8_t *tag = data + params->hash_result_offset;
+
+       if (params->override_iv_ptr)
+               iv_ptr = params->override_iv_ptr;
+       else if (session->cipher.iv.data)
+               iv_ptr = session->cipher.iv.data;
+       else
+               return ODP_CRYPTO_ALG_ERR_IV_INVALID;
+
+       /* All cipher data must be part of the authentication */
+       if (params->auth_range.offset > params->cipher_range.offset ||
+           params->auth_range.offset + auth_len <
+           params->cipher_range.offset + plain_len)
+               return ODP_CRYPTO_ALG_ERR_DATA_SIZE;
+
+       /*
+        * 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_enc, iv_ptr, AES_BLOCK_SIZE);
+
+       /* Adjust pointer for beginning of area to cipher/auth */
+       uint8_t *plaindata = data + params->cipher_range.offset;
+
+       /* Encrypt it */
+       EVP_CIPHER_CTX *ctx = session->cipher.data.aes_gcm.ctx;
+       int cipher_len = 0;
+
+       EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_enc);
+
+       /* Authenticate header data (if any) without encrypting them */
+       if (aad_head < plaindata) {
+               EVP_EncryptUpdate(ctx, NULL, &cipher_len,
+                                 aad_head, plaindata - aad_head);
+       }
+
+       EVP_EncryptUpdate(ctx, plaindata, &cipher_len,
+                         plaindata, plain_len);
+       cipher_len = plain_len;
+
+       /* Authenticate footer data (if any) without encrypting them */
+       if (aad_head + auth_len > plaindata + plain_len) {
+               EVP_EncryptUpdate(ctx, NULL, NULL, aad_tail,
+                                 auth_len - (aad_tail - aad_head));
+       }
+
+       EVP_EncryptFinal_ex(ctx, plaindata + cipher_len, &cipher_len);
+       EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);
+
+       return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static
+odp_crypto_alg_err_t aes_gcm_decrypt(odp_crypto_op_params_t *params,
+                                    odp_crypto_generic_session_t *session)
+{
+       uint8_t *data  = odp_packet_data(params->out_pkt);
+       uint32_t cipher_len   = params->cipher_range.length;
+       uint8_t *aad_head = data + params->auth_range.offset;
+       uint8_t *aad_tail = data + params->cipher_range.offset +
+               params->cipher_range.length;
+       uint32_t auth_len = params->auth_range.length;
+       unsigned char iv_enc[AES_BLOCK_SIZE];
+       void *iv_ptr;
+       uint8_t *tag   = data + params->hash_result_offset;
+
+       if (params->override_iv_ptr)
+               iv_ptr = params->override_iv_ptr;
+       else if (session->cipher.iv.data)
+               iv_ptr = session->cipher.iv.data;
+       else
+               return ODP_CRYPTO_ALG_ERR_IV_INVALID;
+
+       /* All cipher data must be part of the authentication */
+       if (params->auth_range.offset > params->cipher_range.offset ||
+           params->auth_range.offset + auth_len <
+           params->cipher_range.offset + cipher_len)
+               return ODP_CRYPTO_ALG_ERR_DATA_SIZE;
+
+       /*
+        * 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_enc, iv_ptr, AES_BLOCK_SIZE);
+
+       /* Adjust pointer for beginning of area to cipher/auth */
+       uint8_t *cipherdata = data + params->cipher_range.offset;
+       /* Encrypt it */
+       EVP_CIPHER_CTX *ctx = session->cipher.data.aes_gcm.ctx;
+       int plain_len = 0;
+
+       EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_enc);
+
+       /* Authenticate header data (if any) without encrypting them */
+       if (aad_head < cipherdata) {
+               EVP_DecryptUpdate(ctx, NULL, &plain_len,
+                                 aad_head, cipherdata - aad_head);
+       }
+
+       EVP_DecryptUpdate(ctx, cipherdata, &plain_len,
+                         cipherdata, cipher_len);
+       plain_len = cipher_len;
+
+       /* Authenticate footer data (if any) without encrypting them */
+       if (aad_head + auth_len > cipherdata + cipher_len) {
+               EVP_DecryptUpdate(ctx, NULL, NULL, aad_tail,
+                                 auth_len - (aad_tail - aad_head));
+       }
+
+       EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
+
+       if (EVP_DecryptFinal_ex(ctx, cipherdata + cipher_len, &plain_len) < 0)
+               return ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+
+       return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static
+int process_aes_gcm_params(odp_crypto_generic_session_t *session,
+                          odp_crypto_session_params_t *params)
+{
+       /* Verify Key len is 16 */
+       if (params->cipher_key.length != 16)
+               return -1;
+
+       /* Set function */
+       EVP_CIPHER_CTX *ctx =
+               session->cipher.data.aes_gcm.ctx = EVP_CIPHER_CTX_new();
+
+       if (ODP_CRYPTO_OP_ENCODE == params->op) {
+               session->cipher.func = aes_gcm_encrypt;
+               EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
+       } else {
+               session->cipher.func = aes_gcm_decrypt;
+               EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
+       }
+
+       EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+                           params->iv.length, NULL);
+       if (ODP_CRYPTO_OP_ENCODE == params->op) {
+               EVP_EncryptInit_ex(ctx, NULL, NULL,
+                                  params->cipher_key.data, NULL);
+       } else {
+               EVP_DecryptInit_ex(ctx, NULL, NULL,
+                                  params->cipher_key.data, NULL);
+       }
+
+       return 0;
+}
+
+static
 odp_crypto_alg_err_t des_encrypt(odp_crypto_op_params_t *params,
                                 odp_crypto_generic_session_t *session)
 {
@@ -479,6 +643,15 @@ odp_crypto_session_create(odp_crypto_session_params_t 
*params,
        case ODP_CIPHER_ALG_AES128_CBC:
                rc = process_aes_params(session, params);
                break;
+       case ODP_CIPHER_ALG_AES128_GCM:
+               /* AES-GCM requires to do both auth and
+                * cipher at the same time */
+               if (params->auth_alg != ODP_AUTH_ALG_AES128_GCM) {
+                       rc = -1;
+                       break;
+               }
+               rc = process_aes_gcm_params(session, params);
+               break;
        default:
                rc = -1;
        }
@@ -501,6 +674,16 @@ odp_crypto_session_create(odp_crypto_session_params_t 
*params,
        case ODP_AUTH_ALG_SHA256_128:
                rc = process_sha256_params(session, params, 128);
                break;
+       case ODP_AUTH_ALG_AES128_GCM:
+               /* AES-GCM requires to do both auth and
+                * cipher at the same time */
+               if (params->cipher_alg != ODP_CIPHER_ALG_AES128_GCM) {
+                       rc = -1;
+                       break;
+               }
+               session->auth.func = null_crypto_routine;
+               rc = 0;
+               break;
        default:
                rc = -1;
        }
-- 
2.6.2.406.gaaaec35


_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to