Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>
---
 platform/linux-generic/odp_crypto.c | 184 +++++++++++++++++++++++++++---------
 1 file changed, 138 insertions(+), 46 deletions(-)

diff --git a/platform/linux-generic/odp_crypto.c 
b/platform/linux-generic/odp_crypto.c
index 7ea90fb92b48..ea7c702650f6 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -190,14 +190,122 @@ odp_crypto_alg_err_t auth_check(odp_crypto_op_param_t 
*param,
 }
 
 static
+int internal_encrypt(EVP_CIPHER_CTX *ctx, odp_crypto_op_param_t *param)
+{
+       odp_packet_t pkt = param->out_pkt;
+       unsigned in_pos = param->cipher_range.offset;
+       unsigned out_pos = param->cipher_range.offset;
+       unsigned in_len = param->cipher_range.length;
+       uint8_t block[2 * EVP_MAX_BLOCK_LENGTH];
+       unsigned block_len = EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(ctx));
+       int cipher_len;
+       int ret;
+
+       while (in_len > 0) {
+               uint32_t seglen = 0; /* GCC */
+               uint8_t *insegaddr = odp_packet_offset(pkt, in_pos,
+                                                      &seglen, NULL);
+               unsigned inseglen = in_len < seglen ? in_len : seglen;
+
+               /* There should be at least 1 additional block in out buffer */
+               if (inseglen > block_len) {
+                       unsigned part = inseglen - block_len;
+
+                       EVP_EncryptUpdate(ctx, insegaddr, &cipher_len,
+                                         insegaddr, part);
+                       in_pos += part;
+                       in_len -= part;
+                       insegaddr += part;
+                       inseglen -= part;
+
+                       out_pos += cipher_len;
+               }
+
+               /* Use temporal storage */
+               if (inseglen > 0) {
+                       unsigned part = inseglen;
+
+                       EVP_EncryptUpdate(ctx, block, &cipher_len,
+                                         insegaddr, part);
+                       in_pos += part;
+                       in_len -= part;
+                       insegaddr += part;
+                       inseglen -= part;
+
+                       odp_packet_copy_from_mem(pkt, out_pos,
+                                                cipher_len, block);
+                       out_pos += cipher_len;
+               }
+       }
+
+       ret = EVP_EncryptFinal_ex(ctx, block, &cipher_len);
+       odp_packet_copy_from_mem(pkt, out_pos, cipher_len, block);
+
+       return ret;
+}
+
+static
+int internal_decrypt(EVP_CIPHER_CTX *ctx, odp_crypto_op_param_t *param)
+{
+       odp_packet_t pkt = param->out_pkt;
+       unsigned in_pos = param->cipher_range.offset;
+       unsigned out_pos = param->cipher_range.offset;
+       unsigned in_len = param->cipher_range.length;
+       uint8_t block[2 * EVP_MAX_BLOCK_LENGTH];
+       unsigned block_len = EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(ctx));
+       int cipher_len;
+       int ret;
+
+       while (in_len > 0) {
+               uint32_t seglen = 0; /* GCC */
+               uint8_t *insegaddr = odp_packet_offset(pkt, in_pos,
+                                                      &seglen, NULL);
+               unsigned inseglen = in_len < seglen ? in_len : seglen;
+
+               /* There should be at least 1 additional block in out buffer */
+               if (inseglen > block_len) {
+                       unsigned part = inseglen - block_len;
+
+                       EVP_DecryptUpdate(ctx, insegaddr, &cipher_len,
+                                         insegaddr, part);
+                       in_pos += part;
+                       in_len -= part;
+                       insegaddr += part;
+                       inseglen -= part;
+
+                       out_pos += cipher_len;
+               }
+
+               /* Use temporal storage */
+               if (inseglen > 0) {
+                       unsigned part = inseglen;
+
+                       EVP_DecryptUpdate(ctx, block, &cipher_len,
+                                         insegaddr, part);
+                       in_pos += part;
+                       in_len -= part;
+                       insegaddr += part;
+                       inseglen -= part;
+
+                       odp_packet_copy_from_mem(pkt, out_pos,
+                                                cipher_len, block);
+                       out_pos += cipher_len;
+               }
+       }
+
+       ret = EVP_DecryptFinal_ex(ctx, block, &cipher_len);
+       odp_packet_copy_from_mem(pkt, out_pos, cipher_len, block);
+
+       return ret;
+}
+
+static
 odp_crypto_alg_err_t cipher_encrypt(odp_crypto_op_param_t *param,
                                    odp_crypto_generic_session_t *session)
 {
        EVP_CIPHER_CTX *ctx;
-       uint8_t *data  = odp_packet_data(param->out_pkt);
-       uint32_t plain_len   = param->cipher_range.length;
        void *iv_ptr;
-       int cipher_len = 0;
+       int ret;
 
        if (param->override_iv_ptr)
                iv_ptr = param->override_iv_ptr;
@@ -206,9 +314,6 @@ odp_crypto_alg_err_t cipher_encrypt(odp_crypto_op_param_t 
*param,
        else
                return ODP_CRYPTO_ALG_ERR_IV_INVALID;
 
-       /* Adjust pointer for beginning of area to cipher/auth */
-       data += param->cipher_range.offset;
-
        /* Encrypt it */
        ctx = EVP_CIPHER_CTX_new();
        EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
@@ -216,13 +321,12 @@ odp_crypto_alg_err_t cipher_encrypt(odp_crypto_op_param_t 
*param,
        EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
        EVP_CIPHER_CTX_set_padding(ctx, 0);
 
-       EVP_EncryptUpdate(ctx, data, &cipher_len, data, plain_len);
-
-       EVP_EncryptFinal_ex(ctx, data + cipher_len, &cipher_len);
+       ret = internal_encrypt(ctx, param);
 
        EVP_CIPHER_CTX_free(ctx);
 
-       return ODP_CRYPTO_ALG_ERR_NONE;
+       return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
+                         ODP_CRYPTO_ALG_ERR_NONE;
 }
 
 static
@@ -230,10 +334,8 @@ odp_crypto_alg_err_t cipher_decrypt(odp_crypto_op_param_t 
*param,
                                    odp_crypto_generic_session_t *session)
 {
        EVP_CIPHER_CTX *ctx;
-       uint8_t *data  = odp_packet_data(param->out_pkt);
-       uint32_t cipher_len   = param->cipher_range.length;
-       int plain_len = 0;
        void *iv_ptr;
+       int ret;
 
        if (param->override_iv_ptr)
                iv_ptr = param->override_iv_ptr;
@@ -242,9 +344,6 @@ odp_crypto_alg_err_t cipher_decrypt(odp_crypto_op_param_t 
*param,
        else
                return ODP_CRYPTO_ALG_ERR_IV_INVALID;
 
-       /* Adjust pointer for beginning of area to cipher/auth */
-       data += param->cipher_range.offset;
-
        /* Decrypt it */
        ctx = EVP_CIPHER_CTX_new();
        EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
@@ -252,13 +351,12 @@ odp_crypto_alg_err_t cipher_decrypt(odp_crypto_op_param_t 
*param,
        EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
        EVP_CIPHER_CTX_set_padding(ctx, 0);
 
-       EVP_DecryptUpdate(ctx, data, &plain_len, data, cipher_len);
-
-       EVP_DecryptFinal_ex(ctx, data + plain_len, &plain_len);
+       ret = internal_decrypt(ctx, param);
 
        EVP_CIPHER_CTX_free(ctx);
 
-       return ODP_CRYPTO_ALG_ERR_NONE;
+       return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
+                         ODP_CRYPTO_ALG_ERR_NONE;
 }
 
 static int process_cipher_param(odp_crypto_generic_session_t *session,
@@ -293,13 +391,12 @@ odp_crypto_alg_err_t 
aes_gcm_encrypt(odp_crypto_op_param_t *param,
                                     odp_crypto_generic_session_t *session)
 {
        EVP_CIPHER_CTX *ctx;
-       uint8_t *data  = odp_packet_data(param->out_pkt);
-       uint32_t plain_len   = param->cipher_range.length;
        const uint8_t *aad_head = param->aad.ptr;
        uint32_t aad_len = param->aad.length;
        void *iv_ptr;
-       int cipher_len = 0;
-       uint8_t *tag = data + param->hash_result_offset;
+       int dummy_len = 0;
+       uint8_t block[EVP_MAX_MD_SIZE];
+       int ret;
 
        if (param->override_iv_ptr)
                iv_ptr = param->override_iv_ptr;
@@ -308,9 +405,6 @@ odp_crypto_alg_err_t aes_gcm_encrypt(odp_crypto_op_param_t 
*param,
        else
                return ODP_CRYPTO_ALG_ERR_IV_INVALID;
 
-       /* Adjust pointer for beginning of area to cipher/auth */
-       data += param->cipher_range.offset;
-
        /* Encrypt it */
        ctx = EVP_CIPHER_CTX_new();
        EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
@@ -322,18 +416,20 @@ odp_crypto_alg_err_t 
aes_gcm_encrypt(odp_crypto_op_param_t *param,
 
        /* Authenticate header data (if any) without encrypting them */
        if (aad_len > 0)
-               EVP_EncryptUpdate(ctx, NULL, &cipher_len,
+               EVP_EncryptUpdate(ctx, NULL, &dummy_len,
                                  aad_head, aad_len);
 
-       EVP_EncryptUpdate(ctx, data, &cipher_len, data, plain_len);
+       ret = internal_encrypt(ctx, param);
 
-       EVP_EncryptFinal_ex(ctx, data + cipher_len, &cipher_len);
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
-                           session->p.auth_digest_len, tag);
+                           session->p.auth_digest_len, block);
+       odp_packet_copy_from_mem(param->out_pkt, param->hash_result_offset,
+                                session->p.auth_digest_len, block);
 
        EVP_CIPHER_CTX_free(ctx);
 
-       return ODP_CRYPTO_ALG_ERR_NONE;
+       return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
+                         ODP_CRYPTO_ALG_ERR_NONE;
 }
 
 static
@@ -341,13 +437,12 @@ odp_crypto_alg_err_t 
aes_gcm_decrypt(odp_crypto_op_param_t *param,
                                     odp_crypto_generic_session_t *session)
 {
        EVP_CIPHER_CTX *ctx;
-       uint8_t *data  = odp_packet_data(param->out_pkt);
-       uint32_t cipher_len   = param->cipher_range.length;
        const uint8_t *aad_head = param->aad.ptr;
        uint32_t aad_len = param->aad.length;
-       int plain_len = 0;
+       int dummy_len = 0;
        void *iv_ptr;
-       uint8_t *tag   = data + param->hash_result_offset;
+       uint8_t block[EVP_MAX_MD_SIZE];
+       int ret;
 
        if (param->override_iv_ptr)
                iv_ptr = param->override_iv_ptr;
@@ -356,9 +451,6 @@ odp_crypto_alg_err_t aes_gcm_decrypt(odp_crypto_op_param_t 
*param,
        else
                return ODP_CRYPTO_ALG_ERR_IV_INVALID;
 
-       /* Adjust pointer for beginning of area to cipher/auth */
-       data += param->cipher_range.offset;
-
        /* Decrypt it */
        ctx = EVP_CIPHER_CTX_new();
        EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
@@ -368,22 +460,22 @@ odp_crypto_alg_err_t 
aes_gcm_decrypt(odp_crypto_op_param_t *param,
        EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
        EVP_CIPHER_CTX_set_padding(ctx, 0);
 
+       odp_packet_copy_to_mem(param->out_pkt, param->hash_result_offset,
+                              session->p.auth_digest_len, block);
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG,
-                           session->p.auth_digest_len, tag);
+                           session->p.auth_digest_len, block);
 
        /* Authenticate header data (if any) without encrypting them */
        if (aad_len > 0)
-               EVP_DecryptUpdate(ctx, NULL, &plain_len,
+               EVP_DecryptUpdate(ctx, NULL, &dummy_len,
                                  aad_head, aad_len);
 
-       EVP_DecryptUpdate(ctx, data, &plain_len, data, cipher_len);
-
-       if (EVP_DecryptFinal_ex(ctx, data + plain_len, &plain_len) <= 0)
-               return ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+       ret = internal_decrypt(ctx, param);
 
        EVP_CIPHER_CTX_free(ctx);
 
-       return ODP_CRYPTO_ALG_ERR_NONE;
+       return ret <= 0 ? ODP_CRYPTO_ALG_ERR_ICV_CHECK :
+                         ODP_CRYPTO_ALG_ERR_NONE;
 }
 
 static int process_aes_gcm_param(odp_crypto_generic_session_t *session,
-- 
2.11.0

Reply via email to