"Fossies" - the Fresh Open Source Software Archive 
Member "cryptsetup-2.4.3/lib/loopaes/loopaes.c" (13 Jan 2022, 6410 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "loopaes.c" see the
Fossies "Dox" file reference documentation.
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 }