blob: 3ab8ea21ab28e50e69e7084aee1dbf8818931b76 [file] [log] [blame]
/*
* Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <psa/crypto.h>
#include "psa_crypto_client.h"
#include "crypto_caller_selector.h"
psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
psa_key_id_t key,
psa_algorithm_t alg)
{
if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
return psa_crypto_client_instance.init_status;
if (operation->handle)
return PSA_ERROR_BAD_STATE;
return crypto_caller_cipher_encrypt_setup(&psa_crypto_client_instance.base,
&operation->handle,
key, alg);
}
psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
psa_key_id_t key,
psa_algorithm_t alg)
{
if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
return psa_crypto_client_instance.init_status;
if (operation->handle)
return PSA_ERROR_BAD_STATE;
return crypto_caller_cipher_decrypt_setup(&psa_crypto_client_instance.base,
&operation->handle,
key, alg);
}
psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
uint8_t *iv,
size_t iv_size,
size_t *iv_length)
{
return crypto_caller_cipher_generate_iv(&psa_crypto_client_instance.base,
operation->handle,
iv, iv_size, iv_length);
}
psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation,
const uint8_t *iv,
size_t iv_length)
{
return crypto_caller_cipher_set_iv(&psa_crypto_client_instance.base,
operation->handle,
iv, iv_length);
}
psa_status_t psa_cipher_update(psa_cipher_operation_t *operation,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
return crypto_caller_cipher_update(&psa_crypto_client_instance.base,
operation->handle,
input, input_length,
output, output_size, output_length);
}
psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
return crypto_caller_cipher_finish(&psa_crypto_client_instance.base,
operation->handle,
output, output_size, output_length);
}
psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation)
{
return crypto_caller_cipher_abort(&psa_crypto_client_instance.base,
operation->handle);
}
static psa_status_t multi_cipher_update(psa_cipher_operation_t *operation,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_status_t psa_status = PSA_SUCCESS;
size_t max_update_size =
crypto_caller_cipher_max_update_size(&psa_crypto_client_instance.base);
size_t bytes_input = 0;
size_t bytes_output = 0;
*output_length = 0;
if (!max_update_size) {
/* Don't know the max update size so assume that the entire
* input and output can be handled in a single update. If
* this isn't true, the first cipher update operation will fail
* safely.
*/
max_update_size = input_length;
}
while ((bytes_input < input_length) && (bytes_output < output_size)) {
size_t update_output_len = 0;
size_t bytes_remaining = input_length - bytes_input;
size_t update_len = (bytes_remaining < max_update_size) ?
bytes_remaining :
max_update_size;
psa_status = psa_cipher_update(operation,
&input[bytes_input], update_len,
&output[bytes_output], output_size - bytes_output, &update_output_len);
if (psa_status != PSA_SUCCESS) {
psa_cipher_abort(operation);
break;
}
bytes_input += update_len;
bytes_output += update_output_len;
}
if (psa_status == PSA_SUCCESS) {
if (bytes_output < output_size) {
size_t finish_output_len = 0;
psa_status = psa_cipher_finish(operation,
&output[bytes_output], output_size - bytes_output, &finish_output_len);
if (psa_status == PSA_SUCCESS) {
*output_length = bytes_output + finish_output_len;
}
}
else {
psa_cipher_abort(operation);
psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
}
}
return psa_status;
}
psa_status_t psa_cipher_encrypt(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_cipher_operation_t operation = psa_cipher_operation_init();
psa_status_t psa_status = psa_cipher_encrypt_setup(&operation, key, alg);
if (psa_status == PSA_SUCCESS) {
psa_status = multi_cipher_update(&operation,
input, input_length,
output, output_size, output_length);
}
return psa_status;
}
psa_status_t psa_cipher_decrypt(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_cipher_operation_t operation = psa_cipher_operation_init();
psa_status_t psa_status = psa_cipher_decrypt_setup(&operation, key, alg);
if (psa_status == PSA_SUCCESS) {
psa_status = multi_cipher_update(&operation,
input, input_length,
output, output_size, output_length);
}
return psa_status;
}