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
26 #include <openssl/evp.h>
28 #include <yaca_crypto.h>
29 #include <yaca_digest.h>
30 #include <yaca_error.h>
35 yaca_digest_algorithm_e algo;
36 const EVP_MD *(*digest)(void);
37 } MESSAGE_DIGESTS[] = {
38 {YACA_DIGEST_MD5, EVP_md5},
39 {YACA_DIGEST_SHA1, EVP_sha1},
40 {YACA_DIGEST_SHA224, EVP_sha224},
41 {YACA_DIGEST_SHA256, EVP_sha256},
42 {YACA_DIGEST_SHA384, EVP_sha384},
43 {YACA_DIGEST_SHA512, EVP_sha512},
46 static const size_t MESSAGE_DIGESTS_SIZE = sizeof(MESSAGE_DIGESTS) / sizeof(MESSAGE_DIGESTS[0]);
48 struct yaca_digest_context_s {
49 struct yaca_context_s ctx;
52 enum context_state_e state;
55 static bool CTX_DEFAULT_STATES[CTX_COUNT][CTX_COUNT] = {
56 /* from \ to INIT, MSG, FIN */
57 /* INIT */ { 0, 1, 1 },
58 /* MSG */ { 0, 1, 1 },
59 /* FIN */ { 0, 0, 0 },
62 static bool verify_state_change(struct yaca_digest_context_s *c, enum context_state_e to)
66 return CTX_DEFAULT_STATES[from][to];
69 static struct yaca_digest_context_s *get_digest_context(const yaca_context_h ctx)
71 if (ctx == YACA_CONTEXT_NULL)
75 case YACA_CONTEXT_DIGEST:
76 return (struct yaca_digest_context_s *)ctx;
82 static int get_digest_output_length(const yaca_context_h ctx,
86 assert(output_len != NULL);
88 struct yaca_digest_context_s *c = get_digest_context(ctx);
90 if (c == NULL || input_len != 0)
91 return YACA_ERROR_INVALID_PARAMETER;
93 int md_size = EVP_MD_CTX_size(c->md_ctx);
95 return YACA_ERROR_INTERNAL;
97 *output_len = md_size;
99 return YACA_ERROR_NONE;
102 static void destroy_digest_context(yaca_context_h ctx)
104 struct yaca_digest_context_s *c = get_digest_context(ctx);
109 EVP_MD_CTX_destroy(c->md_ctx);
113 int digest_get_algorithm(yaca_digest_algorithm_e algo, const EVP_MD **md)
121 ret = YACA_ERROR_INVALID_PARAMETER;
123 for (i = 0; i < MESSAGE_DIGESTS_SIZE; ++i)
124 if (MESSAGE_DIGESTS[i].algo == algo) {
125 *md = MESSAGE_DIGESTS[i].digest();
126 ret = YACA_ERROR_NONE;
130 if (ret == YACA_ERROR_NONE && *md == NULL) {
131 ret = YACA_ERROR_INTERNAL;
138 API int yaca_digest_initialize(yaca_context_h *ctx, yaca_digest_algorithm_e algo)
141 struct yaca_digest_context_s *nc = NULL;
145 return YACA_ERROR_INVALID_PARAMETER;
147 ret = yaca_zalloc(sizeof(struct yaca_digest_context_s), (void**)&nc);
148 if (ret != YACA_ERROR_NONE)
151 nc->ctx.type = YACA_CONTEXT_DIGEST;
152 nc->ctx.context_destroy = destroy_digest_context;
153 nc->ctx.get_output_length = get_digest_output_length;
154 nc->ctx.set_property = NULL;
155 nc->ctx.get_property = NULL;
157 ret = digest_get_algorithm(algo, &md);
158 if (ret != YACA_ERROR_NONE)
161 nc->md_ctx = EVP_MD_CTX_create();
162 if (nc->md_ctx == NULL) {
163 ret = YACA_ERROR_INTERNAL;
168 ret = EVP_DigestInit(nc->md_ctx, md);
170 ret = YACA_ERROR_INTERNAL;
175 nc->state = CTX_INITIALIZED;
176 *ctx = (yaca_context_h)nc;
178 ret = YACA_ERROR_NONE;
181 yaca_context_destroy((yaca_context_h)nc);
186 API int yaca_digest_update(yaca_context_h ctx, const char *message, size_t message_len)
188 struct yaca_digest_context_s *c = get_digest_context(ctx);
191 if (c == NULL || message == NULL || message_len == 0)
192 return YACA_ERROR_INVALID_PARAMETER;
194 if (!verify_state_change(c, CTX_MSG_UPDATED))
195 return YACA_ERROR_INVALID_PARAMETER;
197 ret = EVP_DigestUpdate(c->md_ctx, message, message_len);
199 ret = YACA_ERROR_INTERNAL;
204 c->state = CTX_MSG_UPDATED;
205 return YACA_ERROR_NONE;
208 API int yaca_digest_finalize(yaca_context_h ctx, char *digest, size_t *digest_len)
210 struct yaca_digest_context_s *c = get_digest_context(ctx);
214 if (c == NULL || digest == NULL || digest_len == NULL)
215 return YACA_ERROR_INVALID_PARAMETER;
217 if (!verify_state_change(c, CTX_FINALIZED))
218 return YACA_ERROR_INVALID_PARAMETER;
220 ret = EVP_DigestFinal_ex(c->md_ctx, (unsigned char*)digest, &len);
222 ret = YACA_ERROR_INTERNAL;
227 c->state = CTX_FINALIZED;
230 return YACA_ERROR_NONE;