From dd9801ab8d32af0132c1b1d8c0814b121091d1a4 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 13:30:02 +0200 Subject: [PATCH 01/16] Add YACA_ERROR_SIGNATURE_INVALID error code. Mentioned in the doxygen. Change-Id: Ieff9d6a8408c878b7ff9656f637382abab23f742 --- api/yaca/error.h | 3 ++- api/yaca/sign.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/yaca/error.h b/api/yaca/error.h index 9a192f4..e8d11ed 100644 --- a/api/yaca/error.h +++ b/api/yaca/error.h @@ -37,7 +37,8 @@ enum __yaca_error_code { YACA_ERROR_OPENSSL_FAILURE = -3, YACA_ERROR_NOT_SUPPORTED = -4, YACA_ERROR_TOO_BIG_ARGUMENT = -5, - YACA_ERROR_OUT_OF_MEMORY = -6 + YACA_ERROR_OUT_OF_MEMORY = -6, + YACA_ERROR_SIGNATURE_INVALID = -7 }; #ifdef __cplusplus diff --git a/api/yaca/sign.h b/api/yaca/sign.h index 0f0855e..217d15d 100644 --- a/api/yaca/sign.h +++ b/api/yaca/sign.h @@ -113,7 +113,7 @@ int yaca_verify_update(yaca_ctx_h ctx, * @param[in] mac_len Size of the MAC or the signature. * * @return 0 on success, negative on error (@see error.h). - * TODO: CRYTPO_ERROR_SIGNATURE_INVALID when verification fails. + * TODO: YACA_ERROR_SIGNATURE_INVALID when verification fails. */ int yaca_verify_final(yaca_ctx_h ctx, const char *mac, -- 2.7.4 From 4d688df05d74a6f2624902130faae9048f899208 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 13:30:44 +0200 Subject: [PATCH 02/16] Add todo.txt file for global TODOs. Change-Id: I79d942960fa25b44095b6ea150d5bd1f408c8343 --- todo.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 todo.txt diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..4f24242 --- /dev/null +++ b/todo.txt @@ -0,0 +1,3 @@ +Global: +- Rethink and possibly add verification of output buffer lengths. + In other words check whether the user won't cause a buffer overflow. -- 2.7.4 From 0af4e6ef1b64389a57475fee28f0d1e39d9e805a Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 13:33:19 +0200 Subject: [PATCH 03/16] Get rid of EVP_MD from digest struct, it's redudant. Change-Id: I52d84125d4b0f2ab1face439477efcc82ee0a0fe --- src/digest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/digest.c b/src/digest.c index 4cc0ceb..bd3f62f 100644 --- a/src/digest.c +++ b/src/digest.c @@ -32,7 +32,6 @@ struct yaca_digest_ctx_s { struct yaca_ctx_s ctx; - const EVP_MD *md; EVP_MD_CTX *mdctx; }; @@ -57,7 +56,7 @@ static int get_digest_output_length(const yaca_ctx_h ctx, size_t input_len) if (c == NULL) return YACA_ERROR_INVALID_ARGUMENT; - return EVP_MD_size(c->md); + return EVP_MD_CTX_size(c->mdctx); } static void destroy_digest_context(yaca_ctx_h ctx) @@ -117,6 +116,7 @@ API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo) { int ret; struct yaca_digest_ctx_s *nc = NULL; + const EVP_MD *md; if (ctx == NULL) return YACA_ERROR_INVALID_ARGUMENT; @@ -129,7 +129,7 @@ API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo) nc->ctx.ctx_destroy = destroy_digest_context; nc->ctx.get_output_length = get_digest_output_length; - ret = digest_get_algorithm(algo, &nc->md); + ret = digest_get_algorithm(algo, &md); if (ret < 0) goto free; @@ -139,7 +139,7 @@ API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo) goto free; } - ret = EVP_DigestInit(nc->mdctx, nc->md); + ret = EVP_DigestInit(nc->mdctx, md); if (ret != 1) { ret = YACA_ERROR_OPENSSL_FAILURE; goto ctx; -- 2.7.4 From 8eb62230e8f7849a09c81283f0fd56ce77d72046 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 13:34:04 +0200 Subject: [PATCH 04/16] Small cosmetic change in digest.c to line it up with the style of the rest of the code. Change-Id: Ib22750311254ffaaa0f241191f9a9fdeed1a00b7 --- src/digest.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/digest.c b/src/digest.c index bd3f62f..93a2535 100644 --- a/src/digest.c +++ b/src/digest.c @@ -147,15 +147,12 @@ API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo) *ctx = (yaca_ctx_h)nc; - ret = 0; + return 0; ctx: - if (ret != 0) - EVP_MD_CTX_destroy(nc->mdctx); + EVP_MD_CTX_destroy(nc->mdctx); free: - if (ret != 0) - yaca_free(nc); - + yaca_free(nc); return ret; } -- 2.7.4 From d475db4315e73f0b5a6875c79f4087d92f5da895 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 13:34:44 +0200 Subject: [PATCH 05/16] Implement getting the bits of an evp type key. Change-Id: Ibbd62e146bcfc7ecaa999a694416db2488e14052 --- src/key.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/key.c b/src/key.c index 78dd5c8..6ba3c9e 100644 --- a/src/key.c +++ b/src/key.c @@ -104,8 +104,16 @@ API int yaca_key_get_length(const yaca_key_h key) } if (evp_key != NULL) { + int ret; + evp_key_sanity_check(evp_key); - return YACA_ERROR_NOT_IMPLEMENTED; + + // TODO: handle ECC keys when they're implemented + ret = EVP_PKEY_bits(evp_key->evp); + if (ret <= 0) + return YACA_ERROR_OPENSSL_FAILURE; + + return ret; } return YACA_ERROR_INVALID_ARGUMENT; -- 2.7.4 From dbffca578cb0f37f323ca093512b7de20bb104bf Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 14:54:01 +0200 Subject: [PATCH 06/16] Remove unused function pointer, no need to do that for keys. Change-Id: I1b856243bc42a09783cadfe42b402f9c8dc144f0 --- src/internal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/internal.h b/src/internal.h index 074951b..491ec2d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -51,8 +51,6 @@ struct yaca_ctx_s struct yaca_key_s { yaca_key_type_e type; - - int (*get_key_length)(const struct yaca_key_s *key); }; /** -- 2.7.4 From 6f066fc11fb5daa91f5e31594dca5d2b9c9d54d8 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 13:42:30 +0200 Subject: [PATCH 07/16] Add SIGN context to context types. Change-Id: If61017092a29d5b50c6036b825492a7760e87cd6 --- src/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal.h b/src/internal.h index 491ec2d..deeff97 100644 --- a/src/internal.h +++ b/src/internal.h @@ -34,7 +34,8 @@ enum yaca_ctx_type_e { YACA_CTX_INVALID = 0, - YACA_CTX_DIGEST + YACA_CTX_DIGEST, + YACA_CTX_SIGN }; /* Base structure for crypto contexts - to be inherited */ -- 2.7.4 From 621c2df6d2005b367b5eb2e5100ead43394708ec Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Wed, 13 Apr 2016 14:44:40 +0200 Subject: [PATCH 08/16] examples: Add LOREM*_SIZE Add macros containing sizes of lorem* strings. Change-Id: I2514f9fc03d55561530fac9ec856f404f9aa987b Signed-off-by: Mateusz Kulikowski --- examples/lorem.c | 10 ++++++---- examples/lorem.h | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/examples/lorem.c b/examples/lorem.c index ac6955f..d6f9f42 100644 --- a/examples/lorem.c +++ b/examples/lorem.c @@ -21,12 +21,14 @@ * @brief Lorem Ipsum */ -const char *lorem8 = "Lorem i"; -const char *lorem16 = "Lorem ipsum dol"; -const char *lorem1024 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec non dolor tincidunt, vehicula erat non, pulvinar nisl. Suspendisse gravida commodo hendrerit. Sed ex magna, aliquet malesuada lectus ut, porttitor tincidunt ante. Nulla facilisi. Morbi nec scelerisque risus. Sed a gravida sapien. Cras sed neque bibendum, dapibus lectus sed, porta nulla. Morbi tristique velit lacus, at luctus turpis mollis sed. Nam quis sapien eu magna cursus venenatis. Phasellus et vestibulum urna, non pellentesque ex. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pretium aliquam porta.\ +#include "lorem.h" + +const char lorem8[LOREM8_SIZE] = "Lorem i"; +const char lorem16[LOREM16_SIZE] = "Lorem ipsum dol"; +const char lorem1024[LOREM1024_SIZE] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec non dolor tincidunt, vehicula erat non, pulvinar nisl. Suspendisse gravida commodo hendrerit. Sed ex magna, aliquet malesuada lectus ut, porttitor tincidunt ante. Nulla facilisi. Morbi nec scelerisque risus. Sed a gravida sapien. Cras sed neque bibendum, dapibus lectus sed, porta nulla. Morbi tristique velit lacus, at luctus turpis mollis sed. Nam quis sapien eu magna cursus venenatis. Phasellus et vestibulum urna, non pellentesque ex. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pretium aliquam porta.\ Morbi magna metus, commodo in fermentum id, mattis pretium mauris. Donec sed rhoncus justo. Duis fringilla sem quis velit dignissim bibendum. Sed porta efficitur ipsum, in dignissim magna molestie eu. Sed elementum maximus risus. Quisque cursus urna lectus, sit amet fringilla purus tempor eu. Praesent tincidunt dolor sit amet dolor vulputate, et molestie tellus euismod. Proin suscipit dictum amet."; -const char *lorem4096 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus congue semper ipsum, ac convallis magna rhoncus sit amet. Donec pellentesque maximus convallis. Mauris ut egestas sem. Maecenas efficitur suscipit auctor. Nunc malesuada laoreet porttitor. Donec gravida tortor nisi, in mattis lectus porta ut. Integer vehicula eros et tellus placerat, nec fermentum justo aliquet.\ +const char lorem4096[LOREM4096_SIZE] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus congue semper ipsum, ac convallis magna rhoncus sit amet. Donec pellentesque maximus convallis. Mauris ut egestas sem. Maecenas efficitur suscipit auctor. Nunc malesuada laoreet porttitor. Donec gravida tortor nisi, in mattis lectus porta ut. Integer vehicula eros et tellus placerat, nec fermentum justo aliquet.\ Maecenas metus massa, ultrices et ultricies sed, imperdiet nec dolor. Nam eget massa eros. Proin vitae laoreet metus, at scelerisque massa. Nullam convallis dolor id nisl iaculis, a gravida risus pretium. Proin non nunc eget nibh fermentum dignissim. Nullam tristique, odio eget rutrum sagittis, tortor purus cursus nunc, nec iaculis quam nunc ac metus. Cras ut tortor a eros porta vehicula non at lectus. Aliquam volutpat quis nisi ut mattis. Curabitur semper vehicula ultrices. Aenean cursus laoreet venenatis. Aenean vulputate, nisl id facilisis fringilla, neque velit posuere libero, et viverra tortor felis vitae urna. Sed in congue nunc. Fusce molestie tempor pharetra. Cras sodales pulvinar nunc non sollicitudin.\ Maecenas vehicula metus ac tristique ultricies. Suspendisse potenti. Pellentesque suscipit egestas augue, sed dictum orci. Pellentesque eu lorem ultricies, vestibulum est in, bibendum turpis. Proin placerat tincidunt metus, eget volutpat dolor. Pellentesque varius leo eget velit lobortis, sit amet congue orci bibendum. Aliquam vitae posuere lorem. Donec sed convallis diam. Quisque aliquam interdum purus, eu ornare ex ullamcorper iaculis. In sit amet nisl eu nisl ultricies dapibus. Aenean finibus efficitur elit ut sodales. Nam sit amet auctor sem, eu iaculis nunc. Vivamus mattis arcu a viverra faucibus. In dignissim, nisi sit amet consectetur tempus, lorem dui fringilla augue, sit amet lacinia lectus sapien efficitur odio.\ Nullam et egestas enim. Nam sit amet mi malesuada, dapibus felis quis, viverra mauris. Ut quis enim eu neque porta vehicula. Etiam ullamcorper vitae turpis vehicula blandit. Maecenas blandit tristique semper. Aliquam at sagittis enim. Donec quis molestie urna. Duis ut urna blandit, pellentesque magna ultrices, dignissim mi. Morbi fermentum ex massa, ut facilisis est tincidunt vel. Nam sed erat in lacus molestie mattis quis ut leo. Phasellus tempus elit urna, eget sagittis purus volutpat sed. Suspendisse aliquam, sem vel gravida lobortis, tortor orci ornare nisi, sed mollis ligula sem nec risus. In a ex nibh. Praesent odio est, molestie sed vestibulum id, varius sit amet lectus. Donec vel diam efficitur, tristique ligula a, aliquet felis. Nullam sit amet neque tellus.\ diff --git a/examples/lorem.h b/examples/lorem.h index 1b7ceb5..1b02d19 100644 --- a/examples/lorem.h +++ b/examples/lorem.h @@ -24,12 +24,22 @@ #ifndef LOREM_H #define LOREM_H +#include + /** Test strings, sizes include null-termination */ -extern const char *lorem8; -extern const char *lorem16; -extern const char *lorem1024; -extern const char *lorem4096; +extern const char lorem8[]; +extern const char lorem16[]; +extern const char lorem1024[]; +extern const char lorem4096[]; + +/** + * Sizes of test strings + */ +#define LOREM8_SIZE ((size_t)8) +#define LOREM16_SIZE ((size_t)16) +#define LOREM1024_SIZE ((size_t)1024) +#define LOREM4096_SIZE ((size_t)4096) #endif -- 2.7.4 From 7979a7584e6e0898ec68dddde6d495edad6db5c8 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Wed, 13 Apr 2016 14:45:16 +0200 Subject: [PATCH 09/16] crypto.h: rename yaca_get_iv_length() to yaca_get_iv_bits() Function returns IV length in bits - rename it to avoid confusion. Change-Id: I58f565e1ca96321856f099d55ec456f23be1dbe0 Signed-off-by: Mateusz Kulikowski --- api/yaca/crypto.h | 10 +++++----- src/crypto.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/yaca/crypto.h b/api/yaca/crypto.h index 66d77e6..1b9feab 100644 --- a/api/yaca/crypto.h +++ b/api/yaca/crypto.h @@ -163,17 +163,17 @@ int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len); #define yaca_get_block_length(ctxa) yaca_get_output_length((ctxa), 0) /** - * @brief yaca_get_iv_length Returns the recomended/default length of the IV for a given encryption configuration. + * @brief yaca_get_iv_bits Returns the recomended/default length of the IV for a given encryption configuration. * * @param[in] algo Encryption algorithm. * @param[in] bcm Chain mode. * @param[in] key_bits Key length in bits (@see crypto_key_len_e). * - * @return negative on error (@see error.h) or the IV length. + * @return negative on error (@see error.h) or the IV length in bits. */ -int yaca_get_iv_length(yaca_enc_algo_e algo, - yaca_block_cipher_mode_e bcm, - size_t key_bits); +int yaca_get_iv_bits(yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + size_t key_bits); /**@}*/ diff --git a/src/crypto.c b/src/crypto.c index af73404..9081bcf 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -108,9 +108,9 @@ API int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len) return ctx->get_output_length(ctx, input_len); } -API int yaca_get_iv_length(yaca_enc_algo_e algo, - yaca_block_cipher_mode_e bcm, - size_t key_bits) +API int yaca_get_iv_bits(yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + size_t key_bits) { return YACA_ERROR_NOT_IMPLEMENTED; } -- 2.7.4 From 144545c77f8b73340d9f684a8ccea404692a777f Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Mon, 11 Apr 2016 11:58:52 +0200 Subject: [PATCH 10/16] Encrypt example update - Handle outputs allocation properly - Calculate IV lengths - Generate IV properly Change-Id: I3ae9c15dac9fa36bb308846fc4c33c61296ca819 Signed-off-by: Mateusz Kulikowski --- examples/encrypt.c | 134 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 45 deletions(-) diff --git a/examples/encrypt.c b/examples/encrypt.c index 8ca1bc1..f428713 100644 --- a/examples/encrypt.c +++ b/examples/encrypt.c @@ -33,6 +33,9 @@ // Symmetric encryption using simple API void encrypt_simple(void) { + const yaca_enc_algo_e algo = YACA_ENC_AES; + const yaca_block_cipher_mode_e bcm = YACA_BCM_CBC; + const size_t key_bits = YACA_KEY_256BIT; int ret; yaca_key_h key = YACA_KEY_NULL; yaca_key_h iv = YACA_KEY_NULL; @@ -40,30 +43,35 @@ void encrypt_simple(void) char *dec_data = NULL; size_t enc_len; size_t dec_len; + int iv_bits; - printf("Plain data (16 of %zu bytes): %.16s\n", (size_t)1024, lorem1024); + printf("Simple Encrypt\nPlain data (16 of %zu bytes): %.16s\n", + LOREM1024_SIZE, lorem1024); - ret = yaca_key_derive_pbkdf2("foo bar", "123456789", 10, - 1000, YACA_DIGEST_SHA256, - YACA_KEY_256BIT, &key); + ret = yaca_key_derive_pbkdf2("foo bar", "123456789", 10, 1000, + YACA_DIGEST_SHA256, key_bits, &key); if (ret) return; - ret = yaca_key_gen(&iv, YACA_KEY_TYPE_IV, YACA_KEY_IV_256BIT); - if (ret) - goto exit; + iv_bits = yaca_get_iv_bits(algo, bcm, key_bits); + if (iv_bits < 0) + return; + + if (iv_bits > 0) { + ret = yaca_key_gen(&iv, YACA_KEY_TYPE_IV, iv_bits); + if (ret) + goto exit; + } - ret = yaca_encrypt(YACA_ENC_AES, YACA_BCM_CBC, - key, iv, lorem1024, 1024, &enc_data, &enc_len); + ret = yaca_encrypt(algo, bcm, key, iv, lorem1024, LOREM1024_SIZE, + &enc_data, &enc_len); if (ret) goto exit; dump_hex(enc_data, 16, "Encrypted data (16 of %zu bytes): ", enc_len); - ret = yaca_decrypt(YACA_ENC_AES, YACA_BCM_CBC, - key, iv, - enc_data, enc_len, - &dec_data, &dec_len); + ret = yaca_decrypt(algo, bcm, key, iv, enc_data, enc_len, &dec_data, + &dec_len); if (ret < 0) goto exit; @@ -81,6 +89,9 @@ exit: // Symmetric encryption using advanced API void encrypt_advanced(void) { + const yaca_enc_algo_e algo = YACA_ENC_AES; + const yaca_block_cipher_mode_e bcm = YACA_BCM_CBC; + const size_t key_bits = YACA_KEY_256BIT; int ret; yaca_ctx_h ctx; yaca_key_h key = YACA_KEY_NULL; @@ -89,86 +100,113 @@ void encrypt_advanced(void) char *dec = NULL; size_t enc_size; size_t dec_size; + int iv_bits; - printf("Plain data (16 of %zu bytes): %.16s\n", (size_t)4096, lorem1024); + printf("Advanced Encrypt\nPlain data (16 of %zu bytes): %.16s\n", + LOREM4096_SIZE, lorem4096); /// Key generation - ret = yaca_key_derive_pbkdf2("foo bar", "123456789", 10, - 1000, YACA_DIGEST_SHA256, - YACA_KEY_256BIT, &key); + ret = yaca_key_derive_pbkdf2("foo bar", "123456789", 10, 1000, + YACA_DIGEST_SHA256, key_bits, &key); if (ret) return; - ret = yaca_key_gen(&iv, YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_IV_256BIT); - if (ret) + iv_bits = yaca_get_iv_bits(algo, bcm, key_bits); + if (iv_bits < 0) goto ex_key; + if (iv_bits > 0) { + ret = yaca_key_gen(&iv, YACA_KEY_TYPE_IV, iv_bits); + if (ret) + goto ex_key; + } + /// Encryption { - ret = yaca_encrypt_init(&ctx, YACA_ENC_AES, YACA_BCM_CBC, - key, iv); + size_t block_len; + size_t output_len; + size_t out_size; + size_t rem; + + ret = yaca_encrypt_init(&ctx, algo, bcm, key, iv); if (ret) goto ex_iv; - ret = yaca_encrypt_update(ctx, lorem4096, 4096, NULL, &enc_size); - if (ret != 42) - goto ex_ctx;// TODO: what error code? - ret = yaca_get_block_length(ctx); if (ret < 0) goto ex_ctx; - enc_size += ret ; // Add block size for finalize + block_len = ret; + + ret = yaca_get_output_length(ctx, LOREM4096_SIZE); + if (ret < 0) + goto ex_ctx; + + output_len = ret; + + /* Calculate max output: size of update + final chunks */ + enc_size = output_len + block_len; enc = yaca_malloc(enc_size); if (enc == NULL) goto ex_ctx; - size_t out_size = enc_size; - ret = yaca_encrypt_update(ctx, lorem4096, 4096, enc, &out_size); + out_size = enc_size; + ret = yaca_encrypt_update(ctx, lorem4096, LOREM4096_SIZE, enc, + &out_size); if (ret < 0) goto ex_of; - size_t rem = enc_size - out_size; + rem = enc_size - out_size; ret = yaca_encrypt_final(ctx, enc + out_size, &rem); if (ret < 0) goto ex_of; enc_size = rem + out_size; - dump_hex(enc, 16, "Encrypted data (16 of %zu bytes): ", enc_size); + dump_hex(enc, 16, "Encrypted data (16 of %zu bytes): ", + enc_size); yaca_ctx_free(ctx); // TODO: perhaps it should not return value } /// Decryption { - ret = yaca_decrypt_init(&ctx, YACA_ENC_AES, YACA_BCM_CBC, - key, iv); + size_t block_len; + size_t output_len; + size_t out_size; + size_t rem; + + ret = yaca_decrypt_init(&ctx, algo, bcm, key, iv); if (ret < 0) { - yaca_free(enc); - goto ex_iv; + ctx = YACA_CTX_NULL; + goto ex_of; } - ret = yaca_decrypt_update(ctx, enc, enc_size, NULL, &dec_size); - if (ret != 42) - goto ex_of; // TODO: what error code? - ret = yaca_get_block_length(ctx); if (ret < 0) goto ex_of; - dec_size += ret; // Add block size for finalize + block_len = ret; + + ret = yaca_get_output_length(ctx, LOREM4096_SIZE); + if (ret < 0) + goto ex_ctx; + + output_len = ret; + + /* Calculate max output: size of update + final chunks */ + dec_size = output_len + block_len; dec = yaca_malloc(dec_size); if (dec == NULL) goto ex_of; - size_t out_size = dec_size; + out_size = dec_size; ret = yaca_decrypt_update(ctx, enc, enc_size, dec, &out_size); if (ret < 0) goto ex_in; - size_t rem = dec_size - out_size; + rem = dec_size - out_size; ret = yaca_encrypt_final(ctx, dec + out_size, &rem); if (ret < 0) goto ex_in; @@ -214,6 +252,9 @@ void encrypt_seal(void) /// Encrypt a.k.a. seal { + size_t out_size; + size_t rem; + ret = yaca_seal_init(&ctx, key_pub, YACA_ENC_AES, YACA_BCM_CBC, &aes_key, &iv); @@ -234,12 +275,12 @@ void encrypt_seal(void) goto ex_ak; // Seal and finalize - size_t out_size = enc_size; + out_size = enc_size; ret = yaca_seal_update(ctx, lorem4096, 4096, enc, &out_size); if (ret < 0) goto ex_of; - size_t rem = enc_size - out_size; + rem = enc_size - out_size; ret = yaca_seal_final(ctx, enc + out_size, &rem); if (ret < 0) goto ex_of; @@ -253,6 +294,9 @@ void encrypt_seal(void) /// Decrypt a.k.a. open { + size_t out_size; + size_t rem; + ret = yaca_open_init(&ctx, key_priv, YACA_ENC_AES, YACA_BCM_CBC, aes_key, iv); @@ -275,12 +319,12 @@ void encrypt_seal(void) goto ex_of; // Seal and finalize - size_t out_size = enc_size; + out_size = enc_size; ret = yaca_open_update(ctx, enc, enc_size, dec, &out_size); if (ret < 0) goto ex_in; - size_t rem = dec_size - out_size; + rem = dec_size - out_size; ret = yaca_open_final(ctx, dec + out_size, &rem); if (ret < 0) goto ex_in; -- 2.7.4 From 455ddca22cb754e2a344b506a2fbbd28b0211c5d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Mon, 11 Apr 2016 12:40:18 +0200 Subject: [PATCH 11/16] simple: Handle encrypt/decrypt block sizes properly - Calculate output block sizes properly - Resize output allocations to size output Change-Id: I58cc4530f9b832375c20c79c9883910adaaccc67 Signed-off-by: Mateusz Kulikowski --- src/simple.c | 62 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/simple.c b/src/simple.c index ce1d5f3..ff7f19e 100644 --- a/src/simple.c +++ b/src/simple.c @@ -90,6 +90,7 @@ API int yaca_encrypt(yaca_enc_algo_e algo, yaca_ctx_h ctx; int ret; char *lcipher; + char *rcipher; size_t out_len, lcipher_len, written; if (plain == NULL || plain_len == 0 || cipher == NULL || cipher_len == NULL || @@ -100,21 +101,28 @@ API int yaca_encrypt(yaca_enc_algo_e algo, return YACA_ERROR_TOO_BIG_ARGUMENT; ret = yaca_encrypt_init(&ctx, algo, bcm, sym_key, iv); - if (ret < 0) + if (ret != 0) return ret; - ret = yaca_get_output_length(ctx, plain_len); - if (ret < 0) + ret = yaca_get_block_length(ctx); + if (ret <= 0) goto err; lcipher_len = ret; + + ret = yaca_get_output_length(ctx, plain_len); + if (ret <= 0) + goto err; + + lcipher_len += ret; + lcipher = yaca_malloc(lcipher_len); if (lcipher == NULL) goto err; out_len = lcipher_len; ret = yaca_encrypt_update(ctx, plain, plain_len, lcipher, &out_len); - if (ret < 0) + if (ret != 0) goto err_free; assert (out_len <= lcipher_len); @@ -122,15 +130,22 @@ API int yaca_encrypt(yaca_enc_algo_e algo, written = out_len; out_len = lcipher_len - written; ret = yaca_encrypt_final(ctx, lcipher + written, &out_len); - if (ret < 0) + if (ret != 0) goto err_free; - assert (out_len + written == lcipher_len); + written += out_len; + assert (written <= lcipher_len); + + rcipher = yaca_realloc(lcipher, written); + if (rcipher == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + goto err_free; + } yaca_ctx_free(ctx); - *cipher = lcipher; - *cipher_len = lcipher_len; + *cipher = rcipher; + *cipher_len = written; return 0; err_free: @@ -152,6 +167,7 @@ API int yaca_decrypt(yaca_enc_algo_e algo, yaca_ctx_h ctx; int ret; char *lplain; + char *rplain; size_t out_len, lplain_len, written; if (cipher == NULL || cipher_len == 0 || plain == NULL || plain_len == NULL || @@ -162,21 +178,28 @@ API int yaca_decrypt(yaca_enc_algo_e algo, return YACA_ERROR_TOO_BIG_ARGUMENT; ret = yaca_decrypt_init(&ctx, algo, bcm, sym_key, iv); - if (ret < 0) + if (ret != 0) return ret; - ret = yaca_get_output_length(ctx, cipher_len); - if (ret < 0) + ret = yaca_get_block_length(ctx); + if (ret <= 0) goto err; lplain_len = ret; + + ret = yaca_get_output_length(ctx, cipher_len); + if (ret <= 0) + goto err; + + lplain_len += ret; + lplain = yaca_malloc(lplain_len); if (!lplain) goto err; out_len = lplain_len; ret = yaca_decrypt_update(ctx, cipher, cipher_len, lplain, &out_len); - if (ret < 0) + if (ret != 0) goto err_free; assert(out_len <= lplain_len); @@ -184,15 +207,22 @@ API int yaca_decrypt(yaca_enc_algo_e algo, written = out_len; out_len = lplain_len - written; ret = yaca_decrypt_final(ctx, lplain + written, &out_len); - if (ret < 0) + if (ret != 0) goto err_free; - assert(out_len + written == lplain_len); + written += out_len; + assert(written <= lplain_len); + + rplain = yaca_realloc(lplain, written); + if (rplain == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + goto err_free; + } yaca_ctx_free(ctx); - *plain = lplain; - *plain_len = lplain_len; + *plain = rplain; + *plain_len = written; return 0; err_free: -- 2.7.4 From c06a90476453190abfe4b143094c91719a0ce9e0 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Mon, 11 Apr 2016 15:27:21 +0200 Subject: [PATCH 12/16] internal.h: add YACA_CTX_ENCRYPT It is context for encryption Change-Id: Icb8ebbb9804edca48cab3d6523a9e27c3ab30fe1 Signed-off-by: Mateusz Kulikowski --- src/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal.h b/src/internal.h index deeff97..504fb6d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -35,7 +35,8 @@ enum yaca_ctx_type_e { YACA_CTX_INVALID = 0, YACA_CTX_DIGEST, - YACA_CTX_SIGN + YACA_CTX_SIGN, + YACA_CTX_ENCRYPT, }; /* Base structure for crypto contexts - to be inherited */ -- 2.7.4 From 9b3d768ceec9e8f051f6f140361a82c231b6a063 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Mon, 11 Apr 2016 15:31:50 +0200 Subject: [PATCH 13/16] encrypt: add get_symmetric_algorithm Implement function to map yaca algorithm enums to EVP_CIPHER. It is currently not very fast, and doesn't handle all algorithms/modes supported by yaca. Change-Id: I34c9a78044561b7fdcdc9e23632e45ff745e7f34 Signed-off-by: Mateusz Kulikowski --- src/encrypt.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/encrypt.c b/src/encrypt.c index ca8fa1d..596a1a4 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -20,12 +20,90 @@ #include #include +#include #include #include #include "internal.h" +static const char *symmetric_algo_to_str(yaca_enc_algo_e algo) +{ + switch(algo) + { + case YACA_ENC_AES: + return "aes"; + case YACA_ENC_UNSAFE_DES: + return "des"; + case YACA_ENC_UNSAFE_RC2: + return "rc2"; + case YACA_ENC_UNSAFE_RC4: + return "rc4"; + case YACA_ENC_CAST5: + return "cast5"; + + case YACA_ENC_UNSAFE_3DES_2TDEA: // TODO: add 3des/2tdea support + case YACA_ENC_3DES_3TDEA: // TODO: add 3des/3tdea support + case YACA_ENC_UNSAFE_SKIPJACK: // TODO: add skipjack implementation + default: + return NULL; + } +} + +static const char *bcm_to_str(yaca_block_cipher_mode_e bcm) +{ + switch (bcm) { + case YACA_BCM_ECB: + return "ecb"; + case YACA_BCM_CBC: + return "cbc"; + case YACA_BCM_CTR: + return "ctr"; + case YACA_BCM_GCM: + return "gcm"; + case YACA_BCM_CFB: + return "cfb"; + case YACA_BCM_OFB: + return "ofb"; + case YACA_BCM_OCB: + return "ocb"; + case YACA_BCM_CCM: + return "ccm"; + default: + return NULL; + } +} + +int get_symmetric_algorithm(yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + unsigned key_bits, + const EVP_CIPHER **cipher) +{ + char cipher_name[32]; + const char *algo_name = symmetric_algo_to_str(algo); + const char *bcm_name = bcm_to_str(bcm); + const EVP_CIPHER *lcipher; + int ret; + + if (algo_name == NULL || bcm_name == NULL || key_bits == 0 || + cipher == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + ret = snprintf(cipher_name, sizeof(cipher_name), "%s-%d-%s", algo_name, + key_bits, bcm_name); + if (ret < 0) + return YACA_ERROR_INVALID_ARGUMENT; + if ((unsigned)ret >= sizeof(cipher_name)) // output was truncated + return YACA_ERROR_INVALID_ARGUMENT; + + lcipher = EVP_get_cipherbyname(cipher_name); + if (lcipher == NULL) + return YACA_ERROR_OPENSSL_FAILURE; // TODO: yaca_get_error_code_from_openssl(ret); + + *cipher = lcipher; + return 0; +} + API int yaca_encrypt_init(yaca_ctx_h *ctx, yaca_enc_algo_e algo, yaca_block_cipher_mode_e bcm, -- 2.7.4 From d9a512a7d78824e32106717770071f38dba97615 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Mon, 11 Apr 2016 15:33:39 +0200 Subject: [PATCH 14/16] Implement yaca_get_iv_bits() Move code to encrypt* as it's encryption related. Change-Id: Id9b5072e3fb220aaffcc0f1aad5f2b0893fa06ed Signed-off-by: Mateusz Kulikowski --- api/yaca/crypto.h | 13 ------------- api/yaca/encrypt.h | 13 +++++++++++++ src/crypto.c | 7 ------- src/encrypt.c | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/api/yaca/crypto.h b/api/yaca/crypto.h index 1b9feab..cd30ff2 100644 --- a/api/yaca/crypto.h +++ b/api/yaca/crypto.h @@ -162,19 +162,6 @@ int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len); */ #define yaca_get_block_length(ctxa) yaca_get_output_length((ctxa), 0) -/** - * @brief yaca_get_iv_bits Returns the recomended/default length of the IV for a given encryption configuration. - * - * @param[in] algo Encryption algorithm. - * @param[in] bcm Chain mode. - * @param[in] key_bits Key length in bits (@see crypto_key_len_e). - * - * @return negative on error (@see error.h) or the IV length in bits. - */ -int yaca_get_iv_bits(yaca_enc_algo_e algo, - yaca_block_cipher_mode_e bcm, - size_t key_bits); - /**@}*/ #ifdef __cplusplus diff --git a/api/yaca/encrypt.h b/api/yaca/encrypt.h index 38e565f..e94fb37 100644 --- a/api/yaca/encrypt.h +++ b/api/yaca/encrypt.h @@ -247,6 +247,19 @@ int yaca_open_final(yaca_ctx_h ctx, char *plain, size_t *plain_len); +/** + * @brief yaca_get_iv_bits Returns the recomended/default length of the IV for a given encryption configuration. + * + * @param[in] algo Encryption algorithm. + * @param[in] bcm Chain mode. + * @param[in] key_bits Key length in bits (@see crypto_key_len_e). + * + * @return negative on error (@see error.h) or the IV length in bits. + */ +int yaca_get_iv_bits(yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + size_t key_bits); + /**@}*/ #ifdef __cplusplus diff --git a/src/crypto.c b/src/crypto.c index 9081bcf..4a49071 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -107,10 +107,3 @@ API int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len) return ctx->get_output_length(ctx, input_len); } - -API int yaca_get_iv_bits(yaca_enc_algo_e algo, - yaca_block_cipher_mode_e bcm, - size_t key_bits) -{ - return YACA_ERROR_NOT_IMPLEMENTED; -} diff --git a/src/encrypt.c b/src/encrypt.c index 596a1a4..bfd730d 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -104,6 +104,20 @@ int get_symmetric_algorithm(yaca_enc_algo_e algo, return 0; } +API int yaca_get_iv_bits(yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + size_t key_bits) +{ + const EVP_CIPHER *cipher; + int ret; + + ret = get_symmetric_algorithm(algo, bcm, key_bits, &cipher); + if (ret < 0) + return ret; + + return EVP_CIPHER_iv_length(cipher) * 8; +} + API int yaca_encrypt_init(yaca_ctx_h *ctx, yaca_enc_algo_e algo, yaca_block_cipher_mode_e bcm, -- 2.7.4 From 31eb3c7613d4f96d309d781e64929cfef366b07b Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Mon, 11 Apr 2016 15:10:17 +0200 Subject: [PATCH 15/16] Add package with examples. Change-Id: Idd9fee1bdc3588721fb74f1dca3ff570e827a757 --- CMakeLists.txt | 8 ++++++++ examples/CMakeLists.txt | 5 +++++ packaging/yaca.spec | 25 ++++++++++++++++++------- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a42b702..0c2f401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,14 @@ IF(NOT DEFINED BIN_INSTALL_DIR) SET(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}") ENDIF(NOT DEFINED BIN_INSTALL_DIR) +IF(NOT DEFINED SHARE_INSTALL_PREFIX) + SET(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share") +ENDIF(NOT DEFINED SHARE_INSTALL_PREFIX) + +IF(NOT DEFINED EXAMPLES_DIR) + SET(EXAMPLES_DIR "${SHARE_INSTALL_PREFIX}/${PROJECT_NAME}/examples") +ENDIF(NOT DEFINED EXAMPLES_DIR) + ADD_SUBDIRECTORY(${SRC_FOLDER}) #ADD_SUBDIRECTORY(${TEST_FOLDER}) ADD_SUBDIRECTORY(${EXAMPLES_FOLDER}) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 160ec0e..6413bad 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -45,6 +45,8 @@ FUNCTION(BUILD_EXAMPLE EXAMPLE_NAME SOURCE_FILE) WORLD_READ WORLD_EXECUTE ) + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE} + DESTINATION ${EXAMPLES_DIR}) ENDFUNCTION(BUILD_EXAMPLE) BUILD_EXAMPLE("yaca-example-digest" digest.c) @@ -53,3 +55,6 @@ BUILD_EXAMPLE("yaca-example-encrypt-gcm" encrypt_aes_gcm.c) BUILD_EXAMPLE("yaca-example-sign" sign.c) BUILD_EXAMPLE("yaca-example-key-exchange" key_exchange.c) BUILD_EXAMPLE("yaca-example-test" test.c) + +INSTALL(FILES ${COMMON_SOURCES} + DESTINATION ${EXAMPLES_DIR}) diff --git a/packaging/yaca.spec b/packaging/yaca.spec index bfef0c7..126018c 100644 --- a/packaging/yaca.spec +++ b/packaging/yaca.spec @@ -13,10 +13,13 @@ Requires(postun): /sbin/ldconfig %description The package provides Yet Another Crypto API. +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + %files -%defattr(644,root,root,755) %{_libdir}/libyaca.so.0 -%attr(755,root,root) %{_libdir}/libyaca.so.%{version} +%{_libdir}/libyaca.so.%{version} %prep %setup -q @@ -33,10 +36,6 @@ make -k %{?jobs:-j%jobs} %clean rm -rf %{buildroot} -%post -n yaca -p /sbin/ldconfig - -%postun -n yaca -p /sbin/ldconfig - ## Devel Package ############################################################### %package devel Summary: Yet Another Crypto API development files @@ -47,7 +46,19 @@ Requires: yaca = %{version}-%{release} The package provides Yet Another Crypto API development files. %files devel -%defattr(644,root,root,755) %{_libdir}/libyaca.so %{_includedir}/yaca %{_libdir}/pkgconfig/yaca.pc + +## Examples Package ############################################################ +%package examples +Summary: Yet Another Crypto API example files +Group: Security/Other +Requires: yaca = %{version}-%{release} + +%description examples +The package provides Yet Another Crypto API example files. + +%files examples +%{_bindir}/yaca-example* +%{_datadir}/%{name}/examples -- 2.7.4 From 4db7c072c298f0b816a8fe079279fb9a104d653d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Mon, 11 Apr 2016 15:35:20 +0200 Subject: [PATCH 16/16] Implement limited symmetric cipher support Change-Id: I5b130e3e1d41cfcce1f730f3d1b316c088432677 Signed-off-by: Mateusz Kulikowski --- src/encrypt.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 247 insertions(+), 13 deletions(-) diff --git a/src/encrypt.c b/src/encrypt.c index bfd730d..d195800 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -17,17 +17,75 @@ */ #include +#include #include #include #include #include +#include #include +#include #include "internal.h" -static const char *symmetric_algo_to_str(yaca_enc_algo_e algo) +enum encrypt_op_type { + OP_ENCRYPT = 0, + OP_DECRYPT = 1 +}; + +struct yaca_encrypt_ctx_s +{ + struct yaca_ctx_s ctx; + + EVP_CIPHER_CTX *cipher_ctx; + enum encrypt_op_type op_type; /* Operation context was created for */ +}; + +static struct yaca_encrypt_ctx_s *get_encrypt_ctx(const yaca_ctx_h ctx) +{ + if (ctx == YACA_CTX_NULL) + return NULL; + + switch (ctx->type) + { + case YACA_CTX_ENCRYPT: + return (struct yaca_encrypt_ctx_s *)ctx; + default: + return NULL; + } +} + +static void destroy_encrypt_ctx(const yaca_ctx_h ctx) +{ + struct yaca_encrypt_ctx_s *nc = get_encrypt_ctx(ctx); + + if (nc == NULL) + return; + + EVP_CIPHER_CTX_free(nc->cipher_ctx); + nc->cipher_ctx = NULL; +} + +static int get_encrypt_output_length(const yaca_ctx_h ctx, size_t input_len) +{ + struct yaca_encrypt_ctx_s *nc = get_encrypt_ctx(ctx); + int block_size; + + if (nc == NULL || nc->cipher_ctx == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + block_size = EVP_CIPHER_CTX_block_size(nc->cipher_ctx); + if (block_size == 0) + return YACA_ERROR_OPENSSL_FAILURE; // TODO: extract openssl error here + + if (input_len > 0) + return block_size + input_len - 1; + return block_size; +} + +static const char *encrypt_algo_to_str(yaca_enc_algo_e algo) { switch(algo) { @@ -74,13 +132,13 @@ static const char *bcm_to_str(yaca_block_cipher_mode_e bcm) } } -int get_symmetric_algorithm(yaca_enc_algo_e algo, - yaca_block_cipher_mode_e bcm, - unsigned key_bits, - const EVP_CIPHER **cipher) +int get_encrypt_algorithm(yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + unsigned key_bits, + const EVP_CIPHER **cipher) { char cipher_name[32]; - const char *algo_name = symmetric_algo_to_str(algo); + const char *algo_name = encrypt_algo_to_str(algo); const char *bcm_name = bcm_to_str(bcm); const EVP_CIPHER *lcipher; int ret; @@ -104,6 +162,178 @@ int get_symmetric_algorithm(yaca_enc_algo_e algo, return 0; } +static int encrypt_init(yaca_ctx_h *ctx, + yaca_enc_algo_e algo, + yaca_block_cipher_mode_e bcm, + const yaca_key_h sym_key, + const yaca_key_h iv, + enum encrypt_op_type op_type) +{ + const struct yaca_key_simple_s *lkey; + const struct yaca_key_simple_s *liv; + struct yaca_encrypt_ctx_s *nc; + const EVP_CIPHER *cipher; + int key_bits; + int iv_bits; + int ret; + + if (ctx == NULL || sym_key == YACA_KEY_NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + lkey = key_get_simple(sym_key); + if (lkey == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + nc = yaca_malloc(sizeof(struct yaca_encrypt_ctx_s)); + if (nc == NULL) + return YACA_ERROR_OUT_OF_MEMORY; + + memset(nc, 0, sizeof(struct yaca_encrypt_ctx_s)); + + nc->ctx.type = YACA_CTX_ENCRYPT; + nc->ctx.ctx_destroy = destroy_encrypt_ctx; + nc->ctx.get_output_length = get_encrypt_output_length; + nc->op_type = op_type; + + // TODO: handling of algorithms with variable key length + ret = yaca_key_get_length(sym_key); + if (ret < 0) + goto err_free; + key_bits = ret; + + ret = get_encrypt_algorithm(algo, bcm, key_bits, &cipher); + if (ret != 0) + goto err_free; + + ret = EVP_CIPHER_iv_length(cipher); + if (ret < 0) + goto err_free; + + iv_bits = ret * 8; + if (iv_bits == 0 && iv != NULL) { /* 0 -> cipher doesn't use iv, but it was provided */ + ret = YACA_ERROR_INVALID_ARGUMENT; + goto err_free; + } + + liv = key_get_simple(iv); + if (ret != 0 && liv == NULL) { /* cipher requires iv, but none was provided */ + ret = YACA_ERROR_INVALID_ARGUMENT; + goto err_free; + } + + // TODO: handling of algorithms with variable IV length + if (iv_bits != yaca_key_get_length(iv)) { /* IV length doesn't match cipher */ + ret = YACA_ERROR_INVALID_ARGUMENT; + goto err_free; + } + + nc->cipher_ctx = EVP_CIPHER_CTX_new(); + if (nc->cipher_ctx == NULL) { + ret = YACA_ERROR_OPENSSL_FAILURE; // TODO: yaca_get_error_code_from_openssl(ret); + goto err_free; + } + + switch (op_type) { + case OP_ENCRYPT: + ret = EVP_EncryptInit(nc->cipher_ctx, cipher, + (unsigned char*)lkey->d, + (unsigned char*)liv->d); + break; + case OP_DECRYPT: + ret = EVP_DecryptInit(nc->cipher_ctx, cipher, + (unsigned char*)lkey->d, + (unsigned char*)liv->d); + break; + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto err_ctx; + } + + if (ret != 1) { + ret = YACA_ERROR_OPENSSL_FAILURE; // TODO: yaca_get_error_code_from_openssl(ret); + goto err_ctx; + } + + *ctx = (yaca_ctx_h)nc; + return 0; + +err_ctx: + EVP_CIPHER_CTX_free(nc->cipher_ctx); +err_free: + yaca_free(nc); + return ret; +} + +static int encrypt_update(yaca_ctx_h ctx, + const unsigned char *input, + size_t input_len, + unsigned char *output, + size_t *output_len, + enum encrypt_op_type op_type) +{ + struct yaca_encrypt_ctx_s *c = get_encrypt_ctx(ctx); + int ret; + int loutput_len; + + if (c == NULL || input == NULL || input_len == 0 || + output == NULL || output_len == NULL || op_type != c->op_type) + return YACA_ERROR_INVALID_ARGUMENT; + + loutput_len = *output_len; + + switch (op_type) { + case OP_ENCRYPT: + ret = EVP_EncryptUpdate(c->cipher_ctx, output, &loutput_len, + input, input_len); + break; + case OP_DECRYPT: + ret = EVP_DecryptUpdate(c->cipher_ctx, output, &loutput_len, + input, input_len); + break; + default: + return YACA_ERROR_INVALID_ARGUMENT; + } + + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; // TODO: yaca_get_error_code_from_openssl(ret); + + *output_len = loutput_len; + return 0; +} + +static int encrypt_final(yaca_ctx_h ctx, + unsigned char *output, + size_t *output_len, + enum encrypt_op_type op_type) +{ + struct yaca_encrypt_ctx_s *c = get_encrypt_ctx(ctx); + int ret; + int loutput_len; + + if (c == NULL || output == NULL || output_len == NULL || + op_type != c->op_type) + return YACA_ERROR_INVALID_ARGUMENT; + + loutput_len = *output_len; + + switch (op_type) { + case OP_ENCRYPT: + ret = EVP_EncryptFinal(c->cipher_ctx, output, &loutput_len); + break; + case OP_DECRYPT: + ret = EVP_DecryptFinal(c->cipher_ctx, output, &loutput_len); + break; + default: + return YACA_ERROR_INVALID_ARGUMENT; + } + + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; // TODO: yaca_get_error_code_from_openssl(ret); + + *output_len = loutput_len; + return 0; +} + API int yaca_get_iv_bits(yaca_enc_algo_e algo, yaca_block_cipher_mode_e bcm, size_t key_bits) @@ -111,7 +341,7 @@ API int yaca_get_iv_bits(yaca_enc_algo_e algo, const EVP_CIPHER *cipher; int ret; - ret = get_symmetric_algorithm(algo, bcm, key_bits, &cipher); + ret = get_encrypt_algorithm(algo, bcm, key_bits, &cipher); if (ret < 0) return ret; @@ -124,7 +354,7 @@ API int yaca_encrypt_init(yaca_ctx_h *ctx, const yaca_key_h sym_key, const yaca_key_h iv) { - return YACA_ERROR_NOT_IMPLEMENTED; + return encrypt_init(ctx, algo, bcm, sym_key, iv, OP_ENCRYPT); } API int yaca_encrypt_update(yaca_ctx_h ctx, @@ -133,14 +363,16 @@ API int yaca_encrypt_update(yaca_ctx_h ctx, char *cipher, size_t *cipher_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + return encrypt_update(ctx, (const unsigned char*)plain, plain_len, + (unsigned char*)cipher, cipher_len, OP_ENCRYPT); } API int yaca_encrypt_final(yaca_ctx_h ctx, char *cipher, size_t *cipher_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + return encrypt_final(ctx, (unsigned char*)cipher, + cipher_len, OP_ENCRYPT); } API int yaca_decrypt_init(yaca_ctx_h *ctx, @@ -149,7 +381,7 @@ API int yaca_decrypt_init(yaca_ctx_h *ctx, const yaca_key_h sym_key, const yaca_key_h iv) { - return YACA_ERROR_NOT_IMPLEMENTED; + return encrypt_init(ctx, algo, bcm, sym_key, iv, OP_DECRYPT); } API int yaca_decrypt_update(yaca_ctx_h ctx, @@ -158,14 +390,16 @@ API int yaca_decrypt_update(yaca_ctx_h ctx, char *plain, size_t *plain_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + return encrypt_update(ctx, (const unsigned char*)cipher, cipher_len, + (unsigned char*)plain, plain_len, OP_DECRYPT); } API int yaca_decrypt_final(yaca_ctx_h ctx, char *plain, size_t *plain_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + return encrypt_final(ctx,(unsigned char*)plain, plain_len, + OP_DECRYPT); } API int yaca_seal_init(yaca_ctx_h *ctx, -- 2.7.4