4cc0ceb6121bed2daf2a342a906505603709fbb2
[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 #include <assert.h>
20 #include <stdint.h>
21
22 #include <openssl/evp.h>
23 #include <openssl/err.h>
24
25 #include <yaca/crypto.h>
26 #include <yaca/error.h>
27 #include <yaca/types.h>
28
29 #include "internal.h"
30
31 struct yaca_digest_ctx_s
32 {
33         struct yaca_ctx_s ctx;
34
35         const EVP_MD *md;
36         EVP_MD_CTX *mdctx;
37 };
38
39 static struct yaca_digest_ctx_s *get_digest_ctx(const yaca_ctx_h ctx)
40 {
41         if (ctx == YACA_CTX_NULL)
42                 return NULL;
43
44         switch (ctx->type)
45         {
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_ctx_h ctx, size_t input_len)
54 {
55         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
56
57         if (c == NULL)
58                 return YACA_ERROR_INVALID_ARGUMENT;
59
60         return EVP_MD_size(c->md);
61 }
62
63 static void destroy_digest_context(yaca_ctx_h ctx)
64 {
65         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
66
67         if (c == NULL)
68                 return;
69
70         EVP_MD_CTX_destroy(c->mdctx);
71 }
72
73 int digest_get_algorithm(yaca_digest_algo_e algo, const EVP_MD **md)
74 {
75         int ret = 0;
76
77         if (!md)
78                 return YACA_ERROR_INVALID_ARGUMENT;
79
80         *md = NULL;
81
82         switch (algo)
83         {
84         case YACA_DIGEST_MD5:
85                 *md = EVP_md5();
86                 break;
87         case YACA_DIGEST_SHA1:
88                 *md = EVP_sha1();
89                 break;
90         case YACA_DIGEST_SHA224:
91                 *md = EVP_sha224();
92                 break;
93         case YACA_DIGEST_SHA256:
94                 *md = EVP_sha256();
95                 break;
96         case YACA_DIGEST_SHA384:
97                 *md = EVP_sha384();
98                 break;
99         case YACA_DIGEST_SHA512:
100                 *md = EVP_sha512();
101                 break;
102         case YACA_DIGEST_CMAC:
103                 ret = YACA_ERROR_NOT_IMPLEMENTED;
104                 break;
105         default:
106                 ret = YACA_ERROR_INVALID_ARGUMENT;
107                 break;
108         }
109
110         if (ret == 0 && *md == NULL)
111                 ret = YACA_ERROR_OPENSSL_FAILURE;
112
113         return ret;
114 }
115
116 API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo)
117 {
118         int ret;
119         struct yaca_digest_ctx_s *nc = NULL;
120
121         if (ctx == NULL)
122                 return YACA_ERROR_INVALID_ARGUMENT;
123
124         nc = yaca_malloc(sizeof(struct yaca_digest_ctx_s));
125         if (nc == NULL)
126                 return YACA_ERROR_OUT_OF_MEMORY;
127
128         nc->ctx.type = YACA_CTX_DIGEST;
129         nc->ctx.ctx_destroy = destroy_digest_context;
130         nc->ctx.get_output_length = get_digest_output_length;
131
132         ret = digest_get_algorithm(algo, &nc->md);
133         if (ret < 0)
134                 goto free;
135
136         nc->mdctx = EVP_MD_CTX_create();
137         if (nc->mdctx == NULL) {
138                 ret = YACA_ERROR_OPENSSL_FAILURE;
139                 goto free;
140         }
141
142         ret = EVP_DigestInit(nc->mdctx, nc->md);
143         if (ret != 1) {
144                 ret = YACA_ERROR_OPENSSL_FAILURE;
145                 goto ctx;
146         }
147
148         *ctx = (yaca_ctx_h)nc;
149
150         ret = 0;
151
152 ctx:
153         if (ret != 0)
154                 EVP_MD_CTX_destroy(nc->mdctx);
155 free:
156         if (ret != 0)
157                 yaca_free(nc);
158
159         return ret;
160 }
161
162 API int yaca_digest_update(yaca_ctx_h ctx, const char *data, size_t data_len)
163 {
164         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
165         int ret;
166
167         if (c == NULL || data == NULL || data_len == 0)
168                 return YACA_ERROR_INVALID_ARGUMENT;
169
170         ret = EVP_DigestUpdate(c->mdctx, data, data_len);
171         if (ret != 1)
172                 return YACA_ERROR_OPENSSL_FAILURE;
173
174         return 0;
175 }
176
177 API int yaca_digest_final(yaca_ctx_h ctx, char *digest, size_t *digest_len)
178 {
179         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
180         int ret;
181         unsigned len = 0;
182
183         if (c == NULL || digest == NULL || digest_len == NULL)
184                 return YACA_ERROR_INVALID_ARGUMENT;
185
186         if (*digest_len == 0 || *digest_len > UINT_MAX) // DigestFinal accepts uint
187                 return YACA_ERROR_INVALID_ARGUMENT;
188
189         ret = EVP_DigestFinal_ex(c->mdctx, (unsigned char*)digest, &len);
190         if (ret != 1)
191                 return YACA_ERROR_OPENSSL_FAILURE;
192
193         *digest_len = len;
194
195         return 0;
196 }