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