Do not support user uuid for plain & loopaes devices.
[platform/upstream/cryptsetup.git] / lib / loopaes / loopaes.c
1 /*
2  * loop-AES compatible volume handling
3  *
4  * Copyright (C) 2011-2012, Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2011-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 <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "libcryptsetup.h"
28 #include "loopaes.h"
29 #include "internal.h"
30
31 static const char *get_hash(unsigned int key_size)
32 {
33         const char *hash;
34
35         switch (key_size) {
36                 case 16: hash = "sha256"; break;
37                 case 24: hash = "sha384"; break;
38                 case 32: hash = "sha512"; break;
39                 default: hash = NULL;
40         }
41
42         return hash;
43 }
44
45 static unsigned char get_tweak(unsigned int keys_count)
46 {
47         switch (keys_count) {
48                 case 64: return 0x55;
49                 case 65: return 0xF4;
50                 default: break;
51         }
52         return 0x00;
53 }
54
55 static int hash_key(const char *src, size_t src_len,
56                     char *dst, size_t dst_len,
57                     const char *hash_name)
58 {
59         struct crypt_hash *hd = NULL;
60         int r;
61
62         if (crypt_hash_init(&hd, hash_name))
63                 return -EINVAL;
64
65         r = crypt_hash_write(hd, src, src_len);
66         if (!r)
67                 r = crypt_hash_final(hd, dst, dst_len);
68
69         crypt_hash_destroy(hd);
70         return r;
71 }
72
73 static int hash_keys(struct crypt_device *cd,
74                      struct volume_key **vk,
75                      const char *hash_override,
76                      const char **input_keys,
77                      unsigned int keys_count,
78                      unsigned int key_len_output)
79 {
80         const char *hash_name;
81         char tweak, *key_ptr;
82         unsigned i, key_len_input;
83         int r;
84
85         hash_name = hash_override ?: get_hash(key_len_output);
86         tweak = get_tweak(keys_count);
87         key_len_input = strlen(input_keys[0]);
88
89         if (!keys_count || !key_len_output || !hash_name || !key_len_input) {
90                 log_err(cd, _("Key processing error (using hash %s).\n"),
91                         hash_name ?: "[none]");
92                 return -EINVAL;
93         }
94
95         *vk = crypt_alloc_volume_key(key_len_output * keys_count, NULL);
96         if (!*vk)
97                 return -ENOMEM;
98
99         for (i = 0; i < keys_count; i++) {
100                 key_ptr = &(*vk)->key[i * key_len_output];
101                 r = hash_key(input_keys[i], key_len_input, key_ptr,
102                              key_len_output, hash_name);
103                 if (r < 0)
104                         break;
105
106                 key_ptr[0] ^= tweak;
107         }
108
109         if (r < 0 && *vk) {
110                 crypt_free_volume_key(*vk);
111                 *vk = NULL;
112         }
113         return r;
114 }
115
116 static int keyfile_is_gpg(char *buffer, size_t buffer_len)
117 {
118         int r = 0;
119         int index = buffer_len < 100 ? buffer_len - 1 : 100;
120         char eos = buffer[index];
121
122         buffer[index] = '\0';
123         if (strstr(buffer, "BEGIN PGP MESSAGE"))
124                 r = 1;
125         buffer[index] = eos;
126         return r;
127 }
128
129 int LOOPAES_parse_keyfile(struct crypt_device *cd,
130                           struct volume_key **vk,
131                           const char *hash,
132                           unsigned int *keys_count,
133                           char *buffer,
134                           size_t buffer_len)
135 {
136         const char *keys[LOOPAES_KEYS_MAX];
137         unsigned i, key_index, key_len, offset;
138
139         log_dbg("Parsing loop-AES keyfile of size %d.", buffer_len);
140
141         if (!buffer_len)
142                 return -EINVAL;
143
144         if (keyfile_is_gpg(buffer, buffer_len)) {
145                 log_err(cd, _("Detected not yet supported GPG encrypted keyfile.\n"));
146                 log_std(cd, _("Please use gpg --decrypt <KEYFILE> | cryptsetup --keyfile=- ...\n"));
147                 return -EINVAL;
148         }
149
150         /* Remove EOL in buffer */
151         for (i = 0; i < buffer_len; i++)
152                 if (buffer[i] == '\n' || buffer[i] == '\r')
153                         buffer[i] = '\0';
154
155         offset = 0;
156         key_index = 0;
157         while (offset < buffer_len && key_index < LOOPAES_KEYS_MAX) {
158                 keys[key_index++] = &buffer[offset];
159                 while (offset < buffer_len && buffer[offset])
160                         offset++;
161                 while (offset < buffer_len && !buffer[offset])
162                         offset++;
163         }
164
165         /* All keys must be the same length */
166         key_len = key_index ? strlen(keys[0]) : 0;
167         for (i = 0; i < key_index; i++)
168                 if (key_len != strlen(keys[i])) {
169                         log_dbg("Unexpected length %d of key #%d (should be %d).",
170                                 strlen(keys[i]), i, key_len);
171                         key_len = 0;
172                         break;
173                 }
174
175         log_dbg("Keyfile: %d keys of length %d.", key_index, key_len);
176         if (offset != buffer_len || key_len == 0 ||
177            (key_index != 1 && key_index !=64 && key_index != 65)) {
178                 log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
179                 return -EINVAL;
180         }
181
182         *keys_count = key_index;
183         return hash_keys(cd, vk, hash, keys, key_index, crypt_get_volume_key_size(cd));
184 }
185
186 int LOOPAES_activate(struct crypt_device *cd,
187                      const char *name,
188                      const char *base_cipher,
189                      unsigned int keys_count,
190                      struct volume_key *vk,
191                      uint32_t flags)
192 {
193         char *cipher = NULL;
194         uint32_t req_flags;
195         int r;
196         struct crypt_dm_active_device dmd = {
197                 .target = DM_CRYPT,
198                 .size   = 0,
199                 .flags  = flags,
200                 .data_device = crypt_data_device(cd),
201                 .u.crypt  = {
202                         .cipher = NULL,
203                         .vk     = vk,
204                         .offset = crypt_get_data_offset(cd),
205                         .iv_offset = crypt_get_iv_offset(cd),
206                 }
207         };
208
209         r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
210                                 dmd.u.crypt.offset, &dmd.size, &dmd.flags);
211         if (r)
212                 return r;
213
214         if (keys_count == 1) {
215                 req_flags = DM_PLAIN64_SUPPORTED;
216                 r = asprintf(&cipher, "%s-%s", base_cipher, "cbc-plain64");
217         } else {
218                 req_flags = DM_LMK_SUPPORTED;
219                 r = asprintf(&cipher, "%s:%d-%s", base_cipher, 64, "cbc-lmk");
220         }
221         if (r < 0)
222                 return -ENOMEM;
223
224         dmd.u.crypt.cipher = cipher;
225         log_dbg("Trying to activate loop-AES device %s using cipher %s.",
226                 name, dmd.u.crypt.cipher);
227
228         r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0);
229
230         if (r < 0 && !(dm_flags() & req_flags)) {
231                 log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
232                 r = -ENOTSUP;
233         }
234
235         free(cipher);
236         return r;
237 }