#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
+#include <limits.h>
#include <openssl/evp.h>
#include "internal.h"
+static const size_t DEFAULT_GCM_TAG_LEN = 16;
+static const size_t DEFAULT_CCM_TAG_LEN = 12;
+
static bool is_encryption_op(enum encrypt_op_type_e op_type)
{
return (op_type == OP_ENCRYPT || op_type == OP_SEAL);
if (nc == NULL)
return;
+ if (nc->backup_ctx != NULL) {
+ yaca_key_destroy(nc->backup_ctx->iv);
+ yaca_key_destroy(nc->backup_ctx->sym_key);
+ yaca_free(nc->backup_ctx);
+ nc->backup_ctx = NULL;
+ }
+
EVP_CIPHER_CTX_free(nc->cipher_ctx);
nc->cipher_ctx = NULL;
}
return YACA_ERROR_NONE;
}
-int set_encrypt_property(yaca_context_h ctx, yaca_property_e property,
- const void *value, size_t value_len)
+static int encrypt_ctx_create(struct yaca_encrypt_context_s **c,
+ enum encrypt_op_type_e op_type,
+ const EVP_CIPHER *cipher)
+{
+ int ret;
+ int mode;
+ struct yaca_encrypt_context_s *nc;
+
+ assert(c != NULL);
+ assert(cipher != NULL);
+
+ ret = yaca_zalloc(sizeof(struct yaca_encrypt_context_s), (void**)&nc);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ nc->ctx.type = YACA_CONTEXT_ENCRYPT;
+ nc->backup_ctx = NULL;
+ nc->ctx.context_destroy = destroy_encrypt_context;
+ nc->ctx.get_output_length = get_encrypt_output_length;
+ nc->ctx.set_property = set_encrypt_property;
+ nc->ctx.get_property = get_encrypt_property;
+ nc->op_type = op_type;
+ nc->tag_len = 0;
+
+ mode = EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE;
+
+ /* set default tag length for GCM and CCM */
+ if (mode == EVP_CIPH_GCM_MODE)
+ nc->tag_len = DEFAULT_GCM_TAG_LEN;
+ else if (mode == EVP_CIPH_CCM_MODE)
+ nc->tag_len = DEFAULT_CCM_TAG_LEN;
+
+ nc->cipher_ctx = EVP_CIPHER_CTX_new();
+ if (nc->cipher_ctx == NULL) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ goto exit;
+ }
+
+ *c = nc;
+ nc = NULL;
+
+ ret = YACA_ERROR_NONE;
+
+exit:
+ yaca_free(nc);
+ return ret;
+}
+
+static int encrypt_ctx_init(struct yaca_encrypt_context_s *c,
+ const EVP_CIPHER *cipher,
+ size_t key_bit_len)
+{
+ int ret;
+
+ assert(c != NULL);
+ assert(cipher != NULL);
+
+ if (key_bit_len / 8 > INT_MAX)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ ret = EVP_CipherInit_ex(c->cipher_ctx,
+ cipher,
+ NULL,
+ NULL,
+ NULL,
+ is_encryption_op(c->op_type) ? 1 : 0);
+ if (ret != 1) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ /* Handling of algorithms with variable key length */
+ ret = EVP_CIPHER_CTX_set_key_length(c->cipher_ctx, key_bit_len / 8);
+ if (ret != 1) {
+ ret = YACA_ERROR_INVALID_PARAMETER;
+ ERROR_CLEAR();
+ return ret;
+ }
+
+ return YACA_ERROR_NONE;
+}
+
+static int encrypt_ctx_setup_iv(struct yaca_encrypt_context_s *c,
+ const EVP_CIPHER *cipher,
+ const struct yaca_key_simple_s *iv)
+{
+ int ret;
+ size_t default_iv_bit_len;
+
+ assert(c != NULL);
+ assert(cipher != NULL);
+
+ ret = EVP_CIPHER_iv_length(cipher);
+ if (ret < 0) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ default_iv_bit_len = ret * 8;
+
+ /* 0 -> cipher doesn't use iv, but it was provided */
+ if (default_iv_bit_len == 0 && iv != NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ if (default_iv_bit_len != 0) { /* cipher requires iv */
+ /* iv was not provided */
+ if (iv == NULL || iv->key.type != YACA_KEY_TYPE_IV)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ if (iv->bit_len / 8 > INT_MAX)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ /* IV length doesn't match cipher (GCM & CCM supports variable IV length) */
+ if (default_iv_bit_len != iv->bit_len) {
+ int mode = EVP_CIPHER_CTX_mode(c->cipher_ctx);
+
+ if (mode == EVP_CIPH_GCM_MODE) {
+ ret = EVP_CIPHER_CTX_ctrl(c->cipher_ctx, EVP_CTRL_GCM_SET_IVLEN,
+ iv->bit_len / 8, NULL);
+ } else if (mode == EVP_CIPH_CCM_MODE) {
+ ret = EVP_CIPHER_CTX_ctrl(c->cipher_ctx, EVP_CTRL_CCM_SET_IVLEN,
+ iv->bit_len / 8, NULL);
+ } else {
+ return YACA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (ret != 1)
+ return YACA_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ return YACA_ERROR_NONE;
+}
+
+static int encrypt_ctx_setup(struct yaca_encrypt_context_s *c,
+ const yaca_key_h key,
+ const yaca_key_h iv)
+{
+ int ret;
+ unsigned char *iv_data = NULL;
+ const struct yaca_key_simple_s *lkey;
+ const struct yaca_key_simple_s *liv;
+
+ assert(c != NULL);
+ assert(key != YACA_KEY_NULL);
+
+ const EVP_CIPHER *cipher = EVP_CIPHER_CTX_cipher(c->cipher_ctx);
+
+ if (cipher == NULL)
+ return YACA_ERROR_INTERNAL;
+
+ lkey = key_get_simple(key);
+ if (lkey == NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ liv = key_get_simple(iv);
+
+ ret = encrypt_ctx_setup_iv(c, cipher, liv);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ if (liv != NULL)
+ iv_data = (unsigned char*)liv->d;
+
+ ret = EVP_CipherInit_ex(c->cipher_ctx,
+ NULL,
+ NULL,
+ (unsigned char*)lkey->d,
+ iv_data,
+ is_encryption_op(c->op_type) ? 1 : 0);
+ if (ret != 1) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ return YACA_ERROR_NONE;
+}
+
+static int encrypt_ctx_backup(struct yaca_encrypt_context_s *c,
+ const EVP_CIPHER *cipher,
+ const yaca_key_h sym_key,
+ const yaca_key_h iv)
+{
+ int ret;
+ struct yaca_backup_context_s *bc;
+
+ assert(c != NULL);
+ assert(cipher != NULL);
+ assert(sym_key != YACA_KEY_NULL);
+ assert(c->backup_ctx == NULL);
+
+ ret = yaca_zalloc(sizeof(struct yaca_backup_context_s), (void**)&bc);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ bc->cipher = cipher;
+ bc->sym_key = key_copy(sym_key);
+ bc->iv = key_copy(iv);
+
+ c->backup_ctx = bc;
+
+ return YACA_ERROR_NONE;
+}
+
+static int encrypt_ctx_restore(struct yaca_encrypt_context_s *c)
+{
+ int ret;
+ struct yaca_key_simple_s *key;
+
+ assert(c != NULL);
+ assert(c->backup_ctx != NULL);
+
+ ret = EVP_CIPHER_CTX_cleanup(c->cipher_ctx);
+ if (ret != 1) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ key = key_get_simple(c->backup_ctx->sym_key);
+ assert(key != NULL);
+
+ ret = encrypt_ctx_init(c, c->backup_ctx->cipher, key->bit_len);
+ assert(ret != YACA_ERROR_INVALID_PARAMETER);
+ return ret;
+}
+
+static int encrypt_ctx_set_ccm_tag_len(struct yaca_encrypt_context_s *c, size_t tag_len)
+{
+ int ret;
+
+ assert(c != NULL);
+ assert(c->backup_ctx != NULL);
+ assert(is_encryption_op(c->op_type));
+
+ if (tag_len == 0 || tag_len > INT_MAX)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ ret = encrypt_ctx_restore(c);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ c->tag_len = tag_len;
+ ret = EVP_CIPHER_CTX_ctrl(c->cipher_ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL);
+ if (ret != 1) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ ret = encrypt_ctx_setup(c, c->backup_ctx->sym_key, c->backup_ctx->iv);
+ assert(ret != YACA_ERROR_INVALID_PARAMETER);
+ return ret;
+}
+
+static int encrypt_ctx_set_ccm_tag(struct yaca_encrypt_context_s *c, char *tag, size_t tag_len)
+{
+ int ret;
+
+ assert(c != NULL);
+ assert(c->backup_ctx != NULL);
+ assert(!is_encryption_op(c->op_type));
+ assert(tag != NULL);
+
+ if (tag_len == 0 || tag_len > INT_MAX)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ ret = encrypt_ctx_restore(c);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ ret = EVP_CIPHER_CTX_ctrl(c->cipher_ctx, EVP_CTRL_CCM_SET_TAG, tag_len, tag);
+ if (ret != 1) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ ret = encrypt_ctx_setup(c, c->backup_ctx->sym_key, c->backup_ctx->iv);
+ assert(ret != YACA_ERROR_INVALID_PARAMETER);
+ return ret;
+}
+
+int set_encrypt_property(yaca_context_h ctx,
+ yaca_property_e property,
+ const void *value,
+ size_t value_len)
{
struct yaca_encrypt_context_s *c = get_encrypt_context(ctx);
int len;
+ int ret = YACA_ERROR_NONE;
int mode;
- if (c == NULL || value == NULL)
+ if (c == NULL || value == NULL || value_len == 0)
return YACA_ERROR_INVALID_PARAMETER;
assert(c->cipher_ctx != NULL);
}
break;
case YACA_PROPERTY_GCM_TAG:
- if (mode != EVP_CIPH_GCM_MODE || is_encryption_op(c->op_type))
+ if (mode != EVP_CIPH_GCM_MODE || is_encryption_op(c->op_type) ||
+ value_len == 0 || value_len > INT_MAX)
return YACA_ERROR_INVALID_PARAMETER;
if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
break;
case YACA_PROPERTY_GCM_TAG_LEN:
if (value_len != sizeof(size_t) || mode != EVP_CIPH_GCM_MODE ||
- !is_encryption_op(c->op_type))
+ !is_encryption_op(c->op_type) ||
+ *(size_t*)value == 0 || *(size_t*)value > INT_MAX)
return YACA_ERROR_INVALID_PARAMETER;
c->tag_len = *(size_t*)value;
if (mode != EVP_CIPH_CCM_MODE || is_encryption_op(c->op_type))
return YACA_ERROR_INVALID_PARAMETER;
- // TODO rebuild context and set the tag
-
+ ret = encrypt_ctx_set_ccm_tag(c, (char*)value, value_len);
break;
case YACA_PROPERTY_CCM_TAG_LEN:
if (value_len != sizeof(size_t) || mode != EVP_CIPH_CCM_MODE ||
!is_encryption_op(c->op_type))
return YACA_ERROR_INVALID_PARAMETER;
- // TODO rebuild context and set the tag len
-
+ ret = encrypt_ctx_set_ccm_tag_len(c, *(size_t*)value);
break;
default:
return YACA_ERROR_INVALID_PARAMETER;
}
- return YACA_ERROR_NONE;
+ return ret;
}
int get_encrypt_property(const yaca_context_h ctx, yaca_property_e property,
if (value_len == NULL || !is_encryption_op(c->op_type) || mode != EVP_CIPH_GCM_MODE)
return YACA_ERROR_INVALID_PARAMETER;
+ assert(c->tag_len <= INT_MAX);
+
if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
EVP_CTRL_GCM_GET_TAG,
- c->tag_len, value) != 1) {
+ c->tag_len,
+ value) != 1) {
ERROR_DUMP(YACA_ERROR_INTERNAL);
return YACA_ERROR_INTERNAL;
}
if (value_len == NULL || !is_encryption_op(c->op_type) || mode != EVP_CIPH_CCM_MODE)
return YACA_ERROR_INVALID_PARAMETER;
+ assert(c->tag_len <= INT_MAX);
+
if (EVP_CIPHER_CTX_ctrl(c->cipher_ctx,
EVP_CTRL_CCM_GET_TAG,
- c->tag_len, value) != 1) {
+ c->tag_len,
+ value) != 1) {
ERROR_DUMP(YACA_ERROR_INTERNAL);
return YACA_ERROR_INTERNAL;
}
const EVP_CIPHER *lcipher;
int ret;
- if (algo_name == NULL || bcm_name == NULL || key_bit_len == 0 || cipher == NULL)
+ assert(cipher != NULL);
+
+ if (algo_name == NULL || bcm_name == NULL || key_bit_len == 0)
return YACA_ERROR_INVALID_PARAMETER;
switch (algo) {
return YACA_ERROR_NONE;
}
-static int encrypt_initialize(yaca_context_h *ctx,
- yaca_encrypt_algorithm_e algo,
- yaca_block_cipher_mode_e bcm,
- const yaca_key_h sym_key,
- const yaca_key_h iv,
- enum encrypt_op_type_e op_type)
+int encrypt_initialize(yaca_context_h *ctx,
+ const EVP_CIPHER *cipher,
+ const yaca_key_h sym_key,
+ const yaca_key_h iv,
+ enum encrypt_op_type_e op_type)
{
- const struct yaca_key_simple_s *lkey;
- const struct yaca_key_simple_s *liv;
struct yaca_encrypt_context_s *nc;
- const EVP_CIPHER *cipher;
- size_t key_bit_len;
- unsigned char *iv_data = NULL;
- size_t iv_bit_len;
- size_t iv_bit_len_check;
+ struct yaca_key_simple_s *lsym_key;
int ret;
-
- assert(op_type == OP_ENCRYPT || op_type == OP_DECRYPT);
+ int mode;
if (ctx == NULL || sym_key == YACA_KEY_NULL)
return YACA_ERROR_INVALID_PARAMETER;
- lkey = key_get_simple(sym_key);
- if (lkey == NULL)
+ lsym_key = key_get_simple(sym_key);
+ if (lsym_key == NULL)
return YACA_ERROR_INVALID_PARAMETER;
- ret = yaca_zalloc(sizeof(struct yaca_encrypt_context_s), (void**)&nc);
+ ret = encrypt_ctx_create(&nc, op_type, cipher);
if (ret != YACA_ERROR_NONE)
return ret;
- nc->ctx.type = YACA_CONTEXT_ENCRYPT;
- nc->ctx.context_destroy = destroy_encrypt_context;
- nc->ctx.get_output_length = get_encrypt_output_length;
- nc->ctx.set_property = set_encrypt_property;
- nc->ctx.get_property = get_encrypt_property;
- nc->op_type = op_type;
- nc->tag_len = 0;
-
- ret = yaca_key_get_bit_length(sym_key, &key_bit_len);
+ ret = encrypt_ctx_init(nc, cipher, lsym_key->bit_len);
if (ret != YACA_ERROR_NONE)
goto exit;
- ret = encrypt_get_algorithm(algo, bcm, key_bit_len, &cipher);
+ ret = encrypt_ctx_setup(nc, sym_key, iv);
if (ret != YACA_ERROR_NONE)
goto exit;
- ret = EVP_CIPHER_iv_length(cipher);
- if (ret < 0) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- goto exit;
- }
-
- iv_bit_len = ret * 8;
- if (iv_bit_len == 0 && iv != NULL) { /* 0 -> cipher doesn't use iv, but it was provided */
- ret = YACA_ERROR_INVALID_PARAMETER;
- goto exit;
- }
-
- if (iv_bit_len != 0) { /* cipher requires iv*/
- liv = key_get_simple(iv);
- if (liv == NULL) { /* iv was not provided */
- ret = YACA_ERROR_INVALID_PARAMETER;
+ mode = EVP_CIPHER_CTX_mode(nc->cipher_ctx);
+ if (mode == EVP_CIPH_CCM_MODE) {
+ ret = encrypt_ctx_backup(nc, cipher, sym_key, iv);
+ if (ret != YACA_ERROR_NONE)
goto exit;
- }
- ret = yaca_key_get_bit_length(iv, &iv_bit_len_check);
- if (ret != YACA_ERROR_NONE) {
- ret = YACA_ERROR_INVALID_PARAMETER;
- goto exit;
- }
- /* IV length doesn't match cipher (GCM & CCM supports variable IV length) */
- if (iv_bit_len != iv_bit_len_check &&
- bcm != YACA_BCM_GCM &&
- bcm != YACA_BCM_CCM) {
- ret = YACA_ERROR_INVALID_PARAMETER;
- goto exit;
- }
- iv_data = (unsigned char*)liv->d;
- }
-
- nc->cipher_ctx = EVP_CIPHER_CTX_new();
- if (nc->cipher_ctx == NULL) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- goto exit;
- }
-
- ret = EVP_CipherInit_ex(nc->cipher_ctx,
- cipher,
- NULL,
- NULL,
- NULL,
- is_encryption_op(op_type) ? 1 : 0);
- if (ret != 1) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- goto exit;
- }
-
- /* Handling of algorithms with variable key length */
- ret = EVP_CIPHER_CTX_set_key_length(nc->cipher_ctx, key_bit_len / 8);
- if (ret != 1) {
- ret = YACA_ERROR_INVALID_PARAMETER;
- ERROR_CLEAR();
- goto exit;
- }
-
- /* Handling of algorithms with variable IV length */
- if (iv_bit_len != iv_bit_len_check) {
- if (bcm == YACA_BCM_GCM)
- ret = EVP_CIPHER_CTX_ctrl(nc->cipher_ctx, EVP_CTRL_GCM_SET_IVLEN,
- iv_bit_len_check / 8, NULL);
-
- if (bcm == YACA_BCM_CCM)
- ret = EVP_CIPHER_CTX_ctrl(nc->cipher_ctx, EVP_CTRL_CCM_SET_IVLEN,
- iv_bit_len_check / 8, NULL);
-
- if (ret != 1) {
- ret = YACA_ERROR_INVALID_PARAMETER;
- ERROR_DUMP(ret);
- goto exit;
- }
- }
-
- ret = EVP_CipherInit_ex(nc->cipher_ctx, NULL, NULL,
- (unsigned char*)lkey->d,
- iv_data,
- is_encryption_op(op_type) ? 1 : 0);
- if (ret != 1) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- goto exit;
}
*ctx = (yaca_context_h)nc;
const yaca_key_h sym_key,
const yaca_key_h iv)
{
- return encrypt_initialize(ctx, algo, bcm, sym_key, iv, OP_ENCRYPT);
+ const EVP_CIPHER *cipher;
+ struct yaca_key_simple_s *key = key_get_simple(sym_key);
+
+ if (key == NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ int ret = encrypt_get_algorithm(algo, bcm, key->bit_len, &cipher);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ return encrypt_initialize(ctx, cipher, sym_key, iv, OP_ENCRYPT);
}
API int yaca_encrypt_update(yaca_context_h ctx,
const yaca_key_h sym_key,
const yaca_key_h iv)
{
- return encrypt_initialize(ctx, algo, bcm, sym_key, iv, OP_DECRYPT);
+ const EVP_CIPHER *cipher;
+ struct yaca_key_simple_s *key = key_get_simple(sym_key);
+
+ if (key == NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ int ret = encrypt_get_algorithm(algo, bcm, key->bit_len, &cipher);
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ return encrypt_initialize(ctx, cipher, sym_key, iv, OP_DECRYPT);
}
API int yaca_decrypt_update(yaca_context_h ctx,
#include <assert.h>
#include <stdint.h>
+#include <string.h>
#include <openssl/evp.h>
#include "internal.h"
-API int yaca_seal_initialize(yaca_context_h *ctx,
- const yaca_key_h pub_key,
- yaca_encrypt_algorithm_e algo,
- yaca_block_cipher_mode_e bcm,
- size_t sym_key_bit_len,
- yaca_key_h *sym_key,
- yaca_key_h *iv)
+static int seal_generate_sym_key(const EVP_CIPHER *cipher, yaca_key_h *sym_key)
+{
+ int ret;
+ int key_len;
+
+ assert(sym_key != NULL);
+ assert(cipher != NULL);
+
+ ret = EVP_CIPHER_key_length(cipher);
+ if (ret <= 0) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+ key_len = ret;
+
+ return yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, key_len * 8, sym_key);
+}
+
+static int seal_generate_iv(const EVP_CIPHER *cipher, yaca_key_h *iv)
+{
+ int ret;
+ int iv_len;
+
+ assert(iv != NULL);
+ assert(cipher != NULL);
+
+ ret = EVP_CIPHER_iv_length(cipher);
+ if (ret < 0) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
+
+ iv_len = ret;
+ if (iv_len == 0) {
+ *iv = YACA_KEY_NULL;
+ return YACA_ERROR_NONE;
+ }
+
+ return yaca_key_generate(YACA_KEY_TYPE_IV, iv_len * 8, iv);
+}
+
+/* used for asymmetric encryption and decryption */
+static int seal_encrypt_decrypt_key(const yaca_key_h asym_key,
+ const yaca_key_h in_key,
+ yaca_key_h *out_key)
{
- struct yaca_key_evp_s *lpub;
- struct yaca_key_simple_s *lkey = NULL;
- struct yaca_key_simple_s *liv = NULL;
- struct yaca_encrypt_context_s *nc;
- const EVP_CIPHER *cipher;
- int pub_key_length;
- unsigned char *key_data = NULL;
- int key_data_length;
- unsigned char *iv_data = NULL;
- int iv_length;
int ret;
+ const struct yaca_key_evp_s *lasym_key;
+ const struct yaca_key_simple_s *lin_key;
+ struct yaca_key_simple_s *lout_key;
+ size_t output_len;
+
+ lin_key = key_get_simple(in_key);
+ if (lin_key == NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
- if (ctx == NULL || pub_key == YACA_KEY_NULL)
+ if (asym_key->type != YACA_KEY_TYPE_RSA_PRIV && asym_key->type != YACA_KEY_TYPE_RSA_PUB)
return YACA_ERROR_INVALID_PARAMETER;
- if (pub_key->type != YACA_KEY_TYPE_RSA_PUB)
+ lasym_key = key_get_evp(asym_key);
+ if (lasym_key == NULL)
return YACA_ERROR_INVALID_PARAMETER;
- lpub = key_get_evp(pub_key);
- assert(lpub);
- ret = yaca_zalloc(sizeof(struct yaca_encrypt_context_s), (void**)&nc);
+ ret = EVP_PKEY_size(lasym_key->evp);
+ if (ret <= 0)
+ return YACA_ERROR_INTERNAL;
+
+ output_len = ret;
+
+ ret = yaca_zalloc(sizeof(struct yaca_key_simple_s) + output_len, (void**)&lout_key);
if (ret != YACA_ERROR_NONE)
return ret;
- nc->ctx.type = YACA_CONTEXT_ENCRYPT;
- nc->ctx.context_destroy = destroy_encrypt_context;
- nc->ctx.get_output_length = get_encrypt_output_length;
- nc->ctx.set_property = set_encrypt_property;
- nc->ctx.get_property = get_encrypt_property;
- nc->op_type = OP_SEAL;
- nc->tag_len = 0;
-
- nc->cipher_ctx = EVP_CIPHER_CTX_new();
- if (nc->cipher_ctx == NULL) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- goto exit;
- }
+ lout_key->key.type = YACA_KEY_TYPE_SYMMETRIC;
+ lout_key->bit_len = output_len * 8;
+
+ if (asym_key->type == YACA_KEY_TYPE_RSA_PRIV)
+ ret = EVP_PKEY_decrypt_old((unsigned char*)lout_key->d,
+ (unsigned char*)lin_key->d,
+ lin_key->bit_len / 8,
+ lasym_key->evp);
+ else
+ ret = EVP_PKEY_encrypt_old((unsigned char*)lout_key->d,
+ (unsigned char*)lin_key->d,
+ lin_key->bit_len / 8,
+ lasym_key->evp);
- ret = EVP_PKEY_size(lpub->evp);
if (ret <= 0) {
ret = YACA_ERROR_INTERNAL;
ERROR_DUMP(ret);
goto exit;
}
- pub_key_length = ret;
- ret = yaca_zalloc(sizeof(struct yaca_key_simple_s) + pub_key_length, (void**)&lkey);
+ output_len = ret;
+
+ /* Update the key length just in case */
+ lout_key->bit_len = output_len * 8;
+
+ *out_key = (yaca_key_h)lout_key;
+ lout_key = NULL;
+
+ ret = YACA_ERROR_NONE;
+
+exit:
+ yaca_key_destroy((yaca_key_h)lout_key);
+
+ return ret;
+}
+
+API int yaca_seal_initialize(yaca_context_h *ctx,
+ const yaca_key_h pub_key,
+ yaca_encrypt_algorithm_e algo,
+ yaca_block_cipher_mode_e bcm,
+ size_t bit_len,
+ yaca_key_h *enc_sym_key,
+ yaca_key_h *iv)
+{
+ int ret;
+ const EVP_CIPHER *cipher;
+ yaca_key_h lsym_key = YACA_KEY_NULL;
+ yaca_key_h liv = YACA_KEY_NULL;
+ yaca_key_h lenc_sym_key = YACA_KEY_NULL;
+
+ if (pub_key == YACA_KEY_NULL || pub_key->type != YACA_KEY_TYPE_RSA_PUB ||
+ enc_sym_key == NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ ret = encrypt_get_algorithm(algo, bcm, bit_len, &cipher);
if (ret != YACA_ERROR_NONE)
goto exit;
- key_data = (unsigned char*)lkey->d;
- ret = encrypt_get_algorithm(algo, bcm, sym_key_bit_len, &cipher);
+ ret = seal_generate_sym_key(cipher, &lsym_key);
if (ret != YACA_ERROR_NONE)
goto exit;
- ret = EVP_CIPHER_iv_length(cipher);
- if (ret < 0) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
+ ret = seal_generate_iv(cipher, &liv);
+ if (ret != YACA_ERROR_NONE)
goto exit;
- }
- iv_length = ret;
- if (iv_length > 0) {
- ret = yaca_zalloc(sizeof(struct yaca_key_simple_s) + iv_length, (void**)&liv);
- if (ret != YACA_ERROR_NONE)
- goto exit;
- iv_data = (unsigned char*)liv->d;
+ if (liv != YACA_KEY_NULL && iv == NULL) {
+ ret = YACA_ERROR_INVALID_PARAMETER;
+ goto exit;
}
- ret = EVP_SealInit(nc->cipher_ctx,
- cipher,
- &key_data,
- &key_data_length,
- iv_data,
- &lpub->evp,
- 1);
+ /* using public key will make it encrypt the symmetric key */
+ ret = seal_encrypt_decrypt_key(pub_key, lsym_key, &lenc_sym_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
- if (ret != 1) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
+ ret = encrypt_initialize(ctx, cipher, lsym_key, liv, OP_SEAL);
+ if (ret != YACA_ERROR_NONE)
goto exit;
- }
- lkey->bit_len = key_data_length * 8;
- lkey->key.type = YACA_KEY_TYPE_SYMMETRIC;
- *sym_key = (yaca_key_h)lkey;
- lkey = NULL;
-
- if (iv_length > 0) {
- liv->bit_len = iv_length * 8;
- liv->key.type = YACA_KEY_TYPE_IV;
- *iv = (yaca_key_h)liv;
- liv = NULL;
- } else {
- *iv = NULL;
- }
- *ctx = (yaca_context_h)nc;
- nc = NULL;
+ *enc_sym_key = lenc_sym_key;
+ lenc_sym_key = YACA_KEY_NULL;
+ *iv = liv;
+ liv = YACA_KEY_NULL;
ret = YACA_ERROR_NONE;
exit:
- yaca_free(liv);
- yaca_free(lkey);
- yaca_context_destroy((yaca_context_h)nc);
+ yaca_key_destroy(liv);
+ yaca_key_destroy(lsym_key);
+ yaca_key_destroy(lenc_sym_key);
return ret;
}
const yaca_key_h prv_key,
yaca_encrypt_algorithm_e algo,
yaca_block_cipher_mode_e bcm,
- size_t sym_key_bit_len,
- const yaca_key_h sym_key,
+ size_t bit_len,
+ const yaca_key_h enc_sym_key,
const yaca_key_h iv)
{
- const struct yaca_key_evp_s *lprv;
- const struct yaca_key_simple_s *lkey;
- const struct yaca_key_simple_s *liv;
- struct yaca_encrypt_context_s *nc;
- const EVP_CIPHER *cipher;
- unsigned char *iv_data = NULL;
- size_t iv_bit_len;
- size_t iv_bit_len_check;
int ret;
+ const EVP_CIPHER *cipher;
+ yaca_key_h lsym_key = YACA_KEY_NULL;
- if (ctx == NULL || prv_key == YACA_KEY_NULL || sym_key == YACA_KEY_NULL)
- return YACA_ERROR_INVALID_PARAMETER;
-
- if (prv_key->type != YACA_KEY_TYPE_RSA_PRIV)
- return YACA_ERROR_INVALID_PARAMETER;
- lprv = key_get_evp(prv_key);
- assert(lprv);
-
- lkey = key_get_simple(sym_key);
- if (lkey == NULL || lkey->key.type != YACA_KEY_TYPE_SYMMETRIC)
+ if (prv_key == YACA_KEY_NULL || prv_key->type != YACA_KEY_TYPE_RSA_PRIV ||
+ enc_sym_key == YACA_KEY_NULL)
return YACA_ERROR_INVALID_PARAMETER;
- ret = yaca_zalloc(sizeof(struct yaca_encrypt_context_s), (void**)&nc);
+ ret = encrypt_get_algorithm(algo, bcm, bit_len, &cipher);
if (ret != YACA_ERROR_NONE)
- return ret;
-
- nc->ctx.type = YACA_CONTEXT_ENCRYPT;
- nc->ctx.context_destroy = destroy_encrypt_context;
- nc->ctx.get_output_length = get_encrypt_output_length;
- nc->ctx.set_property = set_encrypt_property;
- nc->ctx.get_property = get_encrypt_property;
- nc->op_type = OP_OPEN;
- nc->tag_len = 0;
-
- ret = encrypt_get_algorithm(algo, bcm, sym_key_bit_len, &cipher);
- if (ret != YACA_ERROR_NONE)
- goto exit;
-
- ret = EVP_CIPHER_iv_length(cipher);
- if (ret < 0) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
goto exit;
- }
- iv_bit_len = ret * 8;
- if (iv_bit_len == 0 && iv != NULL) { /* 0 -> cipher doesn't use iv, but it was provided */
- ret = YACA_ERROR_INVALID_PARAMETER;
+ /* using private key will make it decrypt the symmetric key */
+ ret = seal_encrypt_decrypt_key(prv_key, enc_sym_key, &lsym_key);
+ if (ret != YACA_ERROR_NONE)
goto exit;
- }
-
- if (iv_bit_len > 0) { /* cipher requires iv*/
- liv = key_get_simple(iv);
- if (liv == NULL || liv->key.type != YACA_KEY_TYPE_IV) { /* iv was not provided */
- ret = YACA_ERROR_INVALID_PARAMETER;
- goto exit;
- }
- ret = yaca_key_get_bit_length(iv, &iv_bit_len_check);
- if (ret != YACA_ERROR_NONE) {
- ret = YACA_ERROR_INVALID_PARAMETER;
- goto exit;
- }
- /* IV length doesn't match cipher */
- if (iv_bit_len != iv_bit_len_check) {
- ret = YACA_ERROR_INVALID_PARAMETER;
- goto exit;
- }
- iv_data = (unsigned char*)liv->d;
- }
- nc->cipher_ctx = EVP_CIPHER_CTX_new();
- if (nc->cipher_ctx == NULL) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- goto exit;
- }
-
- ret = EVP_OpenInit(nc->cipher_ctx, cipher,
- (unsigned char*)lkey->d,
- EVP_PKEY_size(lprv->evp),
- iv_data,
- lprv->evp);
- if (ret != 1) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
+ ret = encrypt_initialize(ctx, cipher, lsym_key, iv, OP_OPEN);
+ if (ret != YACA_ERROR_NONE)
goto exit;
- }
- *ctx = (yaca_context_h)nc;
- nc = NULL;
ret = YACA_ERROR_NONE;
exit:
- yaca_context_destroy((yaca_context_h)nc);
-
+ yaca_key_destroy(lsym_key);
return ret;
}