* #YACA_BCM_ECB,\n
* #YACA_BCM_GCM,\n
* #YACA_BCM_CCM,\n
- * #YACA_BCM_CTR
+ * #YACA_BCM_CTR,\n
+ * #YACA_BCM_WRAP
* - see #yaca_block_cipher_mode_e for details on additional properties (mandatory).
*/
YACA_ENCRYPT_AES = 0,
* #YACA_BCM_CFB,\n
* #YACA_BCM_CFB1,\n
* #YACA_BCM_CFB8,\n
- * #YACA_BCM_ECB
+ * #YACA_BCM_ECB,\n
+ * #YACA_BCM_WRAP
* - see #yaca_block_cipher_mode_e for details on additional properties (mandatory).
* - Use triple DES keys to perform corresponding 3-key 3DES encryption.
*/
* @see examples/encrypt_aes_gcm_ccm.c
* @see examples/seal.c
*/
- YACA_BCM_CCM
+ YACA_BCM_CCM,
+
+ /**
+ * Used with #YACA_ENCRYPT_AES or #YACA_ENCRYPT_3DES_3TDEA to perform a key wrapping
+ * (key material symmetric encryption).
+ *
+ * Only a single yaca_encrypt_update() / yaca_decrypt_update() is allowed.
+ *
+ * Usage in yaca_seal_initialize() / yaca_open_finalize() is forbidden.
+ *
+ * Key used to do the wrapping with #YACA_ENCRYPT_AES can be a 128-bit key, a 192-bit key, or a 256-bit key.
+ * Wrapped key can be a 128-bit key, a 192-bit key, or a 256-bit key.
+ * #YACA_ENCRYPT_AES allows wrapping multiple keys together.
+ *
+ * Key used to do the wrapping with #YACA_ENCRYPT_3DES_3TDEA can be a 192 bit DES key only.
+ * Wrapped key can be a 128-bit DES key (two-key), or a 192-bit DES key (three-key).
+ * #YACA_ENCRYPT_3DES_3TDEA allows wrapping only one key.
+ *
+ */
+ YACA_BCM_WRAP
} yaca_block_cipher_mode_e;
BUILD_EXAMPLE("yaca-example-key-exchange" key_exchange.c)
BUILD_EXAMPLE("yaca-example-key-impexp" key_import_export.c)
BUILD_EXAMPLE("yaca-example-key-password" key_password.c)
+BUILD_EXAMPLE("yaca-example-key-wrap" key_wrap.c)
INSTALL(FILES ${COMMON_SOURCES}
DESTINATION ${EXAMPLES_DIR})
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/**
+ * @file key_wrap.c
+ * @brief
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <yaca_crypto.h>
+#include <yaca_simple.h>
+#include <yaca_encrypt.h>
+#include <yaca_key.h>
+#include <yaca_error.h>
+
+#include "misc.h"
+#include "../src/debug.h"
+
+void key_wrap_aes(void)
+{
+ int ret;
+ yaca_key_h sym_key = YACA_KEY_NULL;
+ yaca_key_h iv = YACA_KEY_NULL;
+ yaca_key_h aes_key = YACA_KEY_NULL;
+
+ size_t iv_bit_len;
+ char *key_data = NULL;
+ size_t key_data_len;
+ char *wrapped_key = NULL;
+ size_t wrapped_key_len;
+
+ printf("\n***** AES key wrapping ******\n");
+
+ ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &aes_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &sym_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES,
+ YACA_BCM_WRAP,
+ YACA_KEY_LENGTH_192BIT,
+ &iv_bit_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ if (iv_bit_len > 0) {
+ ret = yaca_key_generate(YACA_KEY_TYPE_IV, iv_bit_len, &iv);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+ }
+
+ /* Key wrapping */
+ {
+ ret = yaca_key_export(aes_key, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, NULL,
+ &key_data, &key_data_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_WRAP, sym_key, iv,
+ key_data, key_data_len,
+ &wrapped_key, &wrapped_key_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ dump_hex(key_data, key_data_len, "***** Unwrapped key:*****");
+ dump_hex(wrapped_key, wrapped_key_len, "***** Wrapped key:*****");
+ }
+
+ yaca_free(key_data);
+ key_data = NULL;
+ yaca_key_destroy(aes_key);
+ aes_key = YACA_KEY_NULL;
+
+ /* Key unwrapping */
+ {
+ ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_WRAP, sym_key, iv,
+ wrapped_key, wrapped_key_len,
+ &key_data, &key_data_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, NULL, key_data, key_data_len, &aes_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ dump_hex(key_data, key_data_len, "***** Unwrapped key:*****");
+ }
+
+exit:
+ yaca_key_destroy(aes_key);
+ yaca_key_destroy(sym_key);
+ yaca_key_destroy(iv);
+ yaca_free(key_data);
+ yaca_free(wrapped_key);
+}
+
+void key_wrap_des(void)
+{
+ int ret;
+ yaca_key_h sym_key = YACA_KEY_NULL;
+ yaca_key_h iv = YACA_KEY_NULL;
+ yaca_key_h des_key = YACA_KEY_NULL;
+
+ size_t iv_bit_len;
+ char *key_data = NULL;
+ size_t key_data_len;
+ char *wrapped_key = NULL;
+ size_t wrapped_key_len;
+
+ printf("\n***** 3DES key wrapping ******\n");
+
+ ret = yaca_key_generate(YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_192BIT, &des_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_key_generate(YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_192BIT, &sym_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_3DES_3TDEA,
+ YACA_BCM_WRAP,
+ YACA_KEY_LENGTH_192BIT,
+ &iv_bit_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ if (iv_bit_len > 0) {
+ ret = yaca_key_generate(YACA_KEY_TYPE_IV, iv_bit_len, &iv);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+ }
+
+ /* Key wrapping */
+ {
+ ret = yaca_key_export(des_key, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, NULL,
+ &key_data, &key_data_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_simple_encrypt(YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_WRAP, sym_key, iv,
+ key_data, key_data_len,
+ &wrapped_key, &wrapped_key_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ dump_hex(key_data, key_data_len, "***** Unwrapped key:*****");
+ dump_hex(wrapped_key, wrapped_key_len, "***** Wrapped key:*****");
+ }
+
+ yaca_free(key_data);
+ key_data = NULL;
+ yaca_key_destroy(des_key);
+ des_key = YACA_KEY_NULL;
+
+ /* Key unwrapping */
+ {
+ ret = yaca_simple_decrypt(YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_WRAP, sym_key, iv,
+ wrapped_key, wrapped_key_len,
+ &key_data, &key_data_len);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ ret = yaca_key_import(YACA_KEY_TYPE_DES, NULL, key_data, key_data_len, &des_key);
+ if (ret != YACA_ERROR_NONE)
+ goto exit;
+
+ dump_hex(key_data, key_data_len, "***** Unwrapped key:*****");
+ }
+
+exit:
+ yaca_key_destroy(des_key);
+ yaca_key_destroy(sym_key);
+ yaca_key_destroy(iv);
+ yaca_free(key_data);
+ yaca_free(wrapped_key);
+}
+
+int main()
+{
+ yaca_debug_set_error_cb(debug_func);
+
+ int ret = yaca_initialize();
+ if (ret != YACA_ERROR_NONE)
+ return ret;
+
+ key_wrap_aes();
+ key_wrap_des();
+
+ yaca_cleanup();
+ return ret;
+}
+
void destroy_encrypt_context(const yaca_context_h ctx)
{
- struct yaca_encrypt_context_s *nc = get_encrypt_context(ctx);
+ struct yaca_encrypt_context_s *c = get_encrypt_context(ctx);
- if (nc == NULL)
+ if (c == 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;
+ if (c->backup_ctx != NULL) {
+ yaca_key_destroy(c->backup_ctx->iv);
+ yaca_key_destroy(c->backup_ctx->sym_key);
+ yaca_free(c->backup_ctx);
+ c->backup_ctx = NULL;
}
- EVP_CIPHER_CTX_free(nc->cipher_ctx);
- nc->cipher_ctx = NULL;
+ EVP_CIPHER_CTX_free(c->cipher_ctx);
+ c->cipher_ctx = NULL;
}
int get_encrypt_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len)
{
assert(output_len != NULL);
- struct yaca_encrypt_context_s *nc = get_encrypt_context(ctx);
+ struct yaca_encrypt_context_s *c = get_encrypt_context(ctx);
int block_size;
- if (nc == NULL)
+ if (c == NULL)
return YACA_ERROR_INVALID_PARAMETER;
- assert(nc->cipher_ctx != NULL);
+ assert(c->cipher_ctx != NULL);
- block_size = EVP_CIPHER_CTX_block_size(nc->cipher_ctx);
+ block_size = EVP_CIPHER_CTX_block_size(c->cipher_ctx);
if (block_size <= 0) {
ERROR_DUMP(YACA_ERROR_INTERNAL);
return YACA_ERROR_INTERNAL;
return YACA_ERROR_NONE;
}
+int get_wrap_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len)
+{
+ assert(output_len != NULL);
+
+ struct yaca_encrypt_context_s *c = get_encrypt_context(ctx);
+ if (c == NULL)
+ return YACA_ERROR_INVALID_PARAMETER;
+ assert(c->cipher_ctx != NULL);
+
+ int type = EVP_CIPHER_type(c->cipher_ctx->cipher);
+
+ if (input_len > 0) {
+ if (type == NID_id_aes128_wrap || type == NID_id_aes192_wrap || type == NID_id_aes256_wrap) {
+ *output_len = input_len + 8;
+ } else if (type == NID_id_smime_alg_CMS3DESwrap) {
+ *output_len = input_len + 16;
+ } else {
+ assert(false);
+ return YACA_ERROR_INTERNAL;
+ }
+ } else {
+ *output_len = 0;
+ }
+
+ return YACA_ERROR_NONE;
+}
+
static int encrypt_ctx_create(struct yaca_encrypt_context_s **c,
enum encrypt_op_type_e op_type,
const EVP_CIPHER *cipher)
if (ret != YACA_ERROR_NONE)
return ret;
+ mode = EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE;
+
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.get_output_length = (mode == EVP_CIPH_WRAP_MODE) ?
+ get_wrap_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;
+ nc->update_called = false;
/* set default tag length for GCM and CCM */
if (mode == EVP_CIPH_GCM_MODE)
goto exit;
}
+ if (mode == EVP_CIPH_WRAP_MODE)
+ EVP_CIPHER_CTX_set_flags(nc->cipher_ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+
*c = nc;
nc = NULL;
return "ofb";
case YACA_BCM_CCM:
return "ccm";
+ case YACA_BCM_WRAP:
+ return "wrap";
default:
return NULL;
}
switch (algo) {
case YACA_ENCRYPT_AES:
- ret = snprintf(cipher_name, sizeof(cipher_name), "%s-%zu-%s",
- algo_name, key_bit_len, bcm_name);
+ if (bcm == YACA_BCM_WRAP)
+ ret = snprintf(cipher_name, sizeof(cipher_name), "id-%s%zu-%s",
+ algo_name, key_bit_len, bcm_name);
+ else
+ ret = snprintf(cipher_name, sizeof(cipher_name), "%s-%zu-%s",
+ algo_name, key_bit_len, bcm_name);
break;
case YACA_ENCRYPT_UNSAFE_DES:
case YACA_ENCRYPT_UNSAFE_RC2:
algo_name, bcm_name);
break;
case YACA_ENCRYPT_UNSAFE_3DES_2TDEA:
+ if (bcm == YACA_BCM_ECB)
+ ret = snprintf(cipher_name, sizeof(cipher_name), "%s", algo_name);
+ else
+ ret = snprintf(cipher_name, sizeof(cipher_name), "%s-%s",
+ algo_name, bcm_name);
+ break;
case YACA_ENCRYPT_3DES_3TDEA:
if (bcm == YACA_BCM_ECB)
ret = snprintf(cipher_name, sizeof(cipher_name), "%s", algo_name);
+ else if (bcm == YACA_BCM_WRAP)
+ ret = snprintf(cipher_name, sizeof(cipher_name), "id-smime-alg-CMS3DESwrap");
else
ret = snprintf(cipher_name, sizeof(cipher_name), "%s-%s",
algo_name, bcm_name);
struct yaca_encrypt_context_s *c = get_encrypt_context(ctx);
int ret;
int loutput_len;
+ int mode;
+ int type;
if (c == NULL || input_len == 0 || output_len == NULL || op_type != c->op_type)
return YACA_ERROR_INVALID_PARAMETER;
- if (EVP_CIPHER_CTX_mode(c->cipher_ctx) != EVP_CIPH_CCM_MODE)
- if (input == NULL || output == NULL)
+ mode = EVP_CIPHER_CTX_mode(c->cipher_ctx);
+ type = EVP_CIPHER_type(c->cipher_ctx->cipher);
+
+ if (mode != EVP_CIPH_CCM_MODE && (input == NULL || output == NULL))
+ return YACA_ERROR_INVALID_PARAMETER;
+
+ if (mode == EVP_CIPH_WRAP_MODE && c->update_called == true)
return YACA_ERROR_INVALID_PARAMETER;
+ if (mode == EVP_CIPH_WRAP_MODE && op_type == OP_ENCRYPT) {
+ if (type == NID_id_aes128_wrap || type == NID_id_aes192_wrap || type == NID_id_aes256_wrap) {
+ if (input_len % 8 != 0 || input_len < (YACA_KEY_LENGTH_UNSAFE_128BIT / 8))
+ return YACA_ERROR_INVALID_PARAMETER;
+ } else if (type == NID_id_smime_alg_CMS3DESwrap) {
+ if (input_len != (YACA_KEY_LENGTH_UNSAFE_128BIT / 8) && input_len != (YACA_KEY_LENGTH_192BIT / 8))
+ return YACA_ERROR_INVALID_PARAMETER;
+ } else {
+ assert(false);
+ return YACA_ERROR_INTERNAL;
+ }
+ }
+
ret = EVP_CipherUpdate(c->cipher_ctx, output, &loutput_len, input, input_len);
if (ret != 1 || loutput_len < 0) {
ret = YACA_ERROR_INTERNAL;
}
*output_len = loutput_len;
+ c->update_called = true;
return YACA_ERROR_NONE;
}
{
struct yaca_encrypt_context_s *c = get_encrypt_context(ctx);
int ret;
- int loutput_len;
+ int loutput_len = 0;
if (c == NULL || output == NULL || output_len == NULL || op_type != c->op_type)
return YACA_ERROR_INVALID_PARAMETER;
- ret = EVP_CipherFinal(c->cipher_ctx, output, &loutput_len);
- if (ret != 1 || loutput_len < 0) {
- ret = YACA_ERROR_INTERNAL;
- ERROR_DUMP(ret);
- return ret;
+ if (EVP_CIPHER_CTX_mode(c->cipher_ctx) != EVP_CIPH_WRAP_MODE) {
+ ret = EVP_CipherFinal(c->cipher_ctx, output, &loutput_len);
+ if (ret != 1 || loutput_len < 0) {
+ ret = YACA_ERROR_INTERNAL;
+ ERROR_DUMP(ret);
+ return ret;
+ }
}
*output_len = loutput_len;
#define YACA_INTERNAL_H
#include <stddef.h>
+#include <stdbool.h>
#include <openssl/ossl_typ.h>
#include <openssl/err.h>
EVP_CIPHER_CTX *cipher_ctx;
enum encrypt_op_type_e op_type; /* Operation context was created for */
size_t tag_len;
+ bool update_called;
};
/* Base structure for crypto keys - to be inherited */
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)
+ enc_sym_key == NULL || bcm == YACA_BCM_WRAP)
return YACA_ERROR_INVALID_PARAMETER;
ret = encrypt_get_algorithm(algo, bcm, bit_len, &cipher);
yaca_key_h lsym_key = YACA_KEY_NULL;
if (prv_key == YACA_KEY_NULL || prv_key->type != YACA_KEY_TYPE_RSA_PRIV ||
- enc_sym_key == YACA_KEY_NULL)
+ enc_sym_key == YACA_KEY_NULL || bcm == YACA_BCM_WRAP)
return YACA_ERROR_INVALID_PARAMETER;
ret = encrypt_get_algorithm(algo, bcm, bit_len, &cipher);