1cb209cc99e5ba1b345a39a9f6717fc95dd2625a
[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-2013, 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;
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).\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 int key_lengths[LOOPAES_KEYS_MAX];
138         unsigned int i, key_index, key_len, offset;
139
140         log_dbg("Parsing loop-AES keyfile of size %d.", 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.\n"));
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("Unterminated key #%d in keyfile.", key_index);
168                         log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
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("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.\n"));
189                 return -EINVAL;
190         }
191
192         log_dbg("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         char *cipher = NULL;
207         uint32_t req_flags;
208         int r;
209         struct crypt_dm_active_device dmd = {
210                 .target = DM_CRYPT,
211                 .size   = 0,
212                 .flags  = flags,
213                 .data_device = crypt_data_device(cd),
214                 .u.crypt  = {
215                         .cipher = NULL,
216                         .vk     = vk,
217                         .offset = crypt_get_data_offset(cd),
218                         .iv_offset = crypt_get_iv_offset(cd),
219                 }
220         };
221
222         r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
223                                 dmd.u.crypt.offset, &dmd.size, &dmd.flags);
224         if (r)
225                 return r;
226
227         if (keys_count == 1) {
228                 req_flags = DM_PLAIN64_SUPPORTED;
229                 r = asprintf(&cipher, "%s-%s", base_cipher, "cbc-plain64");
230         } else {
231                 req_flags = DM_LMK_SUPPORTED;
232                 r = asprintf(&cipher, "%s:%d-%s", base_cipher, 64, "cbc-lmk");
233         }
234         if (r < 0)
235                 return -ENOMEM;
236
237         dmd.u.crypt.cipher = cipher;
238         log_dbg("Trying to activate loop-AES device %s using cipher %s.",
239                 name, dmd.u.crypt.cipher);
240
241         r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0);
242
243         if (r < 0 && !(dm_flags() & req_flags)) {
244                 log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
245                 r = -ENOTSUP;
246         }
247
248         free(cipher);
249         return r;
250 }