2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
28 #include <openssl/crypto.h>
29 #include <openssl/evp.h>
30 #include <openssl/rand.h>
31 #include <openssl/err.h>
33 #include <yaca_crypto.h>
34 #include <yaca_error.h>
38 static pthread_mutex_t *mutexes = NULL;
40 static void locking_callback(int mode, int type, const char *file, int line)
42 /* Ignore NULL mutexes and lock/unlock error codes as we can't do anything
48 if (mode & CRYPTO_LOCK)
49 pthread_mutex_lock(&mutexes[type]);
50 else if (mode & CRYPTO_UNLOCK)
51 pthread_mutex_unlock(&mutexes[type]);
54 static unsigned long thread_id_callback()
56 return pthread_self();
59 static void destroy_mutexes(int count)
61 if (mutexes != NULL) {
62 for (int i = 0; i < count; i++) {
63 /* Ignore returned value as we can't do anything about it */
64 pthread_mutex_destroy(&mutexes[i]);
71 API int yaca_initialize(void)
75 return YACA_ERROR_INTERNAL; // TODO introduce new one?
79 /* This should never fail on a /dev/random equipped system. If it does it
80 * means we might need to figure out another way of a truly random seed.
81 * https://wiki.openssl.org/index.php/Random_Numbers
83 * Another things to maybe consider for the future:
84 * - entropy on a mobile device (no mouse/keyboard)
85 * - fork safety: https://wiki.openssl.org/index.php/Random_fork-safety
86 * - hardware random generator (RdRand on new Intels, Samsung hardware?)
88 if (RAND_status() != 1) {
89 ERROR_DUMP(YACA_ERROR_INTERNAL);
90 return YACA_ERROR_INTERNAL;
93 OpenSSL_add_all_digests();
94 OpenSSL_add_all_ciphers();
96 /* enable threads support */
97 if (CRYPTO_num_locks() > 0) {
98 ret = yaca_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t), (void**)&mutexes);
99 if (ret != YACA_ERROR_NONE)
102 for (int i = 0; i < CRYPTO_num_locks(); i++) {
103 if (pthread_mutex_init(&mutexes[i], NULL) != 0) {
104 int ret = YACA_ERROR_NONE;
107 ret = YACA_ERROR_OUT_OF_MEMORY;
114 ret = YACA_ERROR_INTERNAL;
122 CRYPTO_set_id_callback(thread_id_callback);
123 CRYPTO_set_locking_callback(locking_callback);
128 * - We should also decide on Openssl config.
129 * - Here's a good tutorial for initalization and cleanup: https://wiki.openssl.org/index.php/Library_Initialization
130 * - We should also initialize the entropy for random number generator: https://wiki.openssl.org/index.php/Random_Numbers#Initialization
133 return YACA_ERROR_NONE;
136 API int yaca_cleanup(void)
139 ERR_remove_thread_state(NULL);
142 CRYPTO_cleanup_all_ex_data();
144 /* threads support cleanup */
145 CRYPTO_set_id_callback(NULL);
146 CRYPTO_set_locking_callback(NULL);
148 destroy_mutexes(CRYPTO_num_locks());
150 return YACA_ERROR_NONE;
153 API int yaca_malloc(size_t size, void **memory)
155 if (size == 0 || memory == NULL)
156 return YACA_ERROR_INVALID_PARAMETER;
158 *memory = OPENSSL_malloc(size);
159 if (*memory == NULL) {
160 ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY);
161 return YACA_ERROR_OUT_OF_MEMORY;
164 return YACA_ERROR_NONE;
167 API int yaca_zalloc(size_t size, void **memory)
169 int ret = yaca_malloc(size, memory);
170 if (ret != YACA_ERROR_NONE)
173 memset(*memory, 0, size);
175 return YACA_ERROR_NONE;
178 API int yaca_realloc(size_t size, void **memory)
180 if (size == 0 || memory == NULL)
181 return YACA_ERROR_INVALID_PARAMETER;
183 void *tmp = OPENSSL_realloc(*memory, size);
185 ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY);
186 return YACA_ERROR_OUT_OF_MEMORY;
191 return YACA_ERROR_NONE;
194 API int yaca_free(void *ptr)
198 return YACA_ERROR_NONE;
201 API int yaca_randomize_bytes(char *data, size_t data_len)
205 if (data == NULL || data_len == 0)
206 return YACA_ERROR_INVALID_PARAMETER;
208 ret = RAND_bytes((unsigned char *)data, data_len);
210 ret = YACA_ERROR_INTERNAL;
215 return YACA_ERROR_NONE;
218 API int yaca_context_set_property(yaca_context_h ctx, yaca_property_e param,
219 const void *value, size_t value_len)
221 if (ctx == YACA_CONTEXT_NULL || ctx->set_param == NULL)
222 return YACA_ERROR_INVALID_PARAMETER;
224 return ctx->set_param(ctx, param, value, value_len);
227 API int yaca_context_get_property(const yaca_context_h ctx, yaca_property_e param,
228 void **value, size_t *value_len)
230 if (ctx == YACA_CONTEXT_NULL || ctx->get_param == NULL)
231 return YACA_ERROR_INVALID_PARAMETER;
233 return ctx->get_param(ctx, param, value, value_len);
236 API int yaca_context_destroy(yaca_context_h ctx)
238 if (ctx != YACA_CONTEXT_NULL) {
239 assert(ctx->ctx_destroy != NULL);
240 ctx->ctx_destroy(ctx);
244 return YACA_ERROR_NONE;
247 API int yaca_get_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len)
249 if (ctx == YACA_CONTEXT_NULL)
250 return YACA_ERROR_INVALID_PARAMETER;
252 return ctx->get_output_length(ctx, input_len, output_len);
255 API int yaca_memcmp(const void *first, const void *second, size_t len)
257 if (CRYPTO_memcmp(first, second, len) == 0)
258 return YACA_ERROR_NONE;
260 return YACA_ERROR_DATA_MISMATCH;