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