Fix null blocks in kernel backend.
[platform/upstream/cryptsetup.git] / lib / crypto_backend / crypto_kernel.c
1 /*
2  * Linux kernel userspace API 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 <stdlib.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <sys/socket.h>
28 #include <sys/utsname.h>
29 #include <linux/if_alg.h>
30 #include "crypto_backend.h"
31
32 /* FIXME: remove later */
33 #ifndef AF_ALG
34 #define AF_ALG 38
35 #endif
36 #ifndef SOL_ALG
37 #define SOL_ALG 279
38 #endif
39
40 static int crypto_backend_initialised = 0;
41 static char version[64];
42
43 struct hash_alg {
44         const char *name;
45         const char *kernel_name;
46         int length;
47 };
48
49 static struct hash_alg hash_algs[] = {
50         { "sha1", "sha1", 20 },
51         { "sha256", "sha256", 32 },
52         { "sha512", "sha512", 64 },
53         { "ripemd160", "rmd160", 20 },
54         { "whirlpool", "wp512", 64 },
55         { NULL, NULL, 0 }
56 };
57
58 struct crypt_hash {
59         int tfmfd;
60         int opfd;
61         int hash_len;
62 };
63
64 struct crypt_hmac {
65         int tfmfd;
66         int opfd;
67         int hash_len;
68 };
69
70 /* Defined in crypt_kernel_ciphers.c */
71 extern int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *opfd);
72
73 int crypt_backend_init(struct crypt_device *ctx)
74 {
75         struct utsname uts;
76         struct sockaddr_alg sa = {
77                 .salg_family = AF_ALG,
78                 .salg_type = "hash",
79                 .salg_name = "sha1",
80         };
81         int tfmfd = -1, opfd = -1;
82
83         if (crypto_backend_initialised)
84                 return 0;
85
86         if (uname(&uts) == -1 || strcmp(uts.sysname, "Linux"))
87                 return -EINVAL;
88
89         if (crypt_kernel_socket_init(&sa, &tfmfd, &opfd) < 0)
90                 return -EINVAL;
91
92         close(tfmfd);
93         close(opfd);
94
95         snprintf(version, sizeof(version), "%s %s kernel cryptoAPI",
96                  uts.sysname, uts.release);
97
98         crypto_backend_initialised = 1;
99         return 0;
100 }
101
102 uint32_t crypt_backend_flags(void)
103 {
104         return CRYPT_BACKEND_KERNEL;
105 }
106
107 const char *crypt_backend_version(void)
108 {
109         return crypto_backend_initialised ? version : "";
110 }
111
112 static struct hash_alg *_get_alg(const char *name)
113 {
114         int i = 0;
115
116         while (name && hash_algs[i].name) {
117                 if (!strcmp(name, hash_algs[i].name))
118                         return &hash_algs[i];
119                 i++;
120         }
121         return NULL;
122 }
123
124 /* HASH */
125 int crypt_hash_size(const char *name)
126 {
127         struct hash_alg *ha = _get_alg(name);
128
129         return ha ? ha->length : -EINVAL;
130 }
131
132 int crypt_hash_init(struct crypt_hash **ctx, const char *name)
133 {
134         struct crypt_hash *h;
135         struct hash_alg *ha;
136         struct sockaddr_alg sa = {
137                 .salg_family = AF_ALG,
138                 .salg_type = "hash",
139         };
140
141         h = malloc(sizeof(*h));
142         if (!h)
143                 return -ENOMEM;
144
145         ha = _get_alg(name);
146         if (!ha) {
147                 free(h);
148                 return -EINVAL;
149         }
150         h->hash_len = ha->length;
151
152         strncpy((char *)sa.salg_name, ha->kernel_name, sizeof(sa.salg_name));
153
154         if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd) < 0) {
155                 free(h);
156                 return -EINVAL;
157         }
158
159         *ctx = h;
160         return 0;
161 }
162
163 int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
164 {
165         ssize_t r;
166
167         r = send(ctx->opfd, buffer, length, MSG_MORE);
168         if (r < 0 || (size_t)r < length)
169                 return -EIO;
170
171         return 0;
172 }
173
174 int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
175 {
176         ssize_t r;
177
178         if (length > (size_t)ctx->hash_len)
179                 return -EINVAL;
180
181         r = read(ctx->opfd, buffer, length);
182         if (r < 0)
183                 return -EIO;
184
185         return 0;
186 }
187
188 int crypt_hash_destroy(struct crypt_hash *ctx)
189 {
190         if (ctx->tfmfd != -1)
191                 close(ctx->tfmfd);
192         if (ctx->opfd != -1)
193                 close(ctx->opfd);
194         memset(ctx, 0, sizeof(*ctx));
195         free(ctx);
196         return 0;
197 }
198
199 /* HMAC */
200 int crypt_hmac_size(const char *name)
201 {
202         return crypt_hash_size(name);
203 }
204
205 int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
206                     const void *buffer, size_t length)
207 {
208         struct crypt_hmac *h;
209         struct hash_alg *ha;
210         struct sockaddr_alg sa = {
211                 .salg_family = AF_ALG,
212                 .salg_type = "hash",
213         };
214
215         h = malloc(sizeof(*h));
216         if (!h)
217                 return -ENOMEM;
218
219         ha = _get_alg(name);
220         if (!ha) {
221                 free(h);
222                 return -EINVAL;
223         }
224         h->hash_len = ha->length;
225
226         snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
227                  "hmac(%s)", ha->kernel_name);
228
229         if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd) < 0) {
230                 free(h);
231                 return -EINVAL;
232         }
233
234         if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, buffer, length) == -1) {
235                 crypt_hmac_destroy(h);
236                 return -EINVAL;
237         }
238
239         *ctx = h;
240         return 0;
241 }
242
243 int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
244 {
245         ssize_t r;
246
247         r = send(ctx->opfd, buffer, length, MSG_MORE);
248         if (r < 0 || (size_t)r < length)
249                 return -EIO;
250
251         return 0;
252 }
253
254 int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
255 {
256         ssize_t r;
257
258         if (length > (size_t)ctx->hash_len)
259                 return -EINVAL;
260
261         r = read(ctx->opfd, buffer, length);
262         if (r < 0)
263                 return -EIO;
264
265         return 0;
266 }
267
268 int crypt_hmac_destroy(struct crypt_hmac *ctx)
269 {
270         if (ctx->tfmfd != -1)
271                 close(ctx->tfmfd);
272         if (ctx->opfd != -1)
273                 close(ctx->opfd);
274         memset(ctx, 0, sizeof(*ctx));
275         free(ctx);
276         return 0;
277 }
278
279 /* RNG - N/A */
280 int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
281 {
282         return -EINVAL;
283 }
284
285 /* PBKDF */
286 int crypt_pbkdf(const char *kdf, const char *hash,
287                 const char *password, size_t password_length,
288                 const char *salt, size_t salt_length,
289                 char *key, size_t key_length,
290                 unsigned int iterations)
291 {
292         if (!kdf || strncmp(kdf, "pbkdf2", 6))
293                 return -EINVAL;
294
295         return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
296                             iterations, key_length, key);
297 }