Try to remove device even if it is busy (libdevmapper now handle retry).
[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 <errno.h>
22 #include <assert.h>
23 #include <gcrypt.h>
24 #include "crypto_backend.h"
25
26 #define GCRYPT_REQ_VERSION "1.1.42"
27
28 static int crypto_backend_initialised = 0;
29
30 struct crypt_hash {
31         gcry_md_hd_t hd;
32         int hash_id;
33         int hash_len;
34 };
35
36 struct crypt_hmac {
37         gcry_md_hd_t hd;
38         int hash_id;
39         int hash_len;
40 };
41
42 int crypt_backend_init(struct crypt_device *ctx __attribute__((unused)))
43 {
44         if (crypto_backend_initialised)
45                 return 0;
46
47         log_dbg("Initialising gcrypt crypto backend.");
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                 log_dbg("Initializing crypto backend (secure memory disabled).");
61                 gcry_control (GCRYCTL_DISABLE_SECMEM);
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         crypto_backend_initialised = 1;
72         return 0;
73 }
74
75 uint32_t crypt_backend_flags(void)
76 {
77         return 0;
78 }
79
80 /* HASH */
81 int crypt_hash_size(const char *name)
82 {
83         int hash_id;
84
85         assert(crypto_backend_initialised);
86
87         hash_id = gcry_md_map_name(name);
88         if (!hash_id)
89                 return -EINVAL;
90
91         return gcry_md_get_algo_dlen(hash_id);
92 }
93
94 int crypt_hash_init(struct crypt_hash **ctx, const char *name)
95 {
96         struct crypt_hash *h;
97
98         assert(crypto_backend_initialised);
99
100         h = malloc(sizeof(*h));
101         if (!h)
102                 return -ENOMEM;
103
104         h->hash_id = gcry_md_map_name(name);
105         if (!h->hash_id) {
106                 free(h);
107                 return -EINVAL;
108         }
109
110         if (gcry_md_open(&h->hd, h->hash_id, 0)) {
111                 free(h);
112                 return -EINVAL;
113         }
114
115         h->hash_len = gcry_md_get_algo_dlen(h->hash_id);
116         *ctx = h;
117         return 0;
118 }
119
120 static void crypt_hash_restart(struct crypt_hash *ctx)
121 {
122         gcry_md_reset(ctx->hd);
123 }
124
125 int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
126 {
127         gcry_md_write(ctx->hd, buffer, length);
128         return 0;
129 }
130
131 int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
132 {
133         unsigned char *hash;
134
135         if (length > (size_t)ctx->hash_len)
136                 return -EINVAL;
137
138         hash = gcry_md_read(ctx->hd, ctx->hash_id);
139         if (!hash)
140                 return -EINVAL;
141
142         memcpy(buffer, hash, length);
143         crypt_hash_restart(ctx);
144
145         return 0;
146 }
147
148 int crypt_hash_destroy(struct crypt_hash *ctx)
149 {
150         gcry_md_close(ctx->hd);
151         memset(ctx, 0, sizeof(*ctx));
152         free(ctx);
153         return 0;
154 }
155
156 /* HMAC */
157 int crypt_hmac_size(const char *name)
158 {
159         return crypt_hash_size(name);
160 }
161
162 int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
163                     const void *buffer, size_t length)
164 {
165         struct crypt_hmac *h;
166
167         assert(crypto_backend_initialised);
168
169         h = malloc(sizeof(*h));
170         if (!h)
171                 return -ENOMEM;
172
173         h->hash_id = gcry_md_map_name(name);
174         if (!h->hash_id) {
175                 free(h);
176                 return -EINVAL;
177         }
178
179         if (gcry_md_open(&h->hd, h->hash_id, GCRY_MD_FLAG_HMAC)) {
180                 free(h);
181                 return -EINVAL;
182         }
183
184         if (gcry_md_setkey(h->hd, buffer, length)) {
185                 gcry_md_close(h->hd);
186                 free(h);
187                 return -EINVAL;
188         }
189
190         h->hash_len = gcry_md_get_algo_dlen(h->hash_id);
191         *ctx = h;
192         return 0;
193 }
194
195 static void crypt_hmac_restart(struct crypt_hmac *ctx)
196 {
197         gcry_md_reset(ctx->hd);
198 }
199
200 int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
201 {
202         gcry_md_write(ctx->hd, buffer, length);
203         return 0;
204 }
205
206 int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
207 {
208         unsigned char *hash;
209
210         if (length > (size_t)ctx->hash_len)
211                 return -EINVAL;
212
213         hash = gcry_md_read(ctx->hd, ctx->hash_id);
214         if (!hash)
215                 return -EINVAL;
216
217         memcpy(buffer, hash, length);
218         crypt_hmac_restart(ctx);
219
220         return 0;
221 }
222
223 int crypt_hmac_destroy(struct crypt_hmac *ctx)
224 {
225         gcry_md_close(ctx->hd);
226         memset(ctx, 0, sizeof(*ctx));
227         free(ctx);
228         return 0;
229 }