From: Dariusz Michaluk Date: Fri, 15 Jul 2016 16:09:25 +0000 (+0200) Subject: Key wrapping implementation/example X-Git-Tag: submit/tizen/20160901.024233~35^2~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4581e7ed408caa4324a7fa2a3b6a577f6c7ca09e;p=platform%2Fcore%2Fsecurity%2Fyaca.git Key wrapping implementation/example Change-Id: Ifedb332212bffa4c0934f57d9d51b12537fe1d1f --- diff --git a/api/yaca/yaca_types.h b/api/yaca/yaca_types.h index f5d9854..0564f2e 100755 --- a/api/yaca/yaca_types.h +++ b/api/yaca/yaca_types.h @@ -344,7 +344,8 @@ typedef enum { * #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, @@ -385,7 +386,8 @@ typedef enum { * #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. */ @@ -540,7 +542,26 @@ typedef enum { * @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; diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index bcc54e4..12cd956 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -52,6 +52,7 @@ BUILD_EXAMPLE("yaca-example-key-gen" key_gen.c) 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}) diff --git a/examples/key_wrap.c b/examples/key_wrap.c new file mode 100644 index 0000000..af8c655 --- /dev/null +++ b/examples/key_wrap.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Krzysztof Jackiewicz + * + * 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 +#include + +#include +#include +#include +#include +#include + +#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; +} + diff --git a/src/encrypt.c b/src/encrypt.c index 08880da..4fa6965 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -58,34 +58,34 @@ struct yaca_encrypt_context_s *get_encrypt_context(const yaca_context_h ctx) 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; @@ -105,6 +105,33 @@ int get_encrypt_output_length(const yaca_context_h ctx, size_t input_len, size_t 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) @@ -120,16 +147,19 @@ static int encrypt_ctx_create(struct yaca_encrypt_context_s **c, 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) @@ -144,6 +174,9 @@ static int encrypt_ctx_create(struct yaca_encrypt_context_s **c, 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; @@ -564,6 +597,8 @@ static const char *bcm_to_str(yaca_block_cipher_mode_e bcm) return "ofb"; case YACA_BCM_CCM: return "ccm"; + case YACA_BCM_WRAP: + return "wrap"; default: return NULL; } @@ -587,8 +622,12 @@ int encrypt_get_algorithm(yaca_encrypt_algorithm_e algo, 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: @@ -597,9 +636,17 @@ int encrypt_get_algorithm(yaca_encrypt_algorithm_e algo, 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); @@ -728,14 +775,34 @@ int encrypt_update(yaca_context_h ctx, 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; @@ -744,6 +811,7 @@ int encrypt_update(yaca_context_h ctx, } *output_len = loutput_len; + c->update_called = true; return YACA_ERROR_NONE; } @@ -753,16 +821,18 @@ int encrypt_finalize(yaca_context_h ctx, { 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; diff --git a/src/internal.h b/src/internal.h index b6e2321..7c202ec 100644 --- a/src/internal.h +++ b/src/internal.h @@ -25,6 +25,7 @@ #define YACA_INTERNAL_H #include +#include #include #include @@ -73,6 +74,7 @@ struct yaca_encrypt_context_s { 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 */ diff --git a/src/seal.c b/src/seal.c index 623d2e8..504470f 100644 --- a/src/seal.c +++ b/src/seal.c @@ -160,7 +160,7 @@ API int yaca_seal_initialize(yaca_context_h *ctx, 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); @@ -233,7 +233,7 @@ API int yaca_open_initialize(yaca_context_h *ctx, 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);