0191e96509cdd8b7f082d55c2d5a735273b765ed
[platform/core/security/yaca.git] / src / digest.c
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18
19 /**
20  * @file digest.c
21  * @brief
22  */
23
24 #include <assert.h>
25
26 #include <openssl/evp.h>
27
28 #include <yaca_crypto.h>
29 #include <yaca_digest.h>
30 #include <yaca_error.h>
31
32 #include "internal.h"
33
34 struct yaca_digest_ctx_s {
35         struct yaca_context_s ctx;
36
37         EVP_MD_CTX *mdctx;
38 };
39
40 static struct yaca_digest_ctx_s *get_digest_ctx(const yaca_context_h ctx)
41 {
42         if (ctx == YACA_CONTEXT_NULL)
43                 return NULL;
44
45         switch (ctx->type) {
46         case YACA_CTX_DIGEST:
47                 return (struct yaca_digest_ctx_s *)ctx;
48         default:
49                 return NULL;
50         }
51 }
52
53 static int get_digest_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len)
54 {
55         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
56
57         if (c == NULL)
58                 return YACA_ERROR_INVALID_PARAMETER;
59
60         int md_size = EVP_MD_CTX_size(c->mdctx);
61         if (md_size <= 0)
62                 return YACA_ERROR_INTERNAL;
63
64         *output_len = md_size;
65
66         return YACA_ERROR_NONE;
67 }
68
69 static void destroy_digest_context(yaca_context_h ctx)
70 {
71         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
72
73         if (c == NULL)
74                 return;
75
76         EVP_MD_CTX_destroy(c->mdctx);
77         c->mdctx = NULL;
78 }
79
80 int digest_get_algorithm(yaca_digest_algorithm_e algo, const EVP_MD **md)
81 {
82         int ret = YACA_ERROR_NONE;
83
84         if (!md)
85                 return YACA_ERROR_INVALID_PARAMETER;
86
87         *md = NULL;
88
89         switch (algo) {
90         case YACA_DIGEST_MD5:
91                 *md = EVP_md5();
92                 break;
93         case YACA_DIGEST_SHA1:
94                 *md = EVP_sha1();
95                 break;
96         case YACA_DIGEST_SHA224:
97                 *md = EVP_sha224();
98                 break;
99         case YACA_DIGEST_SHA256:
100                 *md = EVP_sha256();
101                 break;
102         case YACA_DIGEST_SHA384:
103                 *md = EVP_sha384();
104                 break;
105         case YACA_DIGEST_SHA512:
106                 *md = EVP_sha512();
107                 break;
108         default:
109                 ret = YACA_ERROR_INVALID_PARAMETER;
110                 break;
111         }
112
113         if (ret == YACA_ERROR_NONE && *md == NULL) {
114                 ret = YACA_ERROR_INTERNAL;
115                 ERROR_DUMP(ret);
116         }
117
118         return ret;
119 }
120
121 API int yaca_digest_initialize(yaca_context_h *ctx, yaca_digest_algorithm_e algo)
122 {
123         int ret;
124         struct yaca_digest_ctx_s *nc = NULL;
125         const EVP_MD *md;
126
127         if (ctx == NULL)
128                 return YACA_ERROR_INVALID_PARAMETER;
129
130         ret = yaca_zalloc(sizeof(struct yaca_digest_ctx_s), (void**)&nc);
131         if (ret != YACA_ERROR_NONE)
132                 return ret;
133
134         nc->ctx.type = YACA_CTX_DIGEST;
135         nc->ctx.ctx_destroy = destroy_digest_context;
136         nc->ctx.get_output_length = get_digest_output_length;
137
138         ret = digest_get_algorithm(algo, &md);
139         if (ret != YACA_ERROR_NONE)
140                 goto exit;
141
142         nc->mdctx = EVP_MD_CTX_create();
143         if (nc->mdctx == NULL) {
144                 ret = YACA_ERROR_INTERNAL;
145                 ERROR_DUMP(ret);
146                 goto exit;
147         }
148
149         ret = EVP_DigestInit(nc->mdctx, md);
150         if (ret != 1) {
151                 ret = YACA_ERROR_INTERNAL;
152                 ERROR_DUMP(ret);
153                 goto exit;
154         }
155
156         *ctx = (yaca_context_h)nc;
157         nc = NULL;
158         ret = YACA_ERROR_NONE;
159
160 exit:
161         yaca_context_destroy((yaca_context_h)nc);
162
163         return ret;
164 }
165
166 API int yaca_digest_update(yaca_context_h ctx, const char *data, size_t data_len)
167 {
168         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
169         int ret;
170
171         if (c == NULL || data == NULL || data_len == 0)
172                 return YACA_ERROR_INVALID_PARAMETER;
173
174         ret = EVP_DigestUpdate(c->mdctx, data, data_len);
175         if (ret != 1) {
176                 ret = YACA_ERROR_INTERNAL;
177                 ERROR_DUMP(ret);
178                 return ret;
179         }
180
181         return YACA_ERROR_NONE;
182 }
183
184 API int yaca_digest_finalize(yaca_context_h ctx, char *digest, size_t *digest_len)
185 {
186         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
187         int ret;
188         unsigned len = 0;
189
190         if (c == NULL || digest == NULL || digest_len == NULL)
191                 return YACA_ERROR_INVALID_PARAMETER;
192
193         if (*digest_len == 0 || *digest_len > UINT_MAX) /* DigestFinal accepts UINT */
194                 return YACA_ERROR_INVALID_PARAMETER;
195
196         ret = EVP_DigestFinal_ex(c->mdctx, (unsigned char*)digest, &len);
197         if (ret != 1) {
198                 ret = YACA_ERROR_INTERNAL;
199                 ERROR_DUMP(ret);
200                 return ret;
201         }
202
203         *digest_len = len;
204
205         return YACA_ERROR_NONE;
206 }