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