9c507480a3b277b60d0864a9254413989f750886
[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         EVP_MD_CTX *mdctx;
36 };
37
38 static struct yaca_digest_ctx_s *get_digest_ctx(const yaca_ctx_h ctx)
39 {
40         if (ctx == YACA_CTX_NULL)
41                 return NULL;
42
43         switch (ctx->type)
44         {
45         case YACA_CTX_DIGEST:
46                 return (struct yaca_digest_ctx_s *)ctx;
47         default:
48                 return NULL;
49         }
50 }
51
52 static int get_digest_output_length(const yaca_ctx_h ctx, size_t input_len)
53 {
54         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
55
56         if (c == NULL)
57                 return YACA_ERROR_INVALID_ARGUMENT;
58
59         return EVP_MD_CTX_size(c->mdctx);
60 }
61
62 static void destroy_digest_context(yaca_ctx_h ctx)
63 {
64         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
65
66         if (c == NULL)
67                 return;
68
69         EVP_MD_CTX_destroy(c->mdctx);
70 }
71
72 int digest_get_algorithm(yaca_digest_algo_e algo, const EVP_MD **md)
73 {
74         int ret = 0;
75
76         if (!md)
77                 return YACA_ERROR_INVALID_ARGUMENT;
78
79         *md = NULL;
80
81         switch (algo)
82         {
83         case YACA_DIGEST_MD5:
84                 *md = EVP_md5();
85                 break;
86         case YACA_DIGEST_SHA1:
87                 *md = EVP_sha1();
88                 break;
89         case YACA_DIGEST_SHA224:
90                 *md = EVP_sha224();
91                 break;
92         case YACA_DIGEST_SHA256:
93                 *md = EVP_sha256();
94                 break;
95         case YACA_DIGEST_SHA384:
96                 *md = EVP_sha384();
97                 break;
98         case YACA_DIGEST_SHA512:
99                 *md = EVP_sha512();
100                 break;
101         case YACA_DIGEST_CMAC:
102                 ret = YACA_ERROR_NOT_IMPLEMENTED;
103                 break;
104         default:
105                 ret = YACA_ERROR_INVALID_ARGUMENT;
106                 break;
107         }
108
109         if (ret == 0 && *md == NULL)
110                 ret = YACA_ERROR_OPENSSL_FAILURE;
111
112         return ret;
113 }
114
115 API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo)
116 {
117         int ret;
118         struct yaca_digest_ctx_s *nc = NULL;
119         const EVP_MD *md;
120
121         if (ctx == NULL)
122                 return YACA_ERROR_INVALID_ARGUMENT;
123
124         nc = yaca_zalloc(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, &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, md);
143         if (ret != 1) {
144                 ret = YACA_ERROR_OPENSSL_FAILURE;
145                 goto ctx;
146         }
147
148         *ctx = (yaca_ctx_h)nc;
149
150         return 0;
151
152 ctx:
153         EVP_MD_CTX_destroy(nc->mdctx);
154 free:
155         yaca_free(nc);
156         return ret;
157 }
158
159 API int yaca_digest_update(yaca_ctx_h ctx, const char *data, size_t data_len)
160 {
161         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
162         int ret;
163
164         if (c == NULL || data == NULL || data_len == 0)
165                 return YACA_ERROR_INVALID_ARGUMENT;
166
167         ret = EVP_DigestUpdate(c->mdctx, data, data_len);
168         if (ret != 1)
169                 return YACA_ERROR_OPENSSL_FAILURE;
170
171         return 0;
172 }
173
174 API int yaca_digest_final(yaca_ctx_h ctx, char *digest, size_t *digest_len)
175 {
176         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
177         int ret;
178         unsigned len = 0;
179
180         if (c == NULL || digest == NULL || digest_len == NULL)
181                 return YACA_ERROR_INVALID_ARGUMENT;
182
183         if (*digest_len == 0 || *digest_len > UINT_MAX) // DigestFinal accepts uint
184                 return YACA_ERROR_INVALID_ARGUMENT;
185
186         ret = EVP_DigestFinal_ex(c->mdctx, (unsigned char*)digest, &len);
187         if (ret != 1)
188                 return YACA_ERROR_OPENSSL_FAILURE;
189
190         *digest_len = len;
191
192         return 0;
193 }