4173691d144dad289660ec56777f61078497137a
[platform/upstream/cryptsetup.git] / lib / crypto_backend / crypto_gcrypt.c
1 /*
2  * GCRYPT crypto backend implementation
3  *
4  * Copyright (C) 2010-2012, Red Hat, Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <string.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <gcrypt.h>
25 #include "crypto_backend.h"
26
27 static int crypto_backend_initialised = 0;
28 static int crypto_backend_secmem = 1;
29 static char version[64];
30
31 struct crypt_hash {
32         gcry_md_hd_t hd;
33         int hash_id;
34         int hash_len;
35 };
36
37 struct crypt_hmac {
38         gcry_md_hd_t hd;
39         int hash_id;
40         int hash_len;
41 };
42
43 int crypt_backend_init(struct crypt_device *ctx)
44 {
45         if (crypto_backend_initialised)
46                 return 0;
47
48         if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
49                 if (!gcry_check_version (GCRYPT_REQ_VERSION)) {
50                         return -ENOSYS;
51                 }
52
53 /* FIXME: If gcrypt compiled to support POSIX 1003.1e capabilities,
54  * it drops all privileges during secure memory initialisation.
55  * For now, the only workaround is to disable secure memory in gcrypt.
56  * cryptsetup always need at least cap_sys_admin privilege for dm-ioctl
57  * and it locks its memory space anyway.
58  */
59 #if 0
60                 gcry_control (GCRYCTL_DISABLE_SECMEM);
61                 crypto_backend_secmem = 0;
62 #else
63
64                 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
65                 gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
66                 gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
67 #endif
68                 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
69         }
70
71         snprintf(version, 64, "gcrypt %s%s",
72                  gcry_check_version(NULL),
73                  crypto_backend_secmem ? "" : ", secmem disabled");
74         crypto_backend_initialised = 1;
75         return 0;
76 }
77
78 const char *crypt_backend_version(void)
79 {
80         return crypto_backend_initialised ? version : "";
81 }
82
83 uint32_t crypt_backend_flags(void)
84 {
85         return 0;
86 }
87
88 /* HASH */
89 int crypt_hash_size(const char *name)
90 {
91         int hash_id;
92
93         assert(crypto_backend_initialised);
94
95         hash_id = gcry_md_map_name(name);
96         if (!hash_id)
97                 return -EINVAL;
98
99         return gcry_md_get_algo_dlen(hash_id);
100 }
101
102 int crypt_hash_init(struct crypt_hash **ctx, const char *name)
103 {
104         struct crypt_hash *h;
105
106         assert(crypto_backend_initialised);
107
108         h = malloc(sizeof(*h));
109         if (!h)
110                 return -ENOMEM;
111
112         h->hash_id = gcry_md_map_name(name);
113         if (!h->hash_id) {
114                 free(h);
115                 return -EINVAL;
116         }
117
118         if (gcry_md_open(&h->hd, h->hash_id, 0)) {
119                 free(h);
120                 return -EINVAL;
121         }
122
123         h->hash_len = gcry_md_get_algo_dlen(h->hash_id);
124         *ctx = h;
125         return 0;
126 }
127
128 static void crypt_hash_restart(struct crypt_hash *ctx)
129 {
130         gcry_md_reset(ctx->hd);
131 }
132
133 int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
134 {
135         gcry_md_write(ctx->hd, buffer, length);
136         return 0;
137 }
138
139 int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
140 {
141         unsigned char *hash;
142
143         if (length > (size_t)ctx->hash_len)
144                 return -EINVAL;
145
146         hash = gcry_md_read(ctx->hd, ctx->hash_id);
147         if (!hash)
148                 return -EINVAL;
149
150         memcpy(buffer, hash, length);
151         crypt_hash_restart(ctx);
152
153         return 0;
154 }
155
156 int crypt_hash_destroy(struct crypt_hash *ctx)
157 {
158         gcry_md_close(ctx->hd);
159         memset(ctx, 0, sizeof(*ctx));
160         free(ctx);
161         return 0;
162 }
163
164 /* HMAC */
165 int crypt_hmac_size(const char *name)
166 {
167         return crypt_hash_size(name);
168 }
169
170 int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
171                     const void *buffer, size_t length)
172 {
173         struct crypt_hmac *h;
174
175         assert(crypto_backend_initialised);
176
177         h = malloc(sizeof(*h));
178         if (!h)
179                 return -ENOMEM;
180
181         h->hash_id = gcry_md_map_name(name);
182         if (!h->hash_id) {
183                 free(h);
184                 return -EINVAL;
185         }
186
187         if (gcry_md_open(&h->hd, h->hash_id, GCRY_MD_FLAG_HMAC)) {
188                 free(h);
189                 return -EINVAL;
190         }
191
192         if (gcry_md_setkey(h->hd, buffer, length)) {
193                 gcry_md_close(h->hd);
194                 free(h);
195                 return -EINVAL;
196         }
197
198         h->hash_len = gcry_md_get_algo_dlen(h->hash_id);
199         *ctx = h;
200         return 0;
201 }
202
203 static void crypt_hmac_restart(struct crypt_hmac *ctx)
204 {
205         gcry_md_reset(ctx->hd);
206 }
207
208 int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
209 {
210         gcry_md_write(ctx->hd, buffer, length);
211         return 0;
212 }
213
214 int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
215 {
216         unsigned char *hash;
217
218         if (length > (size_t)ctx->hash_len)
219                 return -EINVAL;
220
221         hash = gcry_md_read(ctx->hd, ctx->hash_id);
222         if (!hash)
223                 return -EINVAL;
224
225         memcpy(buffer, hash, length);
226         crypt_hmac_restart(ctx);
227
228         return 0;
229 }
230
231 int crypt_hmac_destroy(struct crypt_hmac *ctx)
232 {
233         gcry_md_close(ctx->hd);
234         memset(ctx, 0, sizeof(*ctx));
235         free(ctx);
236         return 0;
237 }
238
239 /* RNG */
240 int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
241 {
242         switch(quality) {
243         case CRYPT_RND_NORMAL:
244                 gcry_randomize(buffer, length, GCRY_STRONG_RANDOM);
245                 break;
246         case CRYPT_RND_SALT:
247         case CRYPT_RND_KEY:
248         default:
249                 gcry_randomize(buffer, length, GCRY_VERY_STRONG_RANDOM);
250                 break;
251         }
252         return 0;
253 }
254
255 /* PBKDF */
256 int crypt_pbkdf(const char *kdf, const char *hash,
257                 const char *password, size_t password_length,
258                 const char *salt, size_t salt_length,
259                 char *key, size_t key_length,
260                 unsigned int iterations)
261 {
262         if (!kdf || strncmp(kdf, "pbkdf2", 6))
263                 return -EINVAL;
264
265         return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
266                             iterations, key_length, key);
267 }
268
269 #if 0
270 /* Until bug in gcrypt related to empty password is fixed,  cannot use this */
271 int crypt_pbkdf(const char *kdf, const char *hash,
272                 const char *password, size_t password_length,
273                 const char *salt, size_t salt_length,
274                 char *key, size_t key_length,
275                 unsigned int iterations)
276 {
277         int hash_id = gcry_md_map_name(hash);
278         int kdf_id;
279
280         if (!hash_id)
281                 return -EINVAL;
282
283         if (kdf && !strncmp(kdf, "pbkdf2", 6))
284                 kdf_id = GCRY_KDF_PBKDF2;
285         else
286                 return -EINVAL;
287
288         if (gcry_kdf_derive(password, password_length, kdf_id, hash_id,
289             salt, salt_length, iterations, key_length, key))
290                 return -EINVAL;
291
292         return 0;
293 }
294 #endif