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.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index 17fced930..65e850343 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;
}