]> git.proxmox.com Git - grub2.git/blame - grub-core/disk/cryptodisk.c
cryptodisk: Rename "total_length" field in grub_cryptodisk_t to "total_sectors"
[grub2.git] / grub-core / disk / cryptodisk.c
CommitLineData
1a1f408f
VS
1/*
2 * GRUB -- GRand Unified Bootloader
dd3f49b1 3 * Copyright (C) 2003,2007,2010,2011,2019 Free Software Foundation, Inc.
1a1f408f
VS
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <grub/cryptodisk.h>
20#include <grub/mm.h>
21#include <grub/misc.h>
22#include <grub/dl.h>
20a40940
VS
23#include <grub/extcmd.h>
24#include <grub/i18n.h>
ce50dbd7
VS
25#include <grub/fs.h>
26#include <grub/file.h>
27#include <grub/procfs.h>
c7f93a20 28#include <grub/partition.h>
1a1f408f
VS
29
30#ifdef GRUB_UTIL
1a1f408f 31#include <grub/emu/hostdisk.h>
1a1f408f
VS
32#endif
33
34GRUB_MOD_LICENSE ("GPLv3+");
35
20a40940
VS
36grub_cryptodisk_dev_t grub_cryptodisk_list;
37
38static const struct grub_arg_option options[] =
39 {
40 {"uuid", 'u', 0, N_("Mount by UUID."), 0, 0},
40211ab8 41 /* TRANSLATORS: It's still restricted to cryptodisks only. */
20a40940 42 {"all", 'a', 0, N_("Mount all."), 0, 0},
9c4b5c13 43 {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0},
20a40940
VS
44 {0, 0, 0, 0, 0, 0}
45 };
46
1a1f408f
VS
47/* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */
48#define GF_POLYNOM 0x87
3e90811d
VS
49static inline int GF_PER_SECTOR (const struct grub_cryptodisk *dev)
50{
51 return 1U << (dev->log_sector_size - GRUB_CRYPTODISK_GF_LOG_BYTES);
52}
1a1f408f
VS
53
54static grub_cryptodisk_t cryptodisk_list = NULL;
6f5f3337 55static grub_uint8_t last_cryptodisk_id = 0;
1a1f408f
VS
56
57static void
58gf_mul_x (grub_uint8_t *g)
59{
60 int over = 0, over2 = 0;
3e90811d 61 unsigned j;
1a1f408f
VS
62
63 for (j = 0; j < GRUB_CRYPTODISK_GF_BYTES; j++)
64 {
65 over2 = !!(g[j] & 0x80);
66 g[j] <<= 1;
67 g[j] |= over;
68 over = over2;
69 }
70 if (over)
71 g[0] ^= GF_POLYNOM;
72}
73
74
75static void
76gf_mul_x_be (grub_uint8_t *g)
77{
78 int over = 0, over2 = 0;
79 int j;
80
3e90811d 81 for (j = (int) GRUB_CRYPTODISK_GF_BYTES - 1; j >= 0; j--)
1a1f408f
VS
82 {
83 over2 = !!(g[j] & 0x80);
84 g[j] <<= 1;
85 g[j] |= over;
86 over = over2;
87 }
88 if (over)
89 g[GRUB_CRYPTODISK_GF_BYTES - 1] ^= GF_POLYNOM;
90}
91
92static void
93gf_mul_be (grub_uint8_t *o, const grub_uint8_t *a, const grub_uint8_t *b)
94{
3e90811d 95 unsigned i;
1a1f408f
VS
96 grub_uint8_t t[GRUB_CRYPTODISK_GF_BYTES];
97 grub_memset (o, 0, GRUB_CRYPTODISK_GF_BYTES);
98 grub_memcpy (t, b, GRUB_CRYPTODISK_GF_BYTES);
99 for (i = 0; i < GRUB_CRYPTODISK_GF_SIZE; i++)
100 {
1865baa7 101 if (((a[GRUB_CRYPTODISK_GF_BYTES - i / GRUB_CHAR_BIT - 1] >> (i % GRUB_CHAR_BIT))) & 1)
1a1f408f
VS
102 grub_crypto_xor (o, o, t, GRUB_CRYPTODISK_GF_BYTES);
103 gf_mul_x_be (t);
104 }
105}
106
107static gcry_err_code_t
108grub_crypto_pcbc_decrypt (grub_crypto_cipher_handle_t cipher,
109 void *out, void *in, grub_size_t size,
110 void *iv)
111{
112 grub_uint8_t *inptr, *outptr, *end;
c35fcdc0 113 grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
94f701a8 114 grub_size_t blocksize;
1a1f408f
VS
115 if (!cipher->cipher->decrypt)
116 return GPG_ERR_NOT_SUPPORTED;
94f701a8
VS
117 blocksize = cipher->cipher->blocksize;
118 if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
119 || ((size & (blocksize - 1)) != 0))
120 return GPG_ERR_INV_ARG;
121 if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
1a1f408f
VS
122 return GPG_ERR_INV_ARG;
123 end = (grub_uint8_t *) in + size;
124 for (inptr = in, outptr = out; inptr < end;
94f701a8 125 inptr += blocksize, outptr += blocksize)
1a1f408f 126 {
94f701a8 127 grub_memcpy (ivt, inptr, blocksize);
1a1f408f 128 cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
94f701a8
VS
129 grub_crypto_xor (outptr, outptr, iv, blocksize);
130 grub_crypto_xor (iv, ivt, outptr, blocksize);
1a1f408f
VS
131 }
132 return GPG_ERR_NO_ERROR;
133}
134
9c6e84b8
VS
135static gcry_err_code_t
136grub_crypto_pcbc_encrypt (grub_crypto_cipher_handle_t cipher,
137 void *out, void *in, grub_size_t size,
138 void *iv)
139{
140 grub_uint8_t *inptr, *outptr, *end;
c35fcdc0 141 grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
94f701a8
VS
142 grub_size_t blocksize;
143 if (!cipher->cipher->encrypt)
9c6e84b8 144 return GPG_ERR_NOT_SUPPORTED;
94f701a8
VS
145 blocksize = cipher->cipher->blocksize;
146 if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
147 return GPG_ERR_INV_ARG;
148 if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
149 || ((size & (blocksize - 1)) != 0))
9c6e84b8
VS
150 return GPG_ERR_INV_ARG;
151 end = (grub_uint8_t *) in + size;
152 for (inptr = in, outptr = out; inptr < end;
94f701a8 153 inptr += blocksize, outptr += blocksize)
9c6e84b8 154 {
94f701a8
VS
155 grub_memcpy (ivt, inptr, blocksize);
156 grub_crypto_xor (outptr, outptr, iv, blocksize);
9c6e84b8 157 cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
94f701a8 158 grub_crypto_xor (iv, ivt, outptr, blocksize);
9c6e84b8
VS
159 }
160 return GPG_ERR_NO_ERROR;
161}
162
1a1f408f
VS
163struct lrw_sector
164{
165 grub_uint8_t low[GRUB_CRYPTODISK_GF_BYTES];
166 grub_uint8_t high[GRUB_CRYPTODISK_GF_BYTES];
167 grub_uint8_t low_byte, low_byte_c;
168};
169
170static void
171generate_lrw_sector (struct lrw_sector *sec,
172 const struct grub_cryptodisk *dev,
173 const grub_uint8_t *iv)
174{
175 grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES];
176 grub_uint16_t c;
177 int j;
178 grub_memcpy (idx, iv, GRUB_CRYPTODISK_GF_BYTES);
3e90811d
VS
179 sec->low_byte = (idx[GRUB_CRYPTODISK_GF_BYTES - 1]
180 & (GF_PER_SECTOR (dev) - 1));
181 sec->low_byte_c = (((GF_PER_SECTOR (dev) - 1) & ~sec->low_byte) + 1);
182 idx[GRUB_CRYPTODISK_GF_BYTES - 1] &= ~(GF_PER_SECTOR (dev) - 1);
1a1f408f
VS
183 gf_mul_be (sec->low, dev->lrw_key, idx);
184 if (!sec->low_byte)
185 return;
186
3e90811d 187 c = idx[GRUB_CRYPTODISK_GF_BYTES - 1] + GF_PER_SECTOR (dev);
1a1f408f
VS
188 if (c & 0x100)
189 {
190 for (j = GRUB_CRYPTODISK_GF_BYTES - 2; j >= 0; j--)
191 {
192 idx[j]++;
193 if (idx[j] != 0)
194 break;
195 }
196 }
197 idx[GRUB_CRYPTODISK_GF_BYTES - 1] = c;
198 gf_mul_be (sec->high, dev->lrw_key, idx);
199}
200
201static void __attribute__ ((unused))
202lrw_xor (const struct lrw_sector *sec,
203 const struct grub_cryptodisk *dev,
204 grub_uint8_t *b)
205{
3e90811d 206 unsigned i;
1a1f408f 207
3e90811d
VS
208 for (i = 0; i < sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES;
209 i += GRUB_CRYPTODISK_GF_BYTES)
1a1f408f
VS
210 grub_crypto_xor (b + i, b + i, sec->low, GRUB_CRYPTODISK_GF_BYTES);
211 grub_crypto_xor (b, b, dev->lrw_precalc + GRUB_CRYPTODISK_GF_BYTES * sec->low_byte,
212 sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES);
213 if (!sec->low_byte)
214 return;
215
216 for (i = sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES;
3e90811d 217 i < (1U << dev->log_sector_size); i += GRUB_CRYPTODISK_GF_BYTES)
1a1f408f
VS
218 grub_crypto_xor (b + i, b + i, sec->high, GRUB_CRYPTODISK_GF_BYTES);
219 grub_crypto_xor (b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES,
220 b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES,
221 dev->lrw_precalc, sec->low_byte * GRUB_CRYPTODISK_GF_BYTES);
222}
223
9c6e84b8
VS
224static gcry_err_code_t
225grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev,
226 grub_uint8_t * data, grub_size_t len,
7b5784d4 227 grub_disk_addr_t sector, int do_encrypt)
1a1f408f
VS
228{
229 grub_size_t i;
230 gcry_err_code_t err;
231
c35fcdc0
VS
232 if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
233 return GPG_ERR_INV_ARG;
234
1a1f408f 235 /* The only mode without IV. */
88ac3146 236 if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey)
7b5784d4 237 return (do_encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len)
9c6e84b8 238 : grub_crypto_ecb_decrypt (dev->cipher, data, data, len));
1a1f408f 239
3e90811d 240 for (i = 0; i < len; i += (1U << dev->log_sector_size))
1a1f408f
VS
241 {
242 grub_size_t sz = ((dev->cipher->cipher->blocksize
243 + sizeof (grub_uint32_t) - 1)
244 / sizeof (grub_uint32_t));
c35fcdc0 245 grub_uint32_t iv[(GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE + 3) / 4];
1a1f408f 246
88ac3146
VS
247 if (dev->rekey)
248 {
249 grub_uint64_t zone = sector >> dev->rekey_shift;
250 if (zone != dev->last_rekey)
251 {
252 err = dev->rekey (dev, zone);
253 if (err)
254 return err;
255 dev->last_rekey = zone;
256 }
257 }
258
c35fcdc0 259 grub_memset (iv, 0, sizeof (iv));
1a1f408f
VS
260 switch (dev->mode_iv)
261 {
262 case GRUB_CRYPTODISK_MODE_IV_NULL:
263 break;
264 case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH:
265 {
266 grub_uint64_t tmp;
c35fcdc0 267 void *ctx;
b44cd9e7 268
c35fcdc0
VS
269 ctx = grub_zalloc (dev->iv_hash->contextsize);
270 if (!ctx)
271 return GPG_ERR_OUT_OF_MEMORY;
b44cd9e7 272
3e90811d 273 tmp = grub_cpu_to_le64 (sector << dev->log_sector_size);
1a1f408f
VS
274 dev->iv_hash->init (ctx);
275 dev->iv_hash->write (ctx, dev->iv_prefix, dev->iv_prefix_len);
276 dev->iv_hash->write (ctx, &tmp, sizeof (tmp));
277 dev->iv_hash->final (ctx);
278
279 grub_memcpy (iv, dev->iv_hash->read (ctx), sizeof (iv));
c35fcdc0 280 grub_free (ctx);
1a1f408f
VS
281 }
282 break;
283 case GRUB_CRYPTODISK_MODE_IV_PLAIN64:
284 iv[1] = grub_cpu_to_le32 (sector >> 32);
4bd4a887 285 /* FALLTHROUGH */
1a1f408f
VS
286 case GRUB_CRYPTODISK_MODE_IV_PLAIN:
287 iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF);
288 break;
171e2be1
VS
289 case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64:
290 iv[1] = grub_cpu_to_le32 (sector >> (32 - dev->log_sector_size));
291 iv[0] = grub_cpu_to_le32 ((sector << dev->log_sector_size)
292 & 0xFFFFFFFF);
293 break;
1a1f408f
VS
294 case GRUB_CRYPTODISK_MODE_IV_BENBI:
295 {
296 grub_uint64_t num = (sector << dev->benbi_log) + 1;
297 iv[sz - 2] = grub_cpu_to_be32 (num >> 32);
298 iv[sz - 1] = grub_cpu_to_be32 (num & 0xFFFFFFFF);
299 }
300 break;
301 case GRUB_CRYPTODISK_MODE_IV_ESSIV:
302 iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF);
303 err = grub_crypto_ecb_encrypt (dev->essiv_cipher, iv, iv,
304 dev->cipher->cipher->blocksize);
305 if (err)
306 return err;
307 }
308
309 switch (dev->mode)
310 {
311 case GRUB_CRYPTODISK_MODE_CBC:
7b5784d4 312 if (do_encrypt)
9c6e84b8
VS
313 err = grub_crypto_cbc_encrypt (dev->cipher, data + i, data + i,
314 (1U << dev->log_sector_size), iv);
315 else
316 err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i,
317 (1U << dev->log_sector_size), iv);
1a1f408f
VS
318 if (err)
319 return err;
320 break;
321
322 case GRUB_CRYPTODISK_MODE_PCBC:
7b5784d4 323 if (do_encrypt)
9c6e84b8
VS
324 err = grub_crypto_pcbc_encrypt (dev->cipher, data + i, data + i,
325 (1U << dev->log_sector_size), iv);
326 else
327 err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i,
328 (1U << dev->log_sector_size), iv);
1a1f408f
VS
329 if (err)
330 return err;
331 break;
332 case GRUB_CRYPTODISK_MODE_XTS:
333 {
3e90811d 334 unsigned j;
1a1f408f
VS
335 err = grub_crypto_ecb_encrypt (dev->secondary_cipher, iv, iv,
336 dev->cipher->cipher->blocksize);
337 if (err)
338 return err;
339
3e90811d 340 for (j = 0; j < (1U << dev->log_sector_size);
1a1f408f
VS
341 j += dev->cipher->cipher->blocksize)
342 {
343 grub_crypto_xor (data + i + j, data + i + j, iv,
344 dev->cipher->cipher->blocksize);
7b5784d4 345 if (do_encrypt)
9c6e84b8
VS
346 err = grub_crypto_ecb_encrypt (dev->cipher, data + i + j,
347 data + i + j,
348 dev->cipher->cipher->blocksize);
349 else
350 err = grub_crypto_ecb_decrypt (dev->cipher, data + i + j,
351 data + i + j,
352 dev->cipher->cipher->blocksize);
1a1f408f
VS
353 if (err)
354 return err;
355 grub_crypto_xor (data + i + j, data + i + j, iv,
356 dev->cipher->cipher->blocksize);
357 gf_mul_x ((grub_uint8_t *) iv);
358 }
359 }
360 break;
361 case GRUB_CRYPTODISK_MODE_LRW:
362 {
363 struct lrw_sector sec;
364
365 generate_lrw_sector (&sec, dev, (grub_uint8_t *) iv);
366 lrw_xor (&sec, dev, data + i);
367
7b5784d4 368 if (do_encrypt)
9c6e84b8
VS
369 err = grub_crypto_ecb_encrypt (dev->cipher, data + i,
370 data + i,
371 (1U << dev->log_sector_size));
372 else
373 err = grub_crypto_ecb_decrypt (dev->cipher, data + i,
374 data + i,
375 (1U << dev->log_sector_size));
1a1f408f
VS
376 if (err)
377 return err;
378 lrw_xor (&sec, dev, data + i);
379 }
380 break;
88ac3146 381 case GRUB_CRYPTODISK_MODE_ECB:
7b5784d4 382 if (do_encrypt)
4c7337bf
VS
383 err = grub_crypto_ecb_encrypt (dev->cipher, data + i, data + i,
384 (1U << dev->log_sector_size));
9c6e84b8 385 else
4c7337bf
VS
386 err = grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i,
387 (1U << dev->log_sector_size));
388 if (err)
389 return err;
88ac3146 390 break;
1a1f408f
VS
391 default:
392 return GPG_ERR_NOT_IMPLEMENTED;
393 }
394 sector++;
395 }
396 return GPG_ERR_NO_ERROR;
397}
398
9c6e84b8
VS
399gcry_err_code_t
400grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
401 grub_uint8_t * data, grub_size_t len,
402 grub_disk_addr_t sector)
403{
404 return grub_cryptodisk_endecrypt (dev, data, len, sector, 0);
405}
406
dd3f49b1
PS
407grub_err_t
408grub_cryptodisk_setcipher (grub_cryptodisk_t crypt, const char *ciphername, const char *ciphermode)
409{
410 const char *cipheriv = NULL;
411 grub_crypto_cipher_handle_t cipher = NULL, secondary_cipher = NULL;
412 grub_crypto_cipher_handle_t essiv_cipher = NULL;
413 const gcry_md_spec_t *essiv_hash = NULL;
414 const struct gcry_cipher_spec *ciph;
415 grub_cryptodisk_mode_t mode;
416 grub_cryptodisk_mode_iv_t mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN64;
417 int benbi_log = 0;
418 grub_err_t ret = GRUB_ERR_NONE;
419
420 ciph = grub_crypto_lookup_cipher_by_name (ciphername);
421 if (!ciph)
422 {
423 ret = grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available",
424 ciphername);
425 goto err;
426 }
427
428 /* Configure the cipher used for the bulk data. */
429 cipher = grub_crypto_cipher_open (ciph);
430 if (!cipher)
431 {
432 ret = grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s could not be initialized",
433 ciphername);
434 goto err;
435 }
436
437 /* Configure the cipher mode. */
438 if (grub_strcmp (ciphermode, "ecb") == 0)
439 {
440 mode = GRUB_CRYPTODISK_MODE_ECB;
441 mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN;
442 cipheriv = NULL;
443 }
444 else if (grub_strcmp (ciphermode, "plain") == 0)
445 {
446 mode = GRUB_CRYPTODISK_MODE_CBC;
447 mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN;
448 cipheriv = NULL;
449 }
450 else if (grub_memcmp (ciphermode, "cbc-", sizeof ("cbc-") - 1) == 0)
451 {
452 mode = GRUB_CRYPTODISK_MODE_CBC;
453 cipheriv = ciphermode + sizeof ("cbc-") - 1;
454 }
455 else if (grub_memcmp (ciphermode, "pcbc-", sizeof ("pcbc-") - 1) == 0)
456 {
457 mode = GRUB_CRYPTODISK_MODE_PCBC;
458 cipheriv = ciphermode + sizeof ("pcbc-") - 1;
459 }
460 else if (grub_memcmp (ciphermode, "xts-", sizeof ("xts-") - 1) == 0)
461 {
462 mode = GRUB_CRYPTODISK_MODE_XTS;
463 cipheriv = ciphermode + sizeof ("xts-") - 1;
464 secondary_cipher = grub_crypto_cipher_open (ciph);
465 if (!secondary_cipher)
466 {
84ff10b1
GW
467 ret = grub_error (GRUB_ERR_FILE_NOT_FOUND,
468 "Secondary cipher %s isn't available", ciphername);
dd3f49b1
PS
469 goto err;
470 }
471 if (cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES)
472 {
473 ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported XTS block size: %d",
474 cipher->cipher->blocksize);
475 goto err;
476 }
477 if (secondary_cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES)
478 {
479 ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported XTS block size: %d",
480 secondary_cipher->cipher->blocksize);
481 goto err;
482 }
483 }
484 else if (grub_memcmp (ciphermode, "lrw-", sizeof ("lrw-") - 1) == 0)
485 {
486 mode = GRUB_CRYPTODISK_MODE_LRW;
487 cipheriv = ciphermode + sizeof ("lrw-") - 1;
488 if (cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES)
489 {
490 ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported LRW block size: %d",
491 cipher->cipher->blocksize);
492 goto err;
493 }
494 }
495 else
496 {
497 ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown cipher mode: %s",
498 ciphermode);
499 goto err;
500 }
501
502 if (cipheriv == NULL)
503 ;
dd3f49b1
PS
504 else if (grub_memcmp (cipheriv, "plain64", sizeof ("plain64") - 1) == 0)
505 mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN64;
6355ba91
GW
506 else if (grub_memcmp (cipheriv, "plain", sizeof ("plain") - 1) == 0)
507 mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN;
dd3f49b1
PS
508 else if (grub_memcmp (cipheriv, "benbi", sizeof ("benbi") - 1) == 0)
509 {
510 if (cipher->cipher->blocksize & (cipher->cipher->blocksize - 1)
511 || cipher->cipher->blocksize == 0)
512 grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported benbi blocksize: %d",
513 cipher->cipher->blocksize);
514 /* FIXME should we return an error here? */
515 for (benbi_log = 0;
516 (cipher->cipher->blocksize << benbi_log) < GRUB_DISK_SECTOR_SIZE;
517 benbi_log++);
518 mode_iv = GRUB_CRYPTODISK_MODE_IV_BENBI;
519 }
520 else if (grub_memcmp (cipheriv, "null", sizeof ("null") - 1) == 0)
521 mode_iv = GRUB_CRYPTODISK_MODE_IV_NULL;
522 else if (grub_memcmp (cipheriv, "essiv:", sizeof ("essiv:") - 1) == 0)
523 {
524 const char *hash_str = cipheriv + 6;
525
526 mode_iv = GRUB_CRYPTODISK_MODE_IV_ESSIV;
527
528 /* Configure the hash and cipher used for ESSIV. */
529 essiv_hash = grub_crypto_lookup_md_by_name (hash_str);
530 if (!essiv_hash)
531 {
532 ret = grub_error (GRUB_ERR_FILE_NOT_FOUND,
533 "Couldn't load %s hash", hash_str);
534 goto err;
535 }
536 essiv_cipher = grub_crypto_cipher_open (ciph);
537 if (!essiv_cipher)
538 {
539 ret = grub_error (GRUB_ERR_FILE_NOT_FOUND,
540 "Couldn't load %s cipher", ciphername);
541 goto err;
542 }
543 }
544 else
545 {
546 ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown IV mode: %s",
547 cipheriv);
548 goto err;
549 }
550
551 crypt->cipher = cipher;
552 crypt->benbi_log = benbi_log;
553 crypt->mode = mode;
554 crypt->mode_iv = mode_iv;
555 crypt->secondary_cipher = secondary_cipher;
556 crypt->essiv_cipher = essiv_cipher;
557 crypt->essiv_hash = essiv_hash;
558
559err:
560 if (ret)
561 {
562 grub_crypto_cipher_close (cipher);
563 grub_crypto_cipher_close (secondary_cipher);
564 }
565 return ret;
566}
567
1a1f408f
VS
568gcry_err_code_t
569grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t keysize)
570{
571 gcry_err_code_t err;
572 int real_keysize;
573
574 real_keysize = keysize;
575 if (dev->mode == GRUB_CRYPTODISK_MODE_XTS)
576 real_keysize /= 2;
577 if (dev->mode == GRUB_CRYPTODISK_MODE_LRW)
578 real_keysize -= dev->cipher->cipher->blocksize;
579
580 /* Set the PBKDF2 output as the cipher key. */
581 err = grub_crypto_cipher_set_key (dev->cipher, key, real_keysize);
582 if (err)
583 return err;
ce50dbd7
VS
584 grub_memcpy (dev->key, key, keysize);
585 dev->keysize = keysize;
1a1f408f
VS
586
587 /* Configure ESSIV if necessary. */
588 if (dev->mode_iv == GRUB_CRYPTODISK_MODE_IV_ESSIV)
589 {
590 grub_size_t essiv_keysize = dev->essiv_hash->mdlen;
c35fcdc0
VS
591 grub_uint8_t hashed_key[GRUB_CRYPTO_MAX_MDLEN];
592 if (essiv_keysize > GRUB_CRYPTO_MAX_MDLEN)
593 return GPG_ERR_INV_ARG;
1a1f408f
VS
594
595 grub_crypto_hash (dev->essiv_hash, hashed_key, key, keysize);
596 err = grub_crypto_cipher_set_key (dev->essiv_cipher,
597 hashed_key, essiv_keysize);
598 if (err)
599 return err;
600 }
601 if (dev->mode == GRUB_CRYPTODISK_MODE_XTS)
602 {
603 err = grub_crypto_cipher_set_key (dev->secondary_cipher,
604 key + real_keysize,
605 keysize / 2);
606 if (err)
607 return err;
608 }
609
610 if (dev->mode == GRUB_CRYPTODISK_MODE_LRW)
611 {
3e90811d 612 unsigned i;
1a1f408f
VS
613 grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES];
614
615 grub_free (dev->lrw_precalc);
616 grub_memcpy (dev->lrw_key, key + real_keysize,
617 dev->cipher->cipher->blocksize);
3e90811d 618 dev->lrw_precalc = grub_malloc ((1U << dev->log_sector_size));
1a1f408f
VS
619 if (!dev->lrw_precalc)
620 return GPG_ERR_OUT_OF_MEMORY;
621 grub_memset (idx, 0, GRUB_CRYPTODISK_GF_BYTES);
3e90811d 622 for (i = 0; i < (1U << dev->log_sector_size);
1a1f408f
VS
623 i += GRUB_CRYPTODISK_GF_BYTES)
624 {
625 idx[GRUB_CRYPTODISK_GF_BYTES - 1] = i / GRUB_CRYPTODISK_GF_BYTES;
626 gf_mul_be (dev->lrw_precalc + i, idx, dev->lrw_key);
627 }
628 }
629 return GPG_ERR_NO_ERROR;
630}
631
632static int
25239370
CW
633grub_cryptodisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
634 grub_disk_pull_t pull)
1a1f408f
VS
635{
636 grub_cryptodisk_t i;
637
638 if (pull != GRUB_DISK_PULL_NONE)
639 return 0;
640
641 for (i = cryptodisk_list; i != NULL; i = i->next)
642 {
643 char buf[30];
644 grub_snprintf (buf, sizeof (buf), "crypto%lu", i->id);
25239370 645 if (hook (buf, hook_data))
1a1f408f
VS
646 return 1;
647 }
648
649 return GRUB_ERR_NONE;
650}
651
652static grub_err_t
cd8fe79a 653grub_cryptodisk_open (const char *name, grub_disk_t disk)
1a1f408f
VS
654{
655 grub_cryptodisk_t dev;
656
657 if (grub_memcmp (name, "crypto", sizeof ("crypto") - 1) != 0)
658 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
659
660 if (grub_memcmp (name, "cryptouuid/", sizeof ("cryptouuid/") - 1) == 0)
661 {
662 for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
663 if (grub_strcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid) == 0)
664 break;
665 }
666 else
667 {
668 unsigned long id = grub_strtoul (name + sizeof ("crypto") - 1, 0, 0);
669 if (grub_errno)
670 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
671 /* Search for requested device in the list of CRYPTODISK devices. */
672 for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
673 if (dev->id == id)
674 break;
675 }
676 if (!dev)
677 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
678
3e90811d
VS
679 disk->log_sector_size = dev->log_sector_size;
680
1a1f408f
VS
681#ifdef GRUB_UTIL
682 if (dev->cheat)
683 {
a47a78be 684 if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
6de292cb 685 dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY);
a47a78be 686 if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
9c4b5c13 687 return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"),
20d53541 688 dev->cheat, grub_util_fd_strerror ());
1a1f408f
VS
689 }
690#endif
691
692 if (!dev->source_disk)
693 {
694 grub_dprintf ("cryptodisk", "Opening device %s\n", name);
695 /* Try to open the source disk and populate the requested disk. */
696 dev->source_disk = grub_disk_open (dev->source);
697 if (!dev->source_disk)
698 return grub_errno;
699 }
700
701 disk->data = dev;
535998c2 702 disk->total_sectors = dev->total_sectors;
cb72aa18 703 disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
1a1f408f
VS
704 disk->id = dev->id;
705 dev->ref++;
706 return GRUB_ERR_NONE;
707}
708
709static void
710grub_cryptodisk_close (grub_disk_t disk)
711{
712 grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
713 grub_dprintf ("cryptodisk", "Closing disk\n");
714
715 dev->ref--;
716
717 if (dev->ref != 0)
718 return;
719#ifdef GRUB_UTIL
720 if (dev->cheat)
721 {
a47a78be
VS
722 grub_util_fd_close (dev->cheat_fd);
723 dev->cheat_fd = GRUB_UTIL_FD_INVALID;
1a1f408f
VS
724 }
725#endif
726 grub_disk_close (dev->source_disk);
727 dev->source_disk = NULL;
728}
729
730static grub_err_t
731grub_cryptodisk_read (grub_disk_t disk, grub_disk_addr_t sector,
20a40940 732 grub_size_t size, char *buf)
1a1f408f
VS
733{
734 grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
735 grub_err_t err;
736 gcry_err_code_t gcry_err;
737
738#ifdef GRUB_UTIL
739 if (dev->cheat)
740 {
b73249d2
VS
741 int r;
742 r = grub_util_fd_seek (dev->cheat_fd, sector << disk->log_sector_size);
743 if (r)
744 return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
745 dev->cheat, grub_util_fd_strerror ());
572e3ea6
VS
746 if (grub_util_fd_read (dev->cheat_fd, buf, size << disk->log_sector_size)
747 != (ssize_t) (size << disk->log_sector_size))
9c4b5c13 748 return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
20d53541 749 dev->cheat, grub_util_fd_strerror ());
1a1f408f
VS
750 return GRUB_ERR_NONE;
751 }
752#endif
753
754 grub_dprintf ("cryptodisk",
755 "Reading %" PRIuGRUB_SIZE " sectors from sector 0x%"
756 PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT64_T "\n",
757 size, sector, dev->offset);
758
572e3ea6 759 err = grub_disk_read (dev->source_disk,
e1b0992a
GW
760 grub_disk_from_native_sector (disk, sector + dev->offset),
761 0, size << disk->log_sector_size, buf);
1a1f408f
VS
762 if (err)
763 {
764 grub_dprintf ("cryptodisk", "grub_disk_read failed with error %d\n", err);
765 return err;
766 }
9c6e84b8
VS
767 gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) buf,
768 size << disk->log_sector_size,
769 sector, 0);
1a1f408f
VS
770 return grub_crypto_gcry_error (gcry_err);
771}
772
773static grub_err_t
9c6e84b8
VS
774grub_cryptodisk_write (grub_disk_t disk, grub_disk_addr_t sector,
775 grub_size_t size, const char *buf)
1a1f408f 776{
9c6e84b8
VS
777 grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
778 gcry_err_code_t gcry_err;
779 char *tmp;
780 grub_err_t err;
781
782#ifdef GRUB_UTIL
783 if (dev->cheat)
784 {
b73249d2
VS
785 int r;
786 r = grub_util_fd_seek (dev->cheat_fd, sector << disk->log_sector_size);
787 if (r)
788 return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
789 dev->cheat, grub_util_fd_strerror ());
9c6e84b8
VS
790 if (grub_util_fd_write (dev->cheat_fd, buf, size << disk->log_sector_size)
791 != (ssize_t) (size << disk->log_sector_size))
9c4b5c13 792 return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
20d53541 793 dev->cheat, grub_util_fd_strerror ());
9c6e84b8
VS
794 return GRUB_ERR_NONE;
795 }
796#endif
797
798 tmp = grub_malloc (size << disk->log_sector_size);
799 if (!tmp)
800 return grub_errno;
801 grub_memcpy (tmp, buf, size << disk->log_sector_size);
802
803 grub_dprintf ("cryptodisk",
804 "Writing %" PRIuGRUB_SIZE " sectors to sector 0x%"
805 PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT64_T "\n",
806 size, sector, dev->offset);
807
808 gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) tmp,
809 size << disk->log_sector_size,
810 sector, 1);
811 if (gcry_err)
812 {
813 grub_free (tmp);
814 return grub_crypto_gcry_error (gcry_err);
815 }
816
442b86de 817 /* Since ->write was called so disk.mod is loaded but be paranoid */
e1b0992a 818 sector = sector + dev->offset;
442b86de
VS
819 if (grub_disk_write_weak)
820 err = grub_disk_write_weak (dev->source_disk,
e1b0992a 821 grub_disk_from_native_sector (disk, sector),
442b86de
VS
822 0, size << disk->log_sector_size, tmp);
823 else
824 err = grub_error (GRUB_ERR_BUG, "disk.mod not loaded");
9c6e84b8
VS
825 grub_free (tmp);
826 return err;
1a1f408f
VS
827}
828
829#ifdef GRUB_UTIL
830static grub_disk_memberlist_t
831grub_cryptodisk_memberlist (grub_disk_t disk)
832{
833 grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
834 grub_disk_memberlist_t list = NULL;
835
836 list = grub_malloc (sizeof (*list));
837 if (list)
838 {
839 list->disk = dev->source_disk;
840 list->next = NULL;
841 }
842
843 return list;
844}
845#endif
846
847static void
848cryptodisk_cleanup (void)
849{
63fe43f3 850#if 0
1a1f408f
VS
851 grub_cryptodisk_t dev = cryptodisk_list;
852 grub_cryptodisk_t tmp;
853
854 while (dev != NULL)
855 {
856 grub_free (dev->source);
857 grub_free (dev->cipher);
858 grub_free (dev->secondary_cipher);
859 grub_free (dev->essiv_cipher);
860 tmp = dev->next;
861 grub_free (dev);
862 dev = tmp;
863 }
63fe43f3 864#endif
1a1f408f
VS
865}
866
867grub_err_t
868grub_cryptodisk_insert (grub_cryptodisk_t newdev, const char *name,
869 grub_disk_t source)
870{
871 newdev->source = grub_strdup (name);
872 if (!newdev->source)
873 {
874 grub_free (newdev);
875 return grub_errno;
876 }
877
6f5f3337 878 newdev->id = last_cryptodisk_id++;
1a1f408f
VS
879 newdev->source_id = source->id;
880 newdev->source_dev_id = source->dev->id;
c7f93a20 881 newdev->partition_start = grub_partition_get_start (source->partition);
1a1f408f
VS
882 newdev->next = cryptodisk_list;
883 cryptodisk_list = newdev;
884
885 return GRUB_ERR_NONE;
886}
887
888grub_cryptodisk_t
889grub_cryptodisk_get_by_uuid (const char *uuid)
890{
891 grub_cryptodisk_t dev;
892 for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
893 if (grub_strcasecmp (dev->uuid, uuid) == 0)
894 return dev;
895 return NULL;
896}
897
898grub_cryptodisk_t
899grub_cryptodisk_get_by_source_disk (grub_disk_t disk)
900{
901 grub_cryptodisk_t dev;
902 for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
903 if (dev->source_id == disk->id && dev->source_dev_id == disk->dev->id)
c7f93a20 904 if ((disk->partition && grub_partition_get_start (disk->partition) == dev->partition_start) ||
905 (!disk->partition && dev->partition_start == 0))
906 return dev;
1a1f408f
VS
907 return NULL;
908}
909
910#ifdef GRUB_UTIL
911grub_err_t
912grub_cryptodisk_cheat_insert (grub_cryptodisk_t newdev, const char *name,
913 grub_disk_t source, const char *cheat)
914{
915 newdev->cheat = grub_strdup (cheat);
916 newdev->source = grub_strdup (name);
917 if (!newdev->source || !newdev->cheat)
918 {
919 grub_free (newdev->source);
920 grub_free (newdev->cheat);
921 return grub_errno;
922 }
923
a47a78be 924 newdev->cheat_fd = GRUB_UTIL_FD_INVALID;
1a1f408f
VS
925 newdev->source_id = source->id;
926 newdev->source_dev_id = source->dev->id;
c7f93a20 927 newdev->partition_start = grub_partition_get_start (source->partition);
6f5f3337 928 newdev->id = last_cryptodisk_id++;
1a1f408f
VS
929 newdev->next = cryptodisk_list;
930 cryptodisk_list = newdev;
931
932 return GRUB_ERR_NONE;
933}
934
935void
bf25f879 936grub_util_cryptodisk_get_abstraction (grub_disk_t disk,
24024dac
CW
937 void (*cb) (const char *val, void *data),
938 void *data)
1a1f408f
VS
939{
940 grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
941
24024dac
CW
942 cb ("cryptodisk", data);
943 cb (dev->modname, data);
1a1f408f
VS
944
945 if (dev->cipher)
24024dac 946 cb (dev->cipher->cipher->modname, data);
1a1f408f 947 if (dev->secondary_cipher)
24024dac 948 cb (dev->secondary_cipher->cipher->modname, data);
1a1f408f 949 if (dev->essiv_cipher)
24024dac 950 cb (dev->essiv_cipher->cipher->modname, data);
1a1f408f 951 if (dev->hash)
24024dac 952 cb (dev->hash->modname, data);
1a1f408f 953 if (dev->essiv_hash)
24024dac 954 cb (dev->essiv_hash->modname, data);
1a1f408f 955 if (dev->iv_hash)
24024dac 956 cb (dev->iv_hash->modname, data);
1a1f408f 957}
20a40940 958
bf25f879
VS
959const char *
960grub_util_cryptodisk_get_uuid (grub_disk_t disk)
20a40940
VS
961{
962 grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
bf25f879 963 return dev->uuid;
20a40940
VS
964}
965
1a1f408f
VS
966#endif
967
20a40940
VS
968static int check_boot, have_it;
969static char *search_uuid;
970
971static void
972cryptodisk_close (grub_cryptodisk_t dev)
973{
974 grub_crypto_cipher_close (dev->cipher);
975 grub_crypto_cipher_close (dev->secondary_cipher);
976 grub_crypto_cipher_close (dev->essiv_cipher);
977 grub_free (dev);
978}
979
980static grub_err_t
981grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
982{
983 grub_err_t err;
984 grub_cryptodisk_t dev;
985 grub_cryptodisk_dev_t cr;
986
987 dev = grub_cryptodisk_get_by_source_disk (source);
988
989 if (dev)
990 return GRUB_ERR_NONE;
991
992 FOR_CRYPTODISK_DEVS (cr)
993 {
994 dev = cr->scan (source, search_uuid, check_boot);
995 if (grub_errno)
996 return grub_errno;
997 if (!dev)
998 continue;
999
1000 err = cr->recover_key (source, dev);
1001 if (err)
1002 {
1003 cryptodisk_close (dev);
1004 return err;
1005 }
1006
1007 grub_cryptodisk_insert (dev, name, source);
1008
1009 have_it = 1;
1010
1011 return GRUB_ERR_NONE;
1012 }
1013 return GRUB_ERR_NONE;
1014}
1015
1016#ifdef GRUB_UTIL
1017#include <grub/util/misc.h>
1018grub_err_t
1019grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat)
1020{
1021 grub_err_t err;
1022 grub_cryptodisk_t dev;
1023 grub_cryptodisk_dev_t cr;
1024 grub_disk_t source;
1025
1026 /* Try to open disk. */
1027 source = grub_disk_open (sourcedev);
1028 if (!source)
1029 return grub_errno;
1030
1031 dev = grub_cryptodisk_get_by_source_disk (source);
1032
1033 if (dev)
1034 {
1035 grub_disk_close (source);
1036 return GRUB_ERR_NONE;
1037 }
1038
1039 FOR_CRYPTODISK_DEVS (cr)
1040 {
1041 dev = cr->scan (source, search_uuid, check_boot);
1042 if (grub_errno)
1043 return grub_errno;
1044 if (!dev)
1045 continue;
1046
1047 grub_util_info ("cheatmounted %s (%s) at %s", sourcedev, dev->modname,
1048 cheat);
1049 err = grub_cryptodisk_cheat_insert (dev, sourcedev, source, cheat);
1050 grub_disk_close (source);
1051 if (err)
1052 grub_free (dev);
1053
1054 return GRUB_ERR_NONE;
1055 }
1056
1057 grub_disk_close (source);
1058
1059 return GRUB_ERR_NONE;
1060}
1061#endif
1062
1063static int
25239370
CW
1064grub_cryptodisk_scan_device (const char *name,
1065 void *data __attribute__ ((unused)))
20a40940
VS
1066{
1067 grub_err_t err;
1068 grub_disk_t source;
1069
1070 /* Try to open disk. */
1071 source = grub_disk_open (name);
1072 if (!source)
c5dbdc33
VS
1073 {
1074 grub_print_error ();
1075 return 0;
1076 }
20a40940
VS
1077
1078 err = grub_cryptodisk_scan_device_real (name, source);
1079
1080 grub_disk_close (source);
1081
1082 if (err)
1083 grub_print_error ();
1084 return have_it && search_uuid ? 1 : 0;
1085}
1086
1087static grub_err_t
1088grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
1089{
1090 struct grub_arg_list *state = ctxt->state;
1091
1092 if (argc < 1 && !state[1].set && !state[2].set)
1093 return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
1094
1095 have_it = 0;
1096 if (state[0].set)
1097 {
1098 grub_cryptodisk_t dev;
1099
1100 dev = grub_cryptodisk_get_by_uuid (args[0]);
1101 if (dev)
1102 {
1103 grub_dprintf ("cryptodisk",
1104 "already mounted as crypto%lu\n", dev->id);
1105 return GRUB_ERR_NONE;
1106 }
1107
1108 check_boot = state[2].set;
1109 search_uuid = args[0];
25239370 1110 grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
20a40940
VS
1111 search_uuid = NULL;
1112
1113 if (!have_it)
1114 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found");
1115 return GRUB_ERR_NONE;
1116 }
1117 else if (state[1].set || (argc == 0 && state[2].set))
1118 {
1119 search_uuid = NULL;
1120 check_boot = state[2].set;
25239370 1121 grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
20a40940
VS
1122 search_uuid = NULL;
1123 return GRUB_ERR_NONE;
1124 }
1125 else
1126 {
1127 grub_err_t err;
1128 grub_disk_t disk;
1129 grub_cryptodisk_t dev;
418f86c6 1130 char *diskname;
c93d3e69
AB
1131 char *disklast = NULL;
1132 grub_size_t len;
20a40940
VS
1133
1134 search_uuid = NULL;
1135 check_boot = state[2].set;
418f86c6 1136 diskname = args[0];
c93d3e69
AB
1137 len = grub_strlen (diskname);
1138 if (len && diskname[0] == '(' && diskname[len - 1] == ')')
ce96d01c 1139 {
c93d3e69 1140 disklast = &diskname[len - 1];
418f86c6 1141 *disklast = '\0';
c93d3e69 1142 diskname++;
ce96d01c 1143 }
c93d3e69
AB
1144
1145 disk = grub_disk_open (diskname);
20a40940 1146 if (!disk)
c93d3e69
AB
1147 {
1148 if (disklast)
1149 *disklast = ')';
1150 return grub_errno;
1151 }
20a40940
VS
1152
1153 dev = grub_cryptodisk_get_by_source_disk (disk);
1154 if (dev)
1155 {
1156 grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id);
1157 grub_disk_close (disk);
c93d3e69
AB
1158 if (disklast)
1159 *disklast = ')';
20a40940
VS
1160 return GRUB_ERR_NONE;
1161 }
1162
c93d3e69 1163 err = grub_cryptodisk_scan_device_real (diskname, disk);
20a40940
VS
1164
1165 grub_disk_close (disk);
c93d3e69
AB
1166 if (disklast)
1167 *disklast = ')';
20a40940
VS
1168
1169 return err;
1170 }
1171}
1172
1a1f408f
VS
1173static struct grub_disk_dev grub_cryptodisk_dev = {
1174 .name = "cryptodisk",
1175 .id = GRUB_DISK_DEVICE_CRYPTODISK_ID,
38409196
VS
1176 .disk_iterate = grub_cryptodisk_iterate,
1177 .disk_open = grub_cryptodisk_open,
1178 .disk_close = grub_cryptodisk_close,
1179 .disk_read = grub_cryptodisk_read,
1180 .disk_write = grub_cryptodisk_write,
1a1f408f 1181#ifdef GRUB_UTIL
38409196 1182 .disk_memberlist = grub_cryptodisk_memberlist,
1a1f408f
VS
1183#endif
1184 .next = 0
1185};
1186
ce50dbd7
VS
1187static char
1188hex (grub_uint8_t val)
1189{
1190 if (val < 10)
1191 return '0' + val;
1192 return 'a' + val - 10;
1193}
1194
1195/* Open a file named NAME and initialize FILE. */
1196static char *
431e57a7 1197luks_script_get (grub_size_t *sz)
ce50dbd7
VS
1198{
1199 grub_cryptodisk_t i;
1200 grub_size_t size = 0;
1201 char *ptr, *ret;
1202
431e57a7
VS
1203 *sz = 0;
1204
ce50dbd7
VS
1205 for (i = cryptodisk_list; i != NULL; i = i->next)
1206 if (grub_strcmp (i->modname, "luks") == 0)
1207 {
1208 size += sizeof ("luks_mount ");
1209 size += grub_strlen (i->uuid);
1210 size += grub_strlen (i->cipher->cipher->name);
1211 size += 54;
1212 if (i->essiv_hash)
1213 size += grub_strlen (i->essiv_hash->name);
1214 size += i->keysize * 2;
1215 }
1216
1217 ret = grub_malloc (size + 1);
1218 if (!ret)
1219 return 0;
1220
1221 ptr = ret;
1222
1223 for (i = cryptodisk_list; i != NULL; i = i->next)
1224 if (grub_strcmp (i->modname, "luks") == 0)
1225 {
1226 unsigned j;
1227 const char *iptr;
1228 ptr = grub_stpcpy (ptr, "luks_mount ");
1229 ptr = grub_stpcpy (ptr, i->uuid);
1230 *ptr++ = ' ';
1231 grub_snprintf (ptr, 21, "%" PRIuGRUB_UINT64_T " ", i->offset);
1232 while (*ptr)
1233 ptr++;
1234 for (iptr = i->cipher->cipher->name; *iptr; iptr++)
1235 *ptr++ = grub_tolower (*iptr);
1236 switch (i->mode)
1237 {
1238 case GRUB_CRYPTODISK_MODE_ECB:
1239 ptr = grub_stpcpy (ptr, "-ecb");
1240 break;
1241 case GRUB_CRYPTODISK_MODE_CBC:
1242 ptr = grub_stpcpy (ptr, "-cbc");
1243 break;
1244 case GRUB_CRYPTODISK_MODE_PCBC:
1245 ptr = grub_stpcpy (ptr, "-pcbc");
1246 break;
1247 case GRUB_CRYPTODISK_MODE_XTS:
1248 ptr = grub_stpcpy (ptr, "-xts");
1249 break;
1250 case GRUB_CRYPTODISK_MODE_LRW:
1251 ptr = grub_stpcpy (ptr, "-lrw");
1252 break;
1253 }
1254
1255 switch (i->mode_iv)
1256 {
1257 case GRUB_CRYPTODISK_MODE_IV_NULL:
1258 ptr = grub_stpcpy (ptr, "-null");
1259 break;
1260 case GRUB_CRYPTODISK_MODE_IV_PLAIN:
1261 ptr = grub_stpcpy (ptr, "-plain");
1262 break;
1263 case GRUB_CRYPTODISK_MODE_IV_PLAIN64:
1264 ptr = grub_stpcpy (ptr, "-plain64");
1265 break;
1266 case GRUB_CRYPTODISK_MODE_IV_BENBI:
1267 ptr = grub_stpcpy (ptr, "-benbi");
1268 break;
1269 case GRUB_CRYPTODISK_MODE_IV_ESSIV:
1270 ptr = grub_stpcpy (ptr, "-essiv:");
1271 ptr = grub_stpcpy (ptr, i->essiv_hash->name);
1272 break;
1273 case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64:
1274 case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH:
1275 break;
1276 }
1277 *ptr++ = ' ';
1278 for (j = 0; j < i->keysize; j++)
1279 {
1280 *ptr++ = hex (i->key[j] >> 4);
1281 *ptr++ = hex (i->key[j] & 0xf);
1282 }
1283 *ptr++ = '\n';
1284 }
1285 *ptr = '\0';
431e57a7 1286 *sz = ptr - ret;
ce50dbd7
VS
1287 return ret;
1288}
1289
1290struct grub_procfs_entry luks_script =
1291{
1292 .name = "luks_script",
1293 .get_contents = luks_script_get
1294};
1295
20a40940
VS
1296static grub_extcmd_t cmd;
1297
1a1f408f
VS
1298GRUB_MOD_INIT (cryptodisk)
1299{
1300 grub_disk_dev_register (&grub_cryptodisk_dev);
20a40940
VS
1301 cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
1302 N_("SOURCE|-u UUID|-a|-b"),
1303 N_("Mount a crypto device."), options);
ce50dbd7 1304 grub_procfs_register ("luks_script", &luks_script);
1a1f408f
VS
1305}
1306
1307GRUB_MOD_FINI (cryptodisk)
1308{
1309 grub_disk_dev_unregister (&grub_cryptodisk_dev);
1310 cryptodisk_cleanup ();
3b3ac0c9 1311 grub_unregister_extcmd (cmd);
ce50dbd7 1312 grub_procfs_unregister (&luks_script);
1a1f408f 1313}