e281fc8b6a0bd7fb6c640e88704a27974d827573
[platform/upstream/cryptsetup.git] / lib / loopaes / loopaes.c
1 /*
2  * loop-AES compatible volume handling
3  *
4  * Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2011-2021 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                      unsigned int key_len_input)
80 {
81         const char *hash_name;
82         char tweak, *key_ptr;
83         unsigned int i;
84         int r = 0;
85
86         hash_name = hash_override ?: get_hash(key_len_output);
87         tweak = get_tweak(keys_count);
88
89         if (!keys_count || !key_len_output || !hash_name || !key_len_input) {
90                 log_err(cd, _("Key processing error (using hash %s)."),
91                         hash_name ?: "[none]");
92                 return -EINVAL;
93         }
94
95         *vk = crypt_alloc_volume_key((size_t)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 int key_lengths[LOOPAES_KEYS_MAX];
138         unsigned int i, key_index, key_len, offset;
139
140         log_dbg(cd, "Parsing loop-AES keyfile of size %zu.", buffer_len);
141
142         if (!buffer_len)
143                 return -EINVAL;
144
145         if (keyfile_is_gpg(buffer, buffer_len)) {
146                 log_err(cd, _("Detected not yet supported GPG encrypted keyfile."));
147                 log_std(cd, _("Please use gpg --decrypt <KEYFILE> | cryptsetup --keyfile=- ...\n"));
148                 return -EINVAL;
149         }
150
151         /* Remove EOL in buffer */
152         for (i = 0; i < buffer_len; i++)
153                 if (buffer[i] == '\n' || buffer[i] == '\r')
154                         buffer[i] = '\0';
155
156         offset = 0;
157         key_index = 0;
158         key_lengths[0] = 0;
159         while (offset < buffer_len && key_index < LOOPAES_KEYS_MAX) {
160                 keys[key_index] = &buffer[offset];
161                 key_lengths[key_index] = 0;;
162                 while (offset < buffer_len && buffer[offset]) {
163                         offset++;
164                         key_lengths[key_index]++;
165                 }
166                 if (offset == buffer_len) {
167                         log_dbg(cd, "Unterminated key #%d in keyfile.", key_index);
168                         log_err(cd, _("Incompatible loop-AES keyfile detected."));
169                         return -EINVAL;
170                 }
171                 while (offset < buffer_len && !buffer[offset])
172                         offset++;
173                 key_index++;
174         }
175
176         /* All keys must be the same length */
177         key_len = key_lengths[0];
178         for (i = 0; i < key_index; i++)
179                 if (!key_lengths[i] || (key_lengths[i] != key_len)) {
180                         log_dbg(cd, "Unexpected length %d of key #%d (should be %d).",
181                                 key_lengths[i], i, key_len);
182                         key_len = 0;
183                         break;
184                 }
185
186         if (offset != buffer_len || key_len == 0 ||
187            (key_index != 1 && key_index !=64 && key_index != 65)) {
188                 log_err(cd, _("Incompatible loop-AES keyfile detected."));
189                 return -EINVAL;
190         }
191
192         log_dbg(cd, "Keyfile: %d keys of length %d.", key_index, key_len);
193
194         *keys_count = key_index;
195         return hash_keys(cd, vk, hash, keys, key_index,
196                          crypt_get_volume_key_size(cd), key_len);
197 }
198
199 int LOOPAES_activate(struct crypt_device *cd,
200                      const char *name,
201                      const char *base_cipher,
202                      unsigned int keys_count,
203                      struct volume_key *vk,
204                      uint32_t flags)
205 {
206         int r;
207         uint32_t req_flags, dmc_flags;
208         char *cipher = NULL;
209         struct crypt_dm_active_device dmd = {
210                 .flags = flags,
211         };
212
213         r = device_block_adjust(cd, crypt_data_device(cd), DEV_EXCL,
214                                 crypt_get_data_offset(cd), &dmd.size, &dmd.flags);
215         if (r)
216                 return r;
217
218         if (keys_count == 1) {
219                 req_flags = DM_PLAIN64_SUPPORTED;
220                 r = asprintf(&cipher, "%s-%s", base_cipher, "cbc-plain64");
221         } else {
222                 req_flags = DM_LMK_SUPPORTED;
223                 r = asprintf(&cipher, "%s:%d-%s", base_cipher, 64, "cbc-lmk");
224         }
225         if (r < 0)
226                 return -ENOMEM;
227
228         r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
229                         vk, cipher, crypt_get_iv_offset(cd),
230                         crypt_get_data_offset(cd), crypt_get_integrity(cd),
231                         crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
232
233         if (r) {
234                 free(cipher);
235                 return r;
236         }
237
238         log_dbg(cd, "Trying to activate loop-AES device %s using cipher %s.",
239                 name, cipher);
240
241         r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd);
242
243         if (r < 0 && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
244             (dmc_flags & req_flags) != req_flags) {
245                 log_err(cd, _("Kernel does not support loop-AES compatible mapping."));
246                 r = -ENOTSUP;
247         }
248
249         dm_targets_free(cd, &dmd);
250         free(cipher);
251
252         return r;
253 }