YACA_BCM_CBC,
/**
- * GCM block cipher mode, IV is needed.
+ * GCM block cipher mode.
+ * This is a variable IV length mode (recommended 96 bits IV).
+ *
* Supported parameters:
- * - #YACA_PARAM_GCM_TAG = GCM tag
- * - #YACA_PARAM_GCM_TAG_LEN = GCM tag length
- * - #YACA_PARAM_GCM_AAD = additional authentication data(optional)
+ * - #YACA_PARAM_GCM_TAG_LEN = GCM tag length\n
+ * Supported tag lengths: @c 32, @c 64, @c 96, @c 104, @c 112, @c 120, @c 128,
+ * (recommended 128 bits tag).\n
+ * Set after yaca_encrypt_final() and before yaca_ctx_get_param(#YACA_PARAM_GCM_TAG)
+ * in encryption operation.\n\n
+ *
+ * - #YACA_PARAM_GCM_TAG = GCM tag\n
+ * Get after yaca_encrypt_final() in encryption operation.\n
+ * Set before yaca_decrypt_final() in decryption operation.\n\n
+ *
+ * - #YACA_PARAM_GCM_AAD = additional authentication data (optional)\n
+ * Set after yaca_encrypt_init() and before yaca_encrypt_update()
+ * in encryption operation.\n
+ * Set after yaca_decrypt_init() and before yaca_decrypt_update()
+ * in decryption operation.\n\n
+ *
+ * @see examples/encrypt_aes_gcm_ccm.c
*/
YACA_BCM_GCM,
/**
* CBC-MAC Mode (AES).
+ * This is a variable IV length mode.\n
+ * Supported IV lengths: 56-104 bits in steps of 8 bits (recommended 56 bits IV).\n\n
+ *
* Supported parameters:
- * - #YACA_PARAM_CCM_TAG = CCM tag
- * - #YACA_PARAM_CCM_TAG_LEN = CCM tag length
- * - #YACA_PARAM_CCM_AAD = additional authentication data(optional)
+ * - #YACA_PARAM_CCM_TAG_LEN = CCM tag length\n
+ * Supported tag lengths: 32-128 bits in step of 16 bits (recommended 96 bits tag).\n
+ * Set after yaca_encrypt_init() and before yaca_encrypt_update()
+ * in encryption operation.\n\n
+ *
+ * - #YACA_PARAM_CCM_TAG = CCM tag\n
+ * Get after yaca_encrypt_final() in encryption operation.\n
+ * Set after yaca_decrypt_init() and before yaca_decrypt_update()
+ * in decryption operation.\n\n
+ *
+ * - #YACA_PARAM_CCM_AAD = additional authentication data (optional)\n
+ * The total plain text length must be passed to yaca_encrypt_update()
+ * if AAD is used.\n
+ * Set after yaca_encrypt_init() and before yaca_encrypt_update()
+ * in encryption operation.\n
+ * You can only call yaca_encrypt_update() once for AAD and once for the plain text.\n\n
+ *
+ * The total encrypted text length must be passed to yaca_decrypt_update()
+ * if AAD is used.\n
+ * Set after yaca_decrypt_init() and before yaca_decrypt_update()
+ * in decryption operation.\n\n
+ *
+ * @see examples/encrypt_aes_gcm_ccm.c
*/
YACA_BCM_CCM
EVP_CIPHER_CTX *cipher_ctx;
enum encrypt_op_type op_type; /* Operation context was created for */
+ size_t tag_len;
};
static struct yaca_encrypt_ctx_s *get_encrypt_ctx(const yaca_ctx_h ctx)
struct yaca_encrypt_ctx_s *nc = get_encrypt_ctx(ctx);
int block_size;
- if (nc == NULL || nc->cipher_ctx == NULL)
+ if (nc == NULL)
return YACA_ERROR_INVALID_ARGUMENT;
+ assert(nc->cipher_ctx != NULL);
block_size = EVP_CIPHER_CTX_block_size(nc->cipher_ctx);
if (block_size <= 0) {
return 0;
}
+static int set_encrypt_param(yaca_ctx_h ctx,
+ yaca_ex_param_e param,
+ const void *value,
+ size_t value_len)
+{
+ struct yaca_encrypt_ctx_s *c = get_encrypt_ctx(ctx);
+ int len;
+
+ if (c == NULL || value == NULL)
+ return YACA_ERROR_INVALID_ARGUMENT;
+ assert(c->cipher_ctx != NULL);
+
+ switch(param)
+ {
+ case YACA_PARAM_GCM_AAD:
+ case YACA_PARAM_CCM_AAD:
+ if (EVP_EncryptUpdate(c->cipher_ctx, NULL, &len, value, value_len) != 1) {
+ ERROR_DUMP(YACA_ERROR_INTERNAL);
+ return YACA_ERROR_INTERNAL;
+ }
+ break;
+ case YACA_PARAM_GCM_TAG:
+ if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
+ EVP_CTRL_GCM_SET_TAG,
+ value_len, (void*)value) != 1) {
+ ERROR_DUMP(YACA_ERROR_INTERNAL);
+ return YACA_ERROR_INTERNAL;
+ }
+ break;
+ case YACA_PARAM_GCM_TAG_LEN:
+ c->tag_len = *(int*)value;
+ break;
+ case YACA_PARAM_CCM_TAG:
+ // TODO Rebuild context
+ if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
+ EVP_CTRL_CCM_SET_TAG,
+ value_len, (void*)value) != 1) {
+ ERROR_DUMP(YACA_ERROR_INTERNAL);
+ return YACA_ERROR_INTERNAL;
+ }
+ break;
+ case YACA_PARAM_CCM_TAG_LEN:
+ //TODO Rebuild context
+ if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
+ EVP_CTRL_CCM_SET_TAG,
+ value_len, NULL) != 1) {
+ ERROR_DUMP(YACA_ERROR_INTERNAL);
+ return YACA_ERROR_INTERNAL;
+ }
+ c->tag_len = *(int*)value;
+ break;
+ default:
+ return YACA_ERROR_INVALID_ARGUMENT;
+ }
+ return 0;
+}
+
+static int get_encrypt_param(const yaca_ctx_h ctx,
+ yaca_ex_param_e param,
+ void **value,
+ size_t *value_len)
+{
+ struct yaca_encrypt_ctx_s *c = get_encrypt_ctx(ctx);
+
+ if (c == NULL || value == NULL || value_len == NULL)
+ return YACA_ERROR_INVALID_ARGUMENT;
+ assert(c->cipher_ctx != NULL);
+
+ switch(param)
+ {
+ case YACA_PARAM_GCM_TAG:
+ if (c->tag_len == 0)
+ return YACA_ERROR_INVALID_ARGUMENT;
+
+ if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
+ EVP_CTRL_GCM_GET_TAG,
+ c->tag_len, value) != 1) {
+ ERROR_DUMP(YACA_ERROR_INTERNAL);
+ return YACA_ERROR_INTERNAL;
+ }
+ *value_len = c->tag_len;
+ break;
+ case YACA_PARAM_CCM_TAG:
+ if (c->tag_len == 0)
+ return YACA_ERROR_INVALID_ARGUMENT;
+
+ if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
+ EVP_CTRL_CCM_GET_TAG,
+ c->tag_len, value) != 1) {
+ ERROR_DUMP(YACA_ERROR_INTERNAL);
+ return YACA_ERROR_INTERNAL;
+ }
+ *value_len = c->tag_len;
+ break;
+ default:
+ return YACA_ERROR_INVALID_ARGUMENT;
+ break;
+ }
+ return 0;
+}
+
static const char *encrypt_algo_to_str(yaca_enc_algo_e algo)
{
switch(algo)
nc->ctx.type = YACA_CTX_ENCRYPT;
nc->ctx.ctx_destroy = destroy_encrypt_ctx;
nc->ctx.get_output_length = get_encrypt_output_length;
+ nc->ctx.set_param = set_encrypt_param;
+ nc->ctx.get_param = get_encrypt_param;
nc->op_type = op_type;
+ nc->tag_len = 0;
ret = yaca_key_get_bits(sym_key, &key_bits);
if (ret != 0)
ret = YACA_ERROR_INVALID_ARGUMENT;
goto err_free;
}
- if (iv_bits != iv_bits_check) { /* IV length doesn't match cipher */
+ /* IV length doesn't match cipher (GCM & CCM supports variable IV length) */
+ if (iv_bits != iv_bits_check &&
+ bcm != YACA_BCM_GCM &&
+ bcm != YACA_BCM_CCM) {
ret = YACA_ERROR_INVALID_ARGUMENT;
goto err_free;
}
switch (op_type) {
case OP_ENCRYPT:
ret = EVP_EncryptInit_ex(nc->cipher_ctx, cipher, NULL, NULL, NULL);
- if (ret != 1)
- break;
+ break;
+ case OP_DECRYPT:
+ ret = EVP_DecryptInit_ex(nc->cipher_ctx, cipher, NULL, NULL, NULL);
+ break;
+ default:
+ ret = YACA_ERROR_INVALID_ARGUMENT;
+ goto err_ctx;
+ }
+
+ if (ret != 1) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ goto err_ctx;
+ }
+
+ /* Handling of algorithms with variable key length */
+ ret = EVP_CIPHER_CTX_set_key_length(nc->cipher_ctx, key_bits / 8);
+ if (ret != 1) {
+ ret = YACA_ERROR_INVALID_ARGUMENT;
+ ERROR_DUMP(ret);
+ goto err_ctx;
+ }
+
+ /* Handling of algorithms with variable IV length */
+ if (iv_bits != iv_bits_check) {
+ if (bcm == YACA_BCM_GCM)
+ ret = EVP_CIPHER_CTX_ctrl(nc->cipher_ctx, EVP_CTRL_GCM_SET_IVLEN,
+ iv_bits_check / 8, NULL);
+
+ if (bcm == YACA_BCM_CCM)
+ ret = EVP_CIPHER_CTX_ctrl(nc->cipher_ctx, EVP_CTRL_CCM_SET_IVLEN,
+ iv_bits_check / 8, NULL);
- /* Handling of algorithms with variable key length */
- ret = EVP_CIPHER_CTX_set_key_length(nc->cipher_ctx, key_bits / 8);
if (ret != 1) {
ret = YACA_ERROR_INVALID_ARGUMENT;
ERROR_DUMP(ret);
goto err_ctx;
}
+ }
+ switch (op_type) {
+ case OP_ENCRYPT:
ret = EVP_EncryptInit_ex(nc->cipher_ctx, NULL, NULL,
(unsigned char*)lkey->d,
iv_data);
-
break;
case OP_DECRYPT:
- ret = EVP_DecryptInit_ex(nc->cipher_ctx, cipher, NULL, NULL, NULL);
- if (ret != 1)
- break;
-
- /* Handling of algorithms with variable key length */
- ret = EVP_CIPHER_CTX_set_key_length(nc->cipher_ctx, key_bits / 8);
- if (ret != 1) {
- ret = YACA_ERROR_INVALID_ARGUMENT;
- ERROR_DUMP(ret);
- goto err_ctx;
- }
-
ret = EVP_DecryptInit_ex(nc->cipher_ctx, NULL, NULL,
(unsigned char*)lkey->d,
iv_data);
-
break;
default:
ret = YACA_ERROR_INVALID_ARGUMENT;
int ret;
int loutput_len;
- if (c == NULL || input == NULL || input_len == 0 ||
- output == NULL || output_len == NULL || op_type != c->op_type)
+ if (c == NULL || input_len == 0 || output_len == NULL || op_type != c->op_type)
return YACA_ERROR_INVALID_ARGUMENT;
loutput_len = *output_len;