aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/odp_crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/odp_crypto.c')
-rw-r--r--platform/linux-generic/odp_crypto.c770
1 files changed, 370 insertions, 400 deletions
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index 54b222fd2..6fc1907d9 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -34,6 +34,9 @@
*
* Keep sorted: first by key length, then by IV length
*/
+static const odp_crypto_cipher_capability_t cipher_capa_null[] = {
+{.key_len = 0, .iv_len = 0} };
+
static const odp_crypto_cipher_capability_t cipher_capa_des[] = {
{.key_len = 24, .iv_len = 8} };
@@ -51,11 +54,24 @@ static const odp_crypto_cipher_capability_t cipher_capa_aes_gcm[] = {
*
* Keep sorted: first by digest length, then by key length
*/
+static const odp_crypto_auth_capability_t auth_capa_null[] = {
+{.digest_len = 0, .key_len = 0, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
+
static const odp_crypto_auth_capability_t auth_capa_md5_hmac[] = {
-{.digest_len = 12, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
+{.digest_len = 12, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 16, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
+
+static const odp_crypto_auth_capability_t auth_capa_sha1_hmac[] = {
+{.digest_len = 12, .key_len = 20, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 20, .key_len = 20, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
static const odp_crypto_auth_capability_t auth_capa_sha256_hmac[] = {
-{.digest_len = 16, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
+{.digest_len = 16, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 32, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
+
+static const odp_crypto_auth_capability_t auth_capa_sha512_hmac[] = {
+{.digest_len = 32, .key_len = 64, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 64, .key_len = 64, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
static const odp_crypto_auth_capability_t auth_capa_aes_gcm[] = {
{.digest_len = 16, .key_len = 0, .aad_len = {.min = 8, .max = 12, .inc = 4} } };
@@ -86,8 +102,10 @@ odp_crypto_generic_session_t *alloc_session(void)
odp_spinlock_lock(&global->lock);
session = global->free;
- if (session)
+ if (session) {
global->free = session->next;
+ session->next = NULL;
+ }
odp_spinlock_unlock(&global->lock);
return session;
@@ -110,128 +128,74 @@ null_crypto_routine(odp_crypto_op_param_t *param ODP_UNUSED,
}
static
-odp_crypto_alg_err_t md5_gen(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+void packet_hmac(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session,
+ uint8_t *hash)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint8_t *icv = data;
+ odp_packet_t pkt = param->out_pkt;
+ uint32_t offset = param->auth_range.offset;
uint32_t len = param->auth_range.length;
- uint8_t hash[EVP_MAX_MD_SIZE];
+ HMAC_CTX ctx;
- /* Adjust pointer for beginning of area to auth */
- data += param->auth_range.offset;
- icv += param->hash_result_offset;
+ ODP_ASSERT(offset + len <= odp_packet_len(pkt));
/* Hash it */
- HMAC(EVP_md5(),
- session->auth.data.md5.key,
- 16,
- data,
- len,
- hash,
- NULL);
-
- /* Copy to the output location */
- memcpy(icv, hash, session->auth.data.md5.bytes);
-
- return ODP_CRYPTO_ALG_ERR_NONE;
-}
-
-static
-odp_crypto_alg_err_t md5_check(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
-{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint8_t *icv = data;
- uint32_t len = param->auth_range.length;
- uint32_t bytes = session->auth.data.md5.bytes;
- uint8_t hash_in[EVP_MAX_MD_SIZE];
- uint8_t hash_out[EVP_MAX_MD_SIZE];
-
- /* Adjust pointer for beginning of area to auth */
- data += param->auth_range.offset;
- icv += param->hash_result_offset;
-
- /* Copy current value out and clear it before authentication */
- memset(hash_in, 0, sizeof(hash_in));
- memcpy(hash_in, icv, bytes);
- memset(icv, 0, bytes);
- memset(hash_out, 0, sizeof(hash_out));
-
- /* Hash it */
- HMAC(EVP_md5(),
- session->auth.data.md5.key,
- 16,
- data,
- len,
- hash_out,
- NULL);
-
- /* Verify match */
- if (0 != memcmp(hash_in, hash_out, bytes))
- return ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx,
+ session->auth.key,
+ session->auth.key_length,
+ session->auth.evp_md,
+ NULL);
+
+ while (len > 0) {
+ uint32_t seglen = 0; /* GCC */
+ void *mapaddr = odp_packet_offset(pkt, offset, &seglen, NULL);
+ uint32_t maclen = len > seglen ? seglen : len;
+
+ HMAC_Update(&ctx, mapaddr, maclen);
+ offset += maclen;
+ len -= maclen;
+ }
- /* Matched */
- return ODP_CRYPTO_ALG_ERR_NONE;
+ HMAC_Final(&ctx, hash, NULL);
+ HMAC_CTX_cleanup(&ctx);
}
static
-odp_crypto_alg_err_t sha256_gen(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+odp_crypto_alg_err_t auth_gen(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint8_t *icv = data;
- uint32_t len = param->auth_range.length;
uint8_t hash[EVP_MAX_MD_SIZE];
- /* Adjust pointer for beginning of area to auth */
- data += param->auth_range.offset;
- icv += param->hash_result_offset;
-
/* Hash it */
- HMAC(EVP_sha256(),
- session->auth.data.sha256.key,
- 32,
- data,
- len,
- hash,
- NULL);
+ packet_hmac(param, session, hash);
/* Copy to the output location */
- memcpy(icv, hash, session->auth.data.sha256.bytes);
+ odp_packet_copy_from_mem(param->out_pkt,
+ param->hash_result_offset,
+ session->auth.bytes,
+ hash);
return ODP_CRYPTO_ALG_ERR_NONE;
}
static
-odp_crypto_alg_err_t sha256_check(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+odp_crypto_alg_err_t auth_check(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint8_t *icv = data;
- uint32_t len = param->auth_range.length;
- uint32_t bytes = session->auth.data.sha256.bytes;
+ uint32_t bytes = session->auth.bytes;
uint8_t hash_in[EVP_MAX_MD_SIZE];
uint8_t hash_out[EVP_MAX_MD_SIZE];
- /* Adjust pointer for beginning of area to auth */
- data += param->auth_range.offset;
- icv += param->hash_result_offset;
-
/* Copy current value out and clear it before authentication */
- memset(hash_in, 0, sizeof(hash_in));
- memcpy(hash_in, icv, bytes);
- memset(icv, 0, bytes);
- memset(hash_out, 0, sizeof(hash_out));
+ odp_packet_copy_to_mem(param->out_pkt, param->hash_result_offset,
+ bytes, hash_in);
+
+ _odp_packet_set_data(param->out_pkt, param->hash_result_offset,
+ 0, bytes);
/* Hash it */
- HMAC(EVP_sha256(),
- session->auth.data.sha256.key,
- 32,
- data,
- len,
- hash_out,
- NULL);
+ packet_hmac(param, session, hash_out);
/* Verify match */
if (0 != memcmp(hash_in, hash_out, bytes))
@@ -242,102 +206,122 @@ odp_crypto_alg_err_t sha256_check(odp_crypto_op_param_t *param,
}
static
-odp_crypto_alg_err_t aes_encrypt(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+int internal_encrypt(EVP_CIPHER_CTX *ctx, odp_crypto_op_param_t *param)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint32_t len = param->cipher_range.length;
- unsigned char iv_enc[AES_BLOCK_SIZE];
- void *iv_ptr;
+ 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;
- if (param->override_iv_ptr)
- iv_ptr = param->override_iv_ptr;
- else if (session->p.iv.data)
- iv_ptr = session->cipher.iv_data;
- else
- return ODP_CRYPTO_ALG_ERR_IV_INVALID;
+ 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;
- /*
- * 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);
+ /* There should be at least 1 additional block in out buffer */
+ if (inseglen > block_len) {
+ unsigned part = inseglen - block_len;
- /* Adjust pointer for beginning of area to cipher */
- data += param->cipher_range.offset;
- /* Encrypt it */
- AES_cbc_encrypt(data, data, len, &session->cipher.data.aes.key,
- iv_enc, AES_ENCRYPT);
+ EVP_EncryptUpdate(ctx, insegaddr, &cipher_len,
+ insegaddr, part);
+ in_pos += part;
+ in_len -= part;
+ insegaddr += part;
+ inseglen -= part;
- return ODP_CRYPTO_ALG_ERR_NONE;
+ 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
-odp_crypto_alg_err_t aes_decrypt(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+int internal_decrypt(EVP_CIPHER_CTX *ctx, odp_crypto_op_param_t *param)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint32_t len = param->cipher_range.length;
- unsigned char iv_enc[AES_BLOCK_SIZE];
- void *iv_ptr;
+ 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;
- if (param->override_iv_ptr)
- iv_ptr = param->override_iv_ptr;
- else if (session->p.iv.data)
- iv_ptr = session->cipher.iv_data;
- else
- return ODP_CRYPTO_ALG_ERR_IV_INVALID;
+ 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;
- /*
- * 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);
+ /* There should be at least 1 additional block in out buffer */
+ if (inseglen > block_len) {
+ unsigned part = inseglen - block_len;
- /* Adjust pointer for beginning of area to cipher */
- data += param->cipher_range.offset;
- /* Encrypt it */
- AES_cbc_encrypt(data, data, len, &session->cipher.data.aes.key,
- iv_enc, AES_DECRYPT);
+ EVP_DecryptUpdate(ctx, insegaddr, &cipher_len,
+ insegaddr, part);
+ in_pos += part;
+ in_len -= part;
+ insegaddr += part;
+ inseglen -= part;
- return ODP_CRYPTO_ALG_ERR_NONE;
-}
+ out_pos += cipher_len;
+ }
-static int process_aes_param(odp_crypto_generic_session_t *session)
-{
- /* Verify IV len is either 0 or 16 */
- if (!((0 == session->p.iv.length) || (16 == session->p.iv.length)))
- return -1;
+ /* Use temporal storage */
+ if (inseglen > 0) {
+ unsigned part = inseglen;
- /* Set function */
- if (ODP_CRYPTO_OP_ENCODE == session->p.op) {
- session->cipher.func = aes_encrypt;
- AES_set_encrypt_key(session->p.cipher_key.data, 128,
- &session->cipher.data.aes.key);
- } else {
- session->cipher.func = aes_decrypt;
- AES_set_decrypt_key(session->p.cipher_key.data, 128,
- &session->cipher.data.aes.key);
+ 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;
+ }
}
- return 0;
+ 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 aes_gcm_encrypt(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+odp_crypto_alg_err_t cipher_encrypt(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint32_t plain_len = param->cipher_range.length;
- uint8_t *aad_head = data + param->auth_range.offset;
- uint8_t *aad_tail = data + param->cipher_range.offset +
- param->cipher_range.length;
- uint32_t auth_len = param->auth_range.length;
- unsigned char iv_enc[AES_BLOCK_SIZE];
+ EVP_CIPHER_CTX *ctx;
void *iv_ptr;
- uint8_t *tag = data + param->hash_result_offset;
+ int ret;
if (param->override_iv_ptr)
iv_ptr = param->override_iv_ptr;
@@ -346,63 +330,28 @@ odp_crypto_alg_err_t aes_gcm_encrypt(odp_crypto_op_param_t *param,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* All cipher data must be part of the authentication */
- if (param->auth_range.offset > param->cipher_range.offset ||
- param->auth_range.offset + auth_len <
- param->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 + param->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);
- }
+ ctx = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
- EVP_EncryptUpdate(ctx, plaindata, &cipher_len,
- plaindata, plain_len);
- cipher_len = plain_len;
+ ret = internal_encrypt(ctx, param);
- /* 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_CIPHER_CTX_free(ctx);
- 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;
+ return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
+ ODP_CRYPTO_ALG_ERR_NONE;
}
static
-odp_crypto_alg_err_t aes_gcm_decrypt(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+odp_crypto_alg_err_t cipher_decrypt(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint32_t cipher_len = param->cipher_range.length;
- uint8_t *aad_head = data + param->auth_range.offset;
- uint8_t *aad_tail = data + param->cipher_range.offset +
- param->cipher_range.length;
- uint32_t auth_len = param->auth_range.length;
- unsigned char iv_enc[AES_BLOCK_SIZE];
+ EVP_CIPHER_CTX *ctx;
void *iv_ptr;
- uint8_t *tag = data + param->hash_result_offset;
+ int ret;
if (param->override_iv_ptr)
iv_ptr = param->override_iv_ptr;
@@ -411,90 +360,59 @@ odp_crypto_alg_err_t aes_gcm_decrypt(odp_crypto_op_param_t *param,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* All cipher data must be part of the authentication */
- if (param->auth_range.offset > param->cipher_range.offset ||
- param->auth_range.offset + auth_len <
- param->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 + param->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);
-
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
-
- /* 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;
+ /* Decrypt it */
+ ctx = EVP_CIPHER_CTX_new();
+ EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
- /* 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));
- }
+ ret = internal_decrypt(ctx, param);
- if (EVP_DecryptFinal_ex(ctx, cipherdata + cipher_len, &plain_len) < 0)
- return ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+ 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_aes_gcm_param(odp_crypto_generic_session_t *session)
+static int process_cipher_param(odp_crypto_generic_session_t *session,
+ const EVP_CIPHER *cipher)
{
- /* Verify Key len is 16 */
- if (session->p.cipher_key.length != 16)
+ /* Verify Key len is valid */
+ if ((uint32_t)EVP_CIPHER_key_length(cipher) !=
+ session->p.cipher_key.length)
return -1;
- /* Set function */
- EVP_CIPHER_CTX *ctx =
- session->cipher.data.aes_gcm.ctx = EVP_CIPHER_CTX_new();
+ /* Verify IV len is correct */
+ if (!((0 == session->p.iv.length) ||
+ ((uint32_t)EVP_CIPHER_iv_length(cipher) == session->p.iv.length)))
+ return -1;
- if (ODP_CRYPTO_OP_ENCODE == session->p.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);
- }
+ session->cipher.evp_cipher = cipher;
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
- session->p.iv.length, NULL);
- if (ODP_CRYPTO_OP_ENCODE == session->p.op) {
- EVP_EncryptInit_ex(ctx, NULL, NULL,
- session->p.cipher_key.data, NULL);
- } else {
- EVP_DecryptInit_ex(ctx, NULL, NULL,
- session->p.cipher_key.data, NULL);
- }
+ memcpy(session->cipher.key_data, session->p.cipher_key.data,
+ session->p.cipher_key.length);
+
+ /* Set function */
+ if (ODP_CRYPTO_OP_ENCODE == session->p.op)
+ session->cipher.func = cipher_encrypt;
+ else
+ session->cipher.func = cipher_decrypt;
return 0;
}
static
-odp_crypto_alg_err_t des_encrypt(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+odp_crypto_alg_err_t aes_gcm_encrypt(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint32_t len = param->cipher_range.length;
- DES_cblock iv;
+ EVP_CIPHER_CTX *ctx;
+ const uint8_t *aad_head = param->aad.ptr;
+ uint32_t aad_len = param->aad.length;
void *iv_ptr;
+ int dummy_len = 0;
+ uint8_t block[EVP_MAX_MD_SIZE];
+ int ret;
if (param->override_iv_ptr)
iv_ptr = param->override_iv_ptr;
@@ -503,36 +421,44 @@ odp_crypto_alg_err_t des_encrypt(odp_crypto_op_param_t *param,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /*
- * 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, iv_ptr, sizeof(iv));
-
- /* Adjust pointer for beginning of area to cipher */
- data += param->cipher_range.offset;
/* 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);
+ ctx = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ session->p.iv.length, NULL);
+ EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
- return ODP_CRYPTO_ALG_ERR_NONE;
+ /* Authenticate header data (if any) without encrypting them */
+ if (aad_len > 0)
+ EVP_EncryptUpdate(ctx, NULL, &dummy_len,
+ aad_head, aad_len);
+
+ ret = internal_encrypt(ctx, param);
+
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_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 ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
+ ODP_CRYPTO_ALG_ERR_NONE;
}
static
-odp_crypto_alg_err_t des_decrypt(odp_crypto_op_param_t *param,
- odp_crypto_generic_session_t *session)
+odp_crypto_alg_err_t aes_gcm_decrypt(odp_crypto_op_param_t *param,
+ odp_crypto_generic_session_t *session)
{
- uint8_t *data = odp_packet_data(param->out_pkt);
- uint32_t len = param->cipher_range.length;
- DES_cblock iv;
+ EVP_CIPHER_CTX *ctx;
+ const uint8_t *aad_head = param->aad.ptr;
+ uint32_t aad_len = param->aad.length;
+ int dummy_len = 0;
void *iv_ptr;
+ uint8_t block[EVP_MAX_MD_SIZE];
+ int ret;
if (param->override_iv_ptr)
iv_ptr = param->override_iv_ptr;
@@ -541,84 +467,76 @@ odp_crypto_alg_err_t des_decrypt(odp_crypto_op_param_t *param,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /*
- * 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, iv_ptr, sizeof(iv));
+ /* Decrypt it */
+ ctx = EVP_CIPHER_CTX_new();
+ EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ session->p.iv.length, NULL);
+ EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
- /* Adjust pointer for beginning of area to cipher */
- data += param->cipher_range.offset;
+ 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, block);
- /* 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);
+ /* Authenticate header data (if any) without encrypting them */
+ if (aad_len > 0)
+ EVP_DecryptUpdate(ctx, NULL, &dummy_len,
+ aad_head, aad_len);
- return ODP_CRYPTO_ALG_ERR_NONE;
+ ret = internal_decrypt(ctx, param);
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ return ret <= 0 ? ODP_CRYPTO_ALG_ERR_ICV_CHECK :
+ ODP_CRYPTO_ALG_ERR_NONE;
}
-static int process_des_param(odp_crypto_generic_session_t *session)
+static int process_aes_gcm_param(odp_crypto_generic_session_t *session,
+ const EVP_CIPHER *cipher)
{
- /* Verify IV len is either 0 or 8 */
- if (!((0 == session->p.iv.length) || (8 == session->p.iv.length)))
+ /* Verify Key len is valid */
+ if ((uint32_t)EVP_CIPHER_key_length(cipher) !=
+ session->p.cipher_key.length)
return -1;
- /* Set function */
- if (ODP_CRYPTO_OP_ENCODE == session->p.op)
- session->cipher.func = des_encrypt;
- else
- session->cipher.func = des_decrypt;
+ memcpy(session->cipher.key_data, session->p.cipher_key.data,
+ session->p.cipher_key.length);
- /* Convert keys */
- DES_set_key((DES_cblock *)&session->p.cipher_key.data[0],
- &session->cipher.data.des.ks1);
- DES_set_key((DES_cblock *)&session->p.cipher_key.data[8],
- &session->cipher.data.des.ks2);
- DES_set_key((DES_cblock *)&session->p.cipher_key.data[16],
- &session->cipher.data.des.ks3);
+ session->cipher.evp_cipher = cipher;
- return 0;
-}
-
-static int process_md5_param(odp_crypto_generic_session_t *session,
- uint32_t bits)
-{
/* Set function */
if (ODP_CRYPTO_OP_ENCODE == session->p.op)
- session->auth.func = md5_gen;
+ session->cipher.func = aes_gcm_encrypt;
else
- session->auth.func = md5_check;
-
- /* Number of valid bytes */
- session->auth.data.md5.bytes = bits / 8;
-
- /* Convert keys */
- memcpy(session->auth.data.md5.key, session->p.auth_key.data, 16);
+ session->cipher.func = aes_gcm_decrypt;
return 0;
}
-static int process_sha256_param(odp_crypto_generic_session_t *session,
- uint32_t bits)
+static int process_auth_param(odp_crypto_generic_session_t *session,
+ uint32_t key_length,
+ const EVP_MD *evp_md)
{
/* Set function */
if (ODP_CRYPTO_OP_ENCODE == session->p.op)
- session->auth.func = sha256_gen;
+ session->auth.func = auth_gen;
else
- session->auth.func = sha256_check;
+ session->auth.func = auth_check;
+
+ session->auth.evp_md = evp_md;
/* Number of valid bytes */
- session->auth.data.sha256.bytes = bits / 8;
+ session->auth.bytes = session->p.auth_digest_len;
+ if (session->auth.bytes < (unsigned)EVP_MD_size(evp_md) / 2)
+ return -1;
/* Convert keys */
- memcpy(session->auth.data.sha256.key, session->p.auth_key.data, 32);
+ session->auth.key_length = key_length;
+ memcpy(session->auth.key, session->p.auth_key.data,
+ session->auth.key_length);
return 0;
}
@@ -639,15 +557,18 @@ int odp_crypto_capability(odp_crypto_capability_t *capa)
capa->auths.bit.null = 1;
capa->auths.bit.md5_hmac = 1;
+ capa->auths.bit.sha1_hmac = 1;
capa->auths.bit.sha256_hmac = 1;
+ capa->auths.bit.sha512_hmac = 1;
capa->auths.bit.aes_gcm = 1;
- /* Deprecated */
+#if ODP_DEPRECATED_API
capa->ciphers.bit.aes128_cbc = 1;
capa->ciphers.bit.aes128_gcm = 1;
capa->auths.bit.md5_96 = 1;
capa->auths.bit.sha256_128 = 1;
capa->auths.bit.aes128_gcm = 1;
+#endif
capa->max_sessions = MAX_SESSIONS;
@@ -664,8 +585,8 @@ int odp_crypto_cipher_capability(odp_cipher_alg_t cipher,
switch (cipher) {
case ODP_CIPHER_ALG_NULL:
- src = NULL;
- num = 0;
+ src = cipher_capa_null;
+ num = sizeof(cipher_capa_null) / size;
break;
case ODP_CIPHER_ALG_DES:
src = cipher_capa_des;
@@ -704,17 +625,25 @@ int odp_crypto_auth_capability(odp_auth_alg_t auth,
switch (auth) {
case ODP_AUTH_ALG_NULL:
- src = NULL;
- num = 0;
+ src = auth_capa_null;
+ num = sizeof(auth_capa_null) / size;
break;
case ODP_AUTH_ALG_MD5_HMAC:
src = auth_capa_md5_hmac;
num = sizeof(auth_capa_md5_hmac) / size;
break;
+ case ODP_AUTH_ALG_SHA1_HMAC:
+ src = auth_capa_sha1_hmac;
+ num = sizeof(auth_capa_sha1_hmac) / size;
+ break;
case ODP_AUTH_ALG_SHA256_HMAC:
src = auth_capa_sha256_hmac;
num = sizeof(auth_capa_sha256_hmac) / size;
break;
+ case ODP_AUTH_ALG_SHA512_HMAC:
+ src = auth_capa_sha512_hmac;
+ num = sizeof(auth_capa_sha512_hmac) / size;
+ break;
case ODP_AUTH_ALG_AES_GCM:
src = auth_capa_aes_gcm;
num = sizeof(auth_capa_aes_gcm) / size;
@@ -738,6 +667,7 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
{
int rc;
odp_crypto_generic_session_t *session;
+ int aes_gcm = 0;
/* Default to successful result */
*status = ODP_CRYPTO_SES_CREATE_ERR_NONE;
@@ -752,16 +682,16 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
/* Copy parameters */
session->p = *param;
- /* Copy IV data */
- if (session->p.iv.data) {
- if (session->p.iv.length > MAX_IV_LEN) {
- ODP_DBG("Maximum IV length exceeded\n");
- return -1;
- }
+ if (session->p.iv.length > MAX_IV_LEN) {
+ ODP_DBG("Maximum IV length exceeded\n");
+ free_session(session);
+ return -1;
+ }
+ /* Copy IV data */
+ if (session->p.iv.data)
memcpy(session->cipher.iv_data, session->p.iv.data,
session->p.iv.length);
- }
/* Derive order */
if (ODP_CRYPTO_OP_ENCODE == param->op)
@@ -777,21 +707,25 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
break;
case ODP_CIPHER_ALG_DES:
case ODP_CIPHER_ALG_3DES_CBC:
- rc = process_des_param(session);
+ rc = process_cipher_param(session, EVP_des_ede3_cbc());
break;
case ODP_CIPHER_ALG_AES_CBC:
- /* deprecated */
+#if ODP_DEPRECATED_API
case ODP_CIPHER_ALG_AES128_CBC:
- rc = process_aes_param(session);
+#endif
+ rc = process_cipher_param(session, EVP_aes_128_cbc());
break;
- case ODP_CIPHER_ALG_AES_GCM:
- /* deprecated */
+#if ODP_DEPRECATED_API
case ODP_CIPHER_ALG_AES128_GCM:
+ if (param->auth_alg == ODP_AUTH_ALG_AES128_GCM)
+ aes_gcm = 1;
+ /* Fallthrough */
+#endif
+ case ODP_CIPHER_ALG_AES_GCM:
/* AES-GCM requires to do both auth and
* cipher at the same time */
- if (param->auth_alg == ODP_AUTH_ALG_AES_GCM ||
- param->auth_alg == ODP_AUTH_ALG_AES128_GCM)
- rc = process_aes_gcm_param(session);
+ if (param->auth_alg == ODP_AUTH_ALG_AES_GCM || aes_gcm)
+ rc = process_aes_gcm_param(session, EVP_aes_128_gcm());
else
rc = -1;
break;
@@ -802,32 +736,54 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
/* Check result */
if (rc) {
*status = ODP_CRYPTO_SES_CREATE_ERR_INV_CIPHER;
+ free_session(session);
return -1;
}
+ aes_gcm = 0;
+
/* Process based on auth */
switch (param->auth_alg) {
case ODP_AUTH_ALG_NULL:
session->auth.func = null_crypto_routine;
rc = 0;
break;
- case ODP_AUTH_ALG_MD5_HMAC:
- /* deprecated */
+#if ODP_DEPRECATED_API
case ODP_AUTH_ALG_MD5_96:
- rc = process_md5_param(session, 96);
+ /* Fixed digest tag length with deprecated algo */
+ session->p.auth_digest_len = 96 / 8;
+ /* Fallthrough */
+#endif
+ case ODP_AUTH_ALG_MD5_HMAC:
+ rc = process_auth_param(session, 16, EVP_md5());
break;
- case ODP_AUTH_ALG_SHA256_HMAC:
- /* deprecated */
+ case ODP_AUTH_ALG_SHA1_HMAC:
+ rc = process_auth_param(session, 20, EVP_sha1());
+ break;
+#if ODP_DEPRECATED_API
case ODP_AUTH_ALG_SHA256_128:
- rc = process_sha256_param(session, 128);
+ /* Fixed digest tag length with deprecated algo */
+ session->p.auth_digest_len = 128 / 8;
+ /* Fallthrough */
+#endif
+ case ODP_AUTH_ALG_SHA256_HMAC:
+ rc = process_auth_param(session, 32, EVP_sha256());
break;
- case ODP_AUTH_ALG_AES_GCM:
- /* deprecated */
+ case ODP_AUTH_ALG_SHA512_HMAC:
+ rc = process_auth_param(session, 64, EVP_sha512());
+ break;
+#if ODP_DEPRECATED_API
case ODP_AUTH_ALG_AES128_GCM:
+ if (param->cipher_alg == ODP_CIPHER_ALG_AES128_GCM)
+ aes_gcm = 1;
+ /* Fixed digest tag length with deprecated algo */
+ session->p.auth_digest_len = 16;
+ /* Fallthrough */
+#endif
+ case ODP_AUTH_ALG_AES_GCM:
/* AES-GCM requires to do both auth and
* cipher at the same time */
- if (param->cipher_alg == ODP_CIPHER_ALG_AES_GCM ||
- param->cipher_alg == ODP_CIPHER_ALG_AES128_GCM) {
+ if (param->cipher_alg == ODP_CIPHER_ALG_AES_GCM || aes_gcm) {
session->auth.func = null_crypto_routine;
rc = 0;
} else {
@@ -841,6 +797,7 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
/* Check result */
if (rc) {
*status = ODP_CRYPTO_SES_CREATE_ERR_INV_AUTH;
+ free_session(session);
return -1;
}
@@ -854,9 +811,6 @@ int odp_crypto_session_destroy(odp_crypto_session_t session)
odp_crypto_generic_session_t *generic;
generic = (odp_crypto_generic_session_t *)(intptr_t)session;
- if (generic->p.cipher_alg == ODP_CIPHER_ALG_AES128_GCM ||
- generic->p.cipher_alg == ODP_CIPHER_ALG_AES_GCM)
- EVP_CIPHER_CTX_free(generic->cipher.data.aes_gcm.ctx);
memset(generic, 0, sizeof(*generic));
free_session(generic);
return 0;
@@ -871,14 +825,17 @@ odp_crypto_operation(odp_crypto_op_param_t *param,
odp_crypto_alg_err_t rc_auth = ODP_CRYPTO_ALG_ERR_NONE;
odp_crypto_generic_session_t *session;
odp_crypto_op_result_t local_result;
+ odp_bool_t allocated = false;
session = (odp_crypto_generic_session_t *)(intptr_t)param->session;
/* Resolve output buffer */
if (ODP_PACKET_INVALID == param->out_pkt &&
- ODP_POOL_INVALID != session->p.output_pool)
+ ODP_POOL_INVALID != session->p.output_pool) {
param->out_pkt = odp_packet_alloc(session->p.output_pool,
odp_packet_len(param->pkt));
+ allocated = true;
+ }
if (odp_unlikely(ODP_PACKET_INVALID == param->out_pkt)) {
ODP_DBG("Alloc failed.\n");
@@ -886,11 +843,16 @@ odp_crypto_operation(odp_crypto_op_param_t *param,
}
if (param->pkt != param->out_pkt) {
- (void)odp_packet_copy_from_pkt(param->out_pkt,
+ int ret;
+
+ ret = odp_packet_copy_from_pkt(param->out_pkt,
0,
param->pkt,
0,
odp_packet_len(param->pkt));
+ if (odp_unlikely(ret < 0))
+ goto err;
+
_odp_packet_copy_md_to_packet(param->pkt, param->out_pkt);
odp_packet_free(param->pkt);
param->pkt = ODP_PACKET_INVALID;
@@ -932,7 +894,7 @@ odp_crypto_operation(odp_crypto_op_param_t *param,
op_result->result = local_result;
if (odp_queue_enq(session->p.compl_queue, completion_event)) {
odp_event_free(completion_event);
- return -1;
+ goto err;
}
/* Indicate to caller operation was async */
@@ -940,13 +902,21 @@ odp_crypto_operation(odp_crypto_op_param_t *param,
} else {
/* Synchronous, simply return results */
if (!result)
- return -1;
+ goto err;
*result = local_result;
/* Indicate to caller operation was sync */
*posted = 0;
}
return 0;
+
+err:
+ if (allocated) {
+ odp_packet_free(param->out_pkt);
+ param->out_pkt = ODP_PACKET_INVALID;
+ }
+
+ return -1;
}
static void ODP_UNUSED openssl_thread_id(CRYPTO_THREADID ODP_UNUSED *id)