Key wrapping implementation/example 58/81658/6
authorDariusz Michaluk <d.michaluk@samsung.com>
Fri, 15 Jul 2016 16:09:25 +0000 (18:09 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Thu, 4 Aug 2016 10:13:01 +0000 (12:13 +0200)
Change-Id: Ifedb332212bffa4c0934f57d9d51b12537fe1d1f

api/yaca/yaca_types.h
examples/CMakeLists.txt
examples/key_wrap.c [new file with mode: 0644]
src/encrypt.c
src/internal.h
src/seal.c

index f5d9854..0564f2e 100755 (executable)
@@ -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;
 
index bcc54e4..12cd956 100644 (file)
@@ -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 (file)
index 0000000..af8c655
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ *  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;
+}
+
index 08880da..4fa6965 100644 (file)
@@ -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;
index b6e2321..7c202ec 100644 (file)
@@ -25,6 +25,7 @@
 #define YACA_INTERNAL_H
 
 #include <stddef.h>
+#include <stdbool.h>
 
 #include <openssl/ossl_typ.h>
 #include <openssl/err.h>
@@ -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 */
index 623d2e8..504470f 100644 (file)
@@ -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);