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