xref: /qemu/crypto/block-luks.c (revision da34e65c)
13e308f20SDaniel P. Berrange /*
23e308f20SDaniel P. Berrange  * QEMU Crypto block device encryption LUKS format
33e308f20SDaniel P. Berrange  *
43e308f20SDaniel P. Berrange  * Copyright (c) 2015-2016 Red Hat, Inc.
53e308f20SDaniel P. Berrange  *
63e308f20SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
73e308f20SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
83e308f20SDaniel P. Berrange  * License as published by the Free Software Foundation; either
93e308f20SDaniel P. Berrange  * version 2 of the License, or (at your option) any later version.
103e308f20SDaniel P. Berrange  *
113e308f20SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
123e308f20SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
133e308f20SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
143e308f20SDaniel P. Berrange  * Lesser General Public License for more details.
153e308f20SDaniel P. Berrange  *
163e308f20SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
173e308f20SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
183e308f20SDaniel P. Berrange  *
193e308f20SDaniel P. Berrange  */
203e308f20SDaniel P. Berrange 
213e308f20SDaniel P. Berrange #include "qemu/osdep.h"
22*da34e65cSMarkus Armbruster #include "qapi/error.h"
233e308f20SDaniel P. Berrange 
243e308f20SDaniel P. Berrange #include "crypto/block-luks.h"
253e308f20SDaniel P. Berrange 
263e308f20SDaniel P. Berrange #include "crypto/hash.h"
273e308f20SDaniel P. Berrange #include "crypto/afsplit.h"
283e308f20SDaniel P. Berrange #include "crypto/pbkdf.h"
293e308f20SDaniel P. Berrange #include "crypto/secret.h"
303e308f20SDaniel P. Berrange #include "crypto/random.h"
313e308f20SDaniel P. Berrange 
323e308f20SDaniel P. Berrange #ifdef CONFIG_UUID
333e308f20SDaniel P. Berrange #include <uuid/uuid.h>
343e308f20SDaniel P. Berrange #endif
353e308f20SDaniel P. Berrange 
363e308f20SDaniel P. Berrange #include "qemu/coroutine.h"
373e308f20SDaniel P. Berrange 
383e308f20SDaniel P. Berrange /*
393e308f20SDaniel P. Berrange  * Reference for the LUKS format implemented here is
403e308f20SDaniel P. Berrange  *
413e308f20SDaniel P. Berrange  *   docs/on-disk-format.pdf
423e308f20SDaniel P. Berrange  *
433e308f20SDaniel P. Berrange  * in 'cryptsetup' package source code
443e308f20SDaniel P. Berrange  *
453e308f20SDaniel P. Berrange  * This file implements the 1.2.1 specification, dated
463e308f20SDaniel P. Berrange  * Oct 16, 2011.
473e308f20SDaniel P. Berrange  */
483e308f20SDaniel P. Berrange 
493e308f20SDaniel P. Berrange typedef struct QCryptoBlockLUKS QCryptoBlockLUKS;
503e308f20SDaniel P. Berrange typedef struct QCryptoBlockLUKSHeader QCryptoBlockLUKSHeader;
513e308f20SDaniel P. Berrange typedef struct QCryptoBlockLUKSKeySlot QCryptoBlockLUKSKeySlot;
523e308f20SDaniel P. Berrange 
533e308f20SDaniel P. Berrange 
543e308f20SDaniel P. Berrange /* The following constants are all defined by the LUKS spec */
553e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_VERSION 1
563e308f20SDaniel P. Berrange 
573e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_MAGIC_LEN 6
583e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN 32
593e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN 32
603e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN 32
613e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_DIGEST_LEN 20
623e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_SALT_LEN 32
633e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_UUID_LEN 40
643e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS 8
653e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_STRIPES 4000
663e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS 1000
673e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS 1000
683e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET 4096
693e308f20SDaniel P. Berrange 
703e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED 0x0000DEAD
713e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED 0x00AC71F3
723e308f20SDaniel P. Berrange 
733e308f20SDaniel P. Berrange #define QCRYPTO_BLOCK_LUKS_SECTOR_SIZE 512LL
743e308f20SDaniel P. Berrange 
753e308f20SDaniel P. Berrange static const char qcrypto_block_luks_magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN] = {
763e308f20SDaniel P. Berrange     'L', 'U', 'K', 'S', 0xBA, 0xBE
773e308f20SDaniel P. Berrange };
783e308f20SDaniel P. Berrange 
793e308f20SDaniel P. Berrange typedef struct QCryptoBlockLUKSNameMap QCryptoBlockLUKSNameMap;
803e308f20SDaniel P. Berrange struct QCryptoBlockLUKSNameMap {
813e308f20SDaniel P. Berrange     const char *name;
823e308f20SDaniel P. Berrange     int id;
833e308f20SDaniel P. Berrange };
843e308f20SDaniel P. Berrange 
853e308f20SDaniel P. Berrange typedef struct QCryptoBlockLUKSCipherSizeMap QCryptoBlockLUKSCipherSizeMap;
863e308f20SDaniel P. Berrange struct QCryptoBlockLUKSCipherSizeMap {
873e308f20SDaniel P. Berrange     uint32_t key_bytes;
883e308f20SDaniel P. Berrange     int id;
893e308f20SDaniel P. Berrange };
903e308f20SDaniel P. Berrange typedef struct QCryptoBlockLUKSCipherNameMap QCryptoBlockLUKSCipherNameMap;
913e308f20SDaniel P. Berrange struct QCryptoBlockLUKSCipherNameMap {
923e308f20SDaniel P. Berrange     const char *name;
933e308f20SDaniel P. Berrange     const QCryptoBlockLUKSCipherSizeMap *sizes;
943e308f20SDaniel P. Berrange };
953e308f20SDaniel P. Berrange 
963e308f20SDaniel P. Berrange 
973e308f20SDaniel P. Berrange static const QCryptoBlockLUKSCipherSizeMap
983e308f20SDaniel P. Berrange qcrypto_block_luks_cipher_size_map_aes[] = {
993e308f20SDaniel P. Berrange     { 16, QCRYPTO_CIPHER_ALG_AES_128 },
1003e308f20SDaniel P. Berrange     { 24, QCRYPTO_CIPHER_ALG_AES_192 },
1013e308f20SDaniel P. Berrange     { 32, QCRYPTO_CIPHER_ALG_AES_256 },
1023e308f20SDaniel P. Berrange     { 0, 0 },
1033e308f20SDaniel P. Berrange };
1043e308f20SDaniel P. Berrange 
1053e308f20SDaniel P. Berrange static const QCryptoBlockLUKSCipherSizeMap
1063e308f20SDaniel P. Berrange qcrypto_block_luks_cipher_size_map_cast5[] = {
1073e308f20SDaniel P. Berrange     { 16, QCRYPTO_CIPHER_ALG_CAST5_128 },
1083e308f20SDaniel P. Berrange     { 0, 0 },
1093e308f20SDaniel P. Berrange };
1103e308f20SDaniel P. Berrange 
1113e308f20SDaniel P. Berrange static const QCryptoBlockLUKSCipherSizeMap
1123e308f20SDaniel P. Berrange qcrypto_block_luks_cipher_size_map_serpent[] = {
1133e308f20SDaniel P. Berrange     { 16, QCRYPTO_CIPHER_ALG_SERPENT_128 },
1143e308f20SDaniel P. Berrange     { 24, QCRYPTO_CIPHER_ALG_SERPENT_192 },
1153e308f20SDaniel P. Berrange     { 32, QCRYPTO_CIPHER_ALG_SERPENT_256 },
1163e308f20SDaniel P. Berrange     { 0, 0 },
1173e308f20SDaniel P. Berrange };
1183e308f20SDaniel P. Berrange 
1193e308f20SDaniel P. Berrange static const QCryptoBlockLUKSCipherSizeMap
1203e308f20SDaniel P. Berrange qcrypto_block_luks_cipher_size_map_twofish[] = {
1213e308f20SDaniel P. Berrange     { 16, QCRYPTO_CIPHER_ALG_TWOFISH_128 },
1223e308f20SDaniel P. Berrange     { 24, QCRYPTO_CIPHER_ALG_TWOFISH_192 },
1233e308f20SDaniel P. Berrange     { 32, QCRYPTO_CIPHER_ALG_TWOFISH_256 },
1243e308f20SDaniel P. Berrange     { 0, 0 },
1253e308f20SDaniel P. Berrange };
1263e308f20SDaniel P. Berrange 
1273e308f20SDaniel P. Berrange static const QCryptoBlockLUKSCipherNameMap
1283e308f20SDaniel P. Berrange qcrypto_block_luks_cipher_name_map[] = {
1293e308f20SDaniel P. Berrange     { "aes", qcrypto_block_luks_cipher_size_map_aes },
1303e308f20SDaniel P. Berrange     { "cast5", qcrypto_block_luks_cipher_size_map_cast5 },
1313e308f20SDaniel P. Berrange     { "serpent", qcrypto_block_luks_cipher_size_map_serpent },
1323e308f20SDaniel P. Berrange     { "twofish", qcrypto_block_luks_cipher_size_map_twofish },
1333e308f20SDaniel P. Berrange };
1343e308f20SDaniel P. Berrange 
1353e308f20SDaniel P. Berrange 
1363e308f20SDaniel P. Berrange /*
1373e308f20SDaniel P. Berrange  * This struct is written to disk in big-endian format,
1383e308f20SDaniel P. Berrange  * but operated upon in native-endian format.
1393e308f20SDaniel P. Berrange  */
1403e308f20SDaniel P. Berrange struct QCryptoBlockLUKSKeySlot {
1413e308f20SDaniel P. Berrange     /* state of keyslot, enabled/disable */
1423e308f20SDaniel P. Berrange     uint32_t active;
1433e308f20SDaniel P. Berrange     /* iterations for PBKDF2 */
1443e308f20SDaniel P. Berrange     uint32_t iterations;
1453e308f20SDaniel P. Berrange     /* salt for PBKDF2 */
1463e308f20SDaniel P. Berrange     uint8_t salt[QCRYPTO_BLOCK_LUKS_SALT_LEN];
1473e308f20SDaniel P. Berrange     /* start sector of key material */
1483e308f20SDaniel P. Berrange     uint32_t key_offset;
1493e308f20SDaniel P. Berrange     /* number of anti-forensic stripes */
1503e308f20SDaniel P. Berrange     uint32_t stripes;
1513e308f20SDaniel P. Berrange } QEMU_PACKED;
1523e308f20SDaniel P. Berrange 
1533e308f20SDaniel P. Berrange QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSKeySlot) != 48);
1543e308f20SDaniel P. Berrange 
1553e308f20SDaniel P. Berrange 
1563e308f20SDaniel P. Berrange /*
1573e308f20SDaniel P. Berrange  * This struct is written to disk in big-endian format,
1583e308f20SDaniel P. Berrange  * but operated upon in native-endian format.
1593e308f20SDaniel P. Berrange  */
1603e308f20SDaniel P. Berrange struct QCryptoBlockLUKSHeader {
1613e308f20SDaniel P. Berrange     /* 'L', 'U', 'K', 'S', '0xBA', '0xBE' */
1623e308f20SDaniel P. Berrange     char magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN];
1633e308f20SDaniel P. Berrange 
1643e308f20SDaniel P. Berrange     /* LUKS version, currently 1 */
1653e308f20SDaniel P. Berrange     uint16_t version;
1663e308f20SDaniel P. Berrange 
1673e308f20SDaniel P. Berrange     /* cipher name specification (aes, etc) */
1683e308f20SDaniel P. Berrange     char cipher_name[QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN];
1693e308f20SDaniel P. Berrange 
1703e308f20SDaniel P. Berrange     /* cipher mode specification (cbc-plain, xts-essiv:sha256, etc) */
1713e308f20SDaniel P. Berrange     char cipher_mode[QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN];
1723e308f20SDaniel P. Berrange 
1733e308f20SDaniel P. Berrange     /* hash specification (sha256, etc) */
1743e308f20SDaniel P. Berrange     char hash_spec[QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN];
1753e308f20SDaniel P. Berrange 
1763e308f20SDaniel P. Berrange     /* start offset of the volume data (in 512 byte sectors) */
1773e308f20SDaniel P. Berrange     uint32_t payload_offset;
1783e308f20SDaniel P. Berrange 
1793e308f20SDaniel P. Berrange     /* Number of key bytes */
1803e308f20SDaniel P. Berrange     uint32_t key_bytes;
1813e308f20SDaniel P. Berrange 
1823e308f20SDaniel P. Berrange     /* master key checksum after PBKDF2 */
1833e308f20SDaniel P. Berrange     uint8_t master_key_digest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN];
1843e308f20SDaniel P. Berrange 
1853e308f20SDaniel P. Berrange     /* salt for master key PBKDF2 */
1863e308f20SDaniel P. Berrange     uint8_t master_key_salt[QCRYPTO_BLOCK_LUKS_SALT_LEN];
1873e308f20SDaniel P. Berrange 
1883e308f20SDaniel P. Berrange     /* iterations for master key PBKDF2 */
1893e308f20SDaniel P. Berrange     uint32_t master_key_iterations;
1903e308f20SDaniel P. Berrange 
1913e308f20SDaniel P. Berrange     /* UUID of the partition in standard ASCII representation */
1923e308f20SDaniel P. Berrange     uint8_t uuid[QCRYPTO_BLOCK_LUKS_UUID_LEN];
1933e308f20SDaniel P. Berrange 
1943e308f20SDaniel P. Berrange     /* key slots */
1953e308f20SDaniel P. Berrange     QCryptoBlockLUKSKeySlot key_slots[QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS];
1963e308f20SDaniel P. Berrange } QEMU_PACKED;
1973e308f20SDaniel P. Berrange 
1983e308f20SDaniel P. Berrange QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSHeader) != 592);
1993e308f20SDaniel P. Berrange 
2003e308f20SDaniel P. Berrange 
2013e308f20SDaniel P. Berrange struct QCryptoBlockLUKS {
2023e308f20SDaniel P. Berrange     QCryptoBlockLUKSHeader header;
2033e308f20SDaniel P. Berrange };
2043e308f20SDaniel P. Berrange 
2053e308f20SDaniel P. Berrange 
2063e308f20SDaniel P. Berrange static int qcrypto_block_luks_cipher_name_lookup(const char *name,
2073e308f20SDaniel P. Berrange                                                  QCryptoCipherMode mode,
2083e308f20SDaniel P. Berrange                                                  uint32_t key_bytes,
2093e308f20SDaniel P. Berrange                                                  Error **errp)
2103e308f20SDaniel P. Berrange {
2113e308f20SDaniel P. Berrange     const QCryptoBlockLUKSCipherNameMap *map =
2123e308f20SDaniel P. Berrange         qcrypto_block_luks_cipher_name_map;
2133e308f20SDaniel P. Berrange     size_t maplen = G_N_ELEMENTS(qcrypto_block_luks_cipher_name_map);
2143e308f20SDaniel P. Berrange     size_t i, j;
2153e308f20SDaniel P. Berrange 
2163e308f20SDaniel P. Berrange     if (mode == QCRYPTO_CIPHER_MODE_XTS) {
2173e308f20SDaniel P. Berrange         key_bytes /= 2;
2183e308f20SDaniel P. Berrange     }
2193e308f20SDaniel P. Berrange 
2203e308f20SDaniel P. Berrange     for (i = 0; i < maplen; i++) {
2213e308f20SDaniel P. Berrange         if (!g_str_equal(map[i].name, name)) {
2223e308f20SDaniel P. Berrange             continue;
2233e308f20SDaniel P. Berrange         }
2243e308f20SDaniel P. Berrange         for (j = 0; j < map[i].sizes[j].key_bytes; j++) {
2253e308f20SDaniel P. Berrange             if (map[i].sizes[j].key_bytes == key_bytes) {
2263e308f20SDaniel P. Berrange                 return map[i].sizes[j].id;
2273e308f20SDaniel P. Berrange             }
2283e308f20SDaniel P. Berrange         }
2293e308f20SDaniel P. Berrange     }
2303e308f20SDaniel P. Berrange 
2313e308f20SDaniel P. Berrange     error_setg(errp, "Algorithm %s with key size %d bytes not supported",
2323e308f20SDaniel P. Berrange                name, key_bytes);
2333e308f20SDaniel P. Berrange     return 0;
2343e308f20SDaniel P. Berrange }
2353e308f20SDaniel P. Berrange 
2363e308f20SDaniel P. Berrange static const char *
2373e308f20SDaniel P. Berrange qcrypto_block_luks_cipher_alg_lookup(QCryptoCipherAlgorithm alg,
2383e308f20SDaniel P. Berrange                                      Error **errp)
2393e308f20SDaniel P. Berrange {
2403e308f20SDaniel P. Berrange     const QCryptoBlockLUKSCipherNameMap *map =
2413e308f20SDaniel P. Berrange         qcrypto_block_luks_cipher_name_map;
2423e308f20SDaniel P. Berrange     size_t maplen = G_N_ELEMENTS(qcrypto_block_luks_cipher_name_map);
2433e308f20SDaniel P. Berrange     size_t i, j;
2443e308f20SDaniel P. Berrange     for (i = 0; i < maplen; i++) {
2453e308f20SDaniel P. Berrange         for (j = 0; j < map[i].sizes[j].key_bytes; j++) {
2463e308f20SDaniel P. Berrange             if (map[i].sizes[j].id == alg) {
2473e308f20SDaniel P. Berrange                 return map[i].name;
2483e308f20SDaniel P. Berrange             }
2493e308f20SDaniel P. Berrange         }
2503e308f20SDaniel P. Berrange     }
2513e308f20SDaniel P. Berrange 
2523e308f20SDaniel P. Berrange     error_setg(errp, "Algorithm '%s' not supported",
2533e308f20SDaniel P. Berrange                QCryptoCipherAlgorithm_lookup[alg]);
2543e308f20SDaniel P. Berrange     return NULL;
2553e308f20SDaniel P. Berrange }
2563e308f20SDaniel P. Berrange 
2573e308f20SDaniel P. Berrange /* XXX replace with qapi_enum_parse() in future, when we can
2583e308f20SDaniel P. Berrange  * make that function emit a more friendly error message */
2593e308f20SDaniel P. Berrange static int qcrypto_block_luks_name_lookup(const char *name,
2603e308f20SDaniel P. Berrange                                           const char *const *map,
2613e308f20SDaniel P. Berrange                                           size_t maplen,
2623e308f20SDaniel P. Berrange                                           const char *type,
2633e308f20SDaniel P. Berrange                                           Error **errp)
2643e308f20SDaniel P. Berrange {
2653e308f20SDaniel P. Berrange     size_t i;
2663e308f20SDaniel P. Berrange     for (i = 0; i < maplen; i++) {
2673e308f20SDaniel P. Berrange         if (g_str_equal(map[i], name)) {
2683e308f20SDaniel P. Berrange             return i;
2693e308f20SDaniel P. Berrange         }
2703e308f20SDaniel P. Berrange     }
2713e308f20SDaniel P. Berrange 
2723e308f20SDaniel P. Berrange     error_setg(errp, "%s %s not supported", type, name);
2733e308f20SDaniel P. Berrange     return 0;
2743e308f20SDaniel P. Berrange }
2753e308f20SDaniel P. Berrange 
2763e308f20SDaniel P. Berrange #define qcrypto_block_luks_cipher_mode_lookup(name, errp)               \
2773e308f20SDaniel P. Berrange     qcrypto_block_luks_name_lookup(name,                                \
2783e308f20SDaniel P. Berrange                                    QCryptoCipherMode_lookup,            \
2793e308f20SDaniel P. Berrange                                    QCRYPTO_CIPHER_MODE__MAX,            \
2803e308f20SDaniel P. Berrange                                    "Cipher mode",                       \
2813e308f20SDaniel P. Berrange                                    errp)
2823e308f20SDaniel P. Berrange 
2833e308f20SDaniel P. Berrange #define qcrypto_block_luks_hash_name_lookup(name, errp)                 \
2843e308f20SDaniel P. Berrange     qcrypto_block_luks_name_lookup(name,                                \
2853e308f20SDaniel P. Berrange                                    QCryptoHashAlgorithm_lookup,         \
2863e308f20SDaniel P. Berrange                                    QCRYPTO_HASH_ALG__MAX,               \
2873e308f20SDaniel P. Berrange                                    "Hash algorithm",                    \
2883e308f20SDaniel P. Berrange                                    errp)
2893e308f20SDaniel P. Berrange 
2903e308f20SDaniel P. Berrange #define qcrypto_block_luks_ivgen_name_lookup(name, errp)                \
2913e308f20SDaniel P. Berrange     qcrypto_block_luks_name_lookup(name,                                \
2923e308f20SDaniel P. Berrange                                    QCryptoIVGenAlgorithm_lookup,        \
2933e308f20SDaniel P. Berrange                                    QCRYPTO_IVGEN_ALG__MAX,              \
2943e308f20SDaniel P. Berrange                                    "IV generator",                      \
2953e308f20SDaniel P. Berrange                                    errp)
2963e308f20SDaniel P. Berrange 
2973e308f20SDaniel P. Berrange 
2983e308f20SDaniel P. Berrange static bool
2993e308f20SDaniel P. Berrange qcrypto_block_luks_has_format(const uint8_t *buf,
3003e308f20SDaniel P. Berrange                               size_t buf_size)
3013e308f20SDaniel P. Berrange {
3023e308f20SDaniel P. Berrange     const QCryptoBlockLUKSHeader *luks_header = (const void *)buf;
3033e308f20SDaniel P. Berrange 
3043e308f20SDaniel P. Berrange     if (buf_size >= offsetof(QCryptoBlockLUKSHeader, cipher_name) &&
3053e308f20SDaniel P. Berrange         memcmp(luks_header->magic, qcrypto_block_luks_magic,
3063e308f20SDaniel P. Berrange                QCRYPTO_BLOCK_LUKS_MAGIC_LEN) == 0 &&
3073e308f20SDaniel P. Berrange         be16_to_cpu(luks_header->version) == QCRYPTO_BLOCK_LUKS_VERSION) {
3083e308f20SDaniel P. Berrange         return true;
3093e308f20SDaniel P. Berrange     } else {
3103e308f20SDaniel P. Berrange         return false;
3113e308f20SDaniel P. Berrange     }
3123e308f20SDaniel P. Berrange }
3133e308f20SDaniel P. Berrange 
3143e308f20SDaniel P. Berrange 
3153e308f20SDaniel P. Berrange /**
3163e308f20SDaniel P. Berrange  * Deal with a quirk of dm-crypt usage of ESSIV.
3173e308f20SDaniel P. Berrange  *
3183e308f20SDaniel P. Berrange  * When calculating ESSIV IVs, the cipher length used by ESSIV
3193e308f20SDaniel P. Berrange  * may be different from the cipher length used for the block
3203e308f20SDaniel P. Berrange  * encryption, becauses dm-crypt uses the hash digest length
3213e308f20SDaniel P. Berrange  * as the key size. ie, if you have AES 128 as the block cipher
3223e308f20SDaniel P. Berrange  * and SHA 256 as ESSIV hash, then ESSIV will use AES 256 as
3233e308f20SDaniel P. Berrange  * the cipher since that gets a key length matching the digest
3243e308f20SDaniel P. Berrange  * size, not AES 128 with truncated digest as might be imagined
3253e308f20SDaniel P. Berrange  */
3263e308f20SDaniel P. Berrange static QCryptoCipherAlgorithm
3273e308f20SDaniel P. Berrange qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher,
3283e308f20SDaniel P. Berrange                                 QCryptoHashAlgorithm hash,
3293e308f20SDaniel P. Berrange                                 Error **errp)
3303e308f20SDaniel P. Berrange {
3313e308f20SDaniel P. Berrange     size_t digestlen = qcrypto_hash_digest_len(hash);
3323e308f20SDaniel P. Berrange     size_t keylen = qcrypto_cipher_get_key_len(cipher);
3333e308f20SDaniel P. Berrange     if (digestlen == keylen) {
3343e308f20SDaniel P. Berrange         return cipher;
3353e308f20SDaniel P. Berrange     }
3363e308f20SDaniel P. Berrange 
3373e308f20SDaniel P. Berrange     switch (cipher) {
3383e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_AES_128:
3393e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_AES_192:
3403e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_AES_256:
3413e308f20SDaniel P. Berrange         if (digestlen == qcrypto_cipher_get_key_len(
3423e308f20SDaniel P. Berrange                 QCRYPTO_CIPHER_ALG_AES_128)) {
3433e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_AES_128;
3443e308f20SDaniel P. Berrange         } else if (digestlen == qcrypto_cipher_get_key_len(
3453e308f20SDaniel P. Berrange                        QCRYPTO_CIPHER_ALG_AES_192)) {
3463e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_AES_192;
3473e308f20SDaniel P. Berrange         } else if (digestlen == qcrypto_cipher_get_key_len(
3483e308f20SDaniel P. Berrange                        QCRYPTO_CIPHER_ALG_AES_256)) {
3493e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_AES_256;
3503e308f20SDaniel P. Berrange         } else {
3513e308f20SDaniel P. Berrange             error_setg(errp, "No AES cipher with key size %zu available",
3523e308f20SDaniel P. Berrange                        digestlen);
3533e308f20SDaniel P. Berrange             return 0;
3543e308f20SDaniel P. Berrange         }
3553e308f20SDaniel P. Berrange         break;
3563e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_SERPENT_128:
3573e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_SERPENT_192:
3583e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_SERPENT_256:
3593e308f20SDaniel P. Berrange         if (digestlen == qcrypto_cipher_get_key_len(
3603e308f20SDaniel P. Berrange                 QCRYPTO_CIPHER_ALG_SERPENT_128)) {
3613e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_SERPENT_128;
3623e308f20SDaniel P. Berrange         } else if (digestlen == qcrypto_cipher_get_key_len(
3633e308f20SDaniel P. Berrange                        QCRYPTO_CIPHER_ALG_SERPENT_192)) {
3643e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_SERPENT_192;
3653e308f20SDaniel P. Berrange         } else if (digestlen == qcrypto_cipher_get_key_len(
3663e308f20SDaniel P. Berrange                        QCRYPTO_CIPHER_ALG_SERPENT_256)) {
3673e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_SERPENT_256;
3683e308f20SDaniel P. Berrange         } else {
3693e308f20SDaniel P. Berrange             error_setg(errp, "No Serpent cipher with key size %zu available",
3703e308f20SDaniel P. Berrange                        digestlen);
3713e308f20SDaniel P. Berrange             return 0;
3723e308f20SDaniel P. Berrange         }
3733e308f20SDaniel P. Berrange         break;
3743e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
3753e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_TWOFISH_192:
3763e308f20SDaniel P. Berrange     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
3773e308f20SDaniel P. Berrange         if (digestlen == qcrypto_cipher_get_key_len(
3783e308f20SDaniel P. Berrange                 QCRYPTO_CIPHER_ALG_TWOFISH_128)) {
3793e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_TWOFISH_128;
3803e308f20SDaniel P. Berrange         } else if (digestlen == qcrypto_cipher_get_key_len(
3813e308f20SDaniel P. Berrange                        QCRYPTO_CIPHER_ALG_TWOFISH_192)) {
3823e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_TWOFISH_192;
3833e308f20SDaniel P. Berrange         } else if (digestlen == qcrypto_cipher_get_key_len(
3843e308f20SDaniel P. Berrange                        QCRYPTO_CIPHER_ALG_TWOFISH_256)) {
3853e308f20SDaniel P. Berrange             return QCRYPTO_CIPHER_ALG_TWOFISH_256;
3863e308f20SDaniel P. Berrange         } else {
3873e308f20SDaniel P. Berrange             error_setg(errp, "No Twofish cipher with key size %zu available",
3883e308f20SDaniel P. Berrange                        digestlen);
3893e308f20SDaniel P. Berrange             return 0;
3903e308f20SDaniel P. Berrange         }
3913e308f20SDaniel P. Berrange         break;
3923e308f20SDaniel P. Berrange     default:
3933e308f20SDaniel P. Berrange         error_setg(errp, "Cipher %s not supported with essiv",
3943e308f20SDaniel P. Berrange                    QCryptoCipherAlgorithm_lookup[cipher]);
3953e308f20SDaniel P. Berrange         return 0;
3963e308f20SDaniel P. Berrange     }
3973e308f20SDaniel P. Berrange }
3983e308f20SDaniel P. Berrange 
3993e308f20SDaniel P. Berrange /*
4003e308f20SDaniel P. Berrange  * Given a key slot, and user password, this will attempt to unlock
4013e308f20SDaniel P. Berrange  * the master encryption key from the key slot.
4023e308f20SDaniel P. Berrange  *
4033e308f20SDaniel P. Berrange  * Returns:
4043e308f20SDaniel P. Berrange  *    0 if the key slot is disabled, or key could not be decrypted
4053e308f20SDaniel P. Berrange  *      with the provided password
4063e308f20SDaniel P. Berrange  *    1 if the key slot is enabled, and key decrypted successfully
4073e308f20SDaniel P. Berrange  *      with the provided password
4083e308f20SDaniel P. Berrange  *   -1 if a fatal error occurred loading the key
4093e308f20SDaniel P. Berrange  */
4103e308f20SDaniel P. Berrange static int
4113e308f20SDaniel P. Berrange qcrypto_block_luks_load_key(QCryptoBlock *block,
4123e308f20SDaniel P. Berrange                             QCryptoBlockLUKSKeySlot *slot,
4133e308f20SDaniel P. Berrange                             const char *password,
4143e308f20SDaniel P. Berrange                             QCryptoCipherAlgorithm cipheralg,
4153e308f20SDaniel P. Berrange                             QCryptoCipherMode ciphermode,
4163e308f20SDaniel P. Berrange                             QCryptoHashAlgorithm hash,
4173e308f20SDaniel P. Berrange                             QCryptoIVGenAlgorithm ivalg,
4183e308f20SDaniel P. Berrange                             QCryptoCipherAlgorithm ivcipheralg,
4193e308f20SDaniel P. Berrange                             QCryptoHashAlgorithm ivhash,
4203e308f20SDaniel P. Berrange                             uint8_t *masterkey,
4213e308f20SDaniel P. Berrange                             size_t masterkeylen,
4223e308f20SDaniel P. Berrange                             QCryptoBlockReadFunc readfunc,
4233e308f20SDaniel P. Berrange                             void *opaque,
4243e308f20SDaniel P. Berrange                             Error **errp)
4253e308f20SDaniel P. Berrange {
4263e308f20SDaniel P. Berrange     QCryptoBlockLUKS *luks = block->opaque;
4273e308f20SDaniel P. Berrange     uint8_t *splitkey;
4283e308f20SDaniel P. Berrange     size_t splitkeylen;
4293e308f20SDaniel P. Berrange     uint8_t *possiblekey;
4303e308f20SDaniel P. Berrange     int ret = -1;
4313e308f20SDaniel P. Berrange     ssize_t rv;
4323e308f20SDaniel P. Berrange     QCryptoCipher *cipher = NULL;
4333e308f20SDaniel P. Berrange     uint8_t keydigest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN];
4343e308f20SDaniel P. Berrange     QCryptoIVGen *ivgen = NULL;
4353e308f20SDaniel P. Berrange     size_t niv;
4363e308f20SDaniel P. Berrange 
4373e308f20SDaniel P. Berrange     if (slot->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED) {
4383e308f20SDaniel P. Berrange         return 0;
4393e308f20SDaniel P. Berrange     }
4403e308f20SDaniel P. Berrange 
4413e308f20SDaniel P. Berrange     splitkeylen = masterkeylen * slot->stripes;
4423e308f20SDaniel P. Berrange     splitkey = g_new0(uint8_t, splitkeylen);
4433e308f20SDaniel P. Berrange     possiblekey = g_new0(uint8_t, masterkeylen);
4443e308f20SDaniel P. Berrange 
4453e308f20SDaniel P. Berrange     /*
4463e308f20SDaniel P. Berrange      * The user password is used to generate a (possible)
4473e308f20SDaniel P. Berrange      * decryption key. This may or may not successfully
4483e308f20SDaniel P. Berrange      * decrypt the master key - we just blindly assume
4493e308f20SDaniel P. Berrange      * the key is correct and validate the results of
4503e308f20SDaniel P. Berrange      * decryption later.
4513e308f20SDaniel P. Berrange      */
4523e308f20SDaniel P. Berrange     if (qcrypto_pbkdf2(hash,
4533e308f20SDaniel P. Berrange                        (const uint8_t *)password, strlen(password),
4543e308f20SDaniel P. Berrange                        slot->salt, QCRYPTO_BLOCK_LUKS_SALT_LEN,
4553e308f20SDaniel P. Berrange                        slot->iterations,
4563e308f20SDaniel P. Berrange                        possiblekey, masterkeylen,
4573e308f20SDaniel P. Berrange                        errp) < 0) {
4583e308f20SDaniel P. Berrange         goto cleanup;
4593e308f20SDaniel P. Berrange     }
4603e308f20SDaniel P. Berrange 
4613e308f20SDaniel P. Berrange     /*
4623e308f20SDaniel P. Berrange      * We need to read the master key material from the
4633e308f20SDaniel P. Berrange      * LUKS key material header. What we're reading is
4643e308f20SDaniel P. Berrange      * not the raw master key, but rather the data after
4653e308f20SDaniel P. Berrange      * it has been passed through AFSplit and the result
4663e308f20SDaniel P. Berrange      * then encrypted.
4673e308f20SDaniel P. Berrange      */
4683e308f20SDaniel P. Berrange     rv = readfunc(block,
4693e308f20SDaniel P. Berrange                   slot->key_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
4703e308f20SDaniel P. Berrange                   splitkey, splitkeylen,
4713e308f20SDaniel P. Berrange                   errp,
4723e308f20SDaniel P. Berrange                   opaque);
4733e308f20SDaniel P. Berrange     if (rv < 0) {
4743e308f20SDaniel P. Berrange         goto cleanup;
4753e308f20SDaniel P. Berrange     }
4763e308f20SDaniel P. Berrange 
4773e308f20SDaniel P. Berrange 
4783e308f20SDaniel P. Berrange     /* Setup the cipher/ivgen that we'll use to try to decrypt
4793e308f20SDaniel P. Berrange      * the split master key material */
4803e308f20SDaniel P. Berrange     cipher = qcrypto_cipher_new(cipheralg, ciphermode,
4813e308f20SDaniel P. Berrange                                 possiblekey, masterkeylen,
4823e308f20SDaniel P. Berrange                                 errp);
4833e308f20SDaniel P. Berrange     if (!cipher) {
4843e308f20SDaniel P. Berrange         goto cleanup;
4853e308f20SDaniel P. Berrange     }
4863e308f20SDaniel P. Berrange 
4873e308f20SDaniel P. Berrange     niv = qcrypto_cipher_get_iv_len(cipheralg,
4883e308f20SDaniel P. Berrange                                     ciphermode);
4893e308f20SDaniel P. Berrange     ivgen = qcrypto_ivgen_new(ivalg,
4903e308f20SDaniel P. Berrange                               ivcipheralg,
4913e308f20SDaniel P. Berrange                               ivhash,
4923e308f20SDaniel P. Berrange                               possiblekey, masterkeylen,
4933e308f20SDaniel P. Berrange                               errp);
4943e308f20SDaniel P. Berrange     if (!ivgen) {
4953e308f20SDaniel P. Berrange         goto cleanup;
4963e308f20SDaniel P. Berrange     }
4973e308f20SDaniel P. Berrange 
4983e308f20SDaniel P. Berrange 
4993e308f20SDaniel P. Berrange     /*
5003e308f20SDaniel P. Berrange      * The master key needs to be decrypted in the same
5013e308f20SDaniel P. Berrange      * way that the block device payload will be decrypted
5023e308f20SDaniel P. Berrange      * later. In particular we'll be using the IV generator
5033e308f20SDaniel P. Berrange      * to reset the encryption cipher every time the master
5043e308f20SDaniel P. Berrange      * key crosses a sector boundary.
5053e308f20SDaniel P. Berrange      */
5063e308f20SDaniel P. Berrange     if (qcrypto_block_decrypt_helper(cipher,
5073e308f20SDaniel P. Berrange                                      niv,
5083e308f20SDaniel P. Berrange                                      ivgen,
5093e308f20SDaniel P. Berrange                                      QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
5103e308f20SDaniel P. Berrange                                      0,
5113e308f20SDaniel P. Berrange                                      splitkey,
5123e308f20SDaniel P. Berrange                                      splitkeylen,
5133e308f20SDaniel P. Berrange                                      errp) < 0) {
5143e308f20SDaniel P. Berrange         goto cleanup;
5153e308f20SDaniel P. Berrange     }
5163e308f20SDaniel P. Berrange 
5173e308f20SDaniel P. Berrange     /*
5183e308f20SDaniel P. Berrange      * Now we've decrypted the split master key, join
5193e308f20SDaniel P. Berrange      * it back together to get the actual master key.
5203e308f20SDaniel P. Berrange      */
5213e308f20SDaniel P. Berrange     if (qcrypto_afsplit_decode(hash,
5223e308f20SDaniel P. Berrange                                masterkeylen,
5233e308f20SDaniel P. Berrange                                slot->stripes,
5243e308f20SDaniel P. Berrange                                splitkey,
5253e308f20SDaniel P. Berrange                                masterkey,
5263e308f20SDaniel P. Berrange                                errp) < 0) {
5273e308f20SDaniel P. Berrange         goto cleanup;
5283e308f20SDaniel P. Berrange     }
5293e308f20SDaniel P. Berrange 
5303e308f20SDaniel P. Berrange 
5313e308f20SDaniel P. Berrange     /*
5323e308f20SDaniel P. Berrange      * We still don't know that the masterkey we got is valid,
5333e308f20SDaniel P. Berrange      * because we just blindly assumed the user's password
5343e308f20SDaniel P. Berrange      * was correct. This is where we now verify it. We are
5353e308f20SDaniel P. Berrange      * creating a hash of the master key using PBKDF and
5363e308f20SDaniel P. Berrange      * then comparing that to the hash stored in the key slot
5373e308f20SDaniel P. Berrange      * header
5383e308f20SDaniel P. Berrange      */
5393e308f20SDaniel P. Berrange     if (qcrypto_pbkdf2(hash,
5403e308f20SDaniel P. Berrange                        masterkey, masterkeylen,
5413e308f20SDaniel P. Berrange                        luks->header.master_key_salt,
5423e308f20SDaniel P. Berrange                        QCRYPTO_BLOCK_LUKS_SALT_LEN,
5433e308f20SDaniel P. Berrange                        luks->header.master_key_iterations,
5443e308f20SDaniel P. Berrange                        keydigest, G_N_ELEMENTS(keydigest),
5453e308f20SDaniel P. Berrange                        errp) < 0) {
5463e308f20SDaniel P. Berrange         goto cleanup;
5473e308f20SDaniel P. Berrange     }
5483e308f20SDaniel P. Berrange 
5493e308f20SDaniel P. Berrange     if (memcmp(keydigest, luks->header.master_key_digest,
5503e308f20SDaniel P. Berrange                QCRYPTO_BLOCK_LUKS_DIGEST_LEN) == 0) {
5513e308f20SDaniel P. Berrange         /* Success, we got the right master key */
5523e308f20SDaniel P. Berrange         ret = 1;
5533e308f20SDaniel P. Berrange         goto cleanup;
5543e308f20SDaniel P. Berrange     }
5553e308f20SDaniel P. Berrange 
5563e308f20SDaniel P. Berrange     /* Fail, user's password was not valid for this key slot,
5573e308f20SDaniel P. Berrange      * tell caller to try another slot */
5583e308f20SDaniel P. Berrange     ret = 0;
5593e308f20SDaniel P. Berrange 
5603e308f20SDaniel P. Berrange  cleanup:
5613e308f20SDaniel P. Berrange     qcrypto_ivgen_free(ivgen);
5623e308f20SDaniel P. Berrange     qcrypto_cipher_free(cipher);
5633e308f20SDaniel P. Berrange     g_free(splitkey);
5643e308f20SDaniel P. Berrange     g_free(possiblekey);
5653e308f20SDaniel P. Berrange     return ret;
5663e308f20SDaniel P. Berrange }
5673e308f20SDaniel P. Berrange 
5683e308f20SDaniel P. Berrange 
5693e308f20SDaniel P. Berrange /*
5703e308f20SDaniel P. Berrange  * Given a user password, this will iterate over all key
5713e308f20SDaniel P. Berrange  * slots and try to unlock each active key slot using the
5723e308f20SDaniel P. Berrange  * password until it successfully obtains a master key.
5733e308f20SDaniel P. Berrange  *
5743e308f20SDaniel P. Berrange  * Returns 0 if a key was loaded, -1 if no keys could be loaded
5753e308f20SDaniel P. Berrange  */
5763e308f20SDaniel P. Berrange static int
5773e308f20SDaniel P. Berrange qcrypto_block_luks_find_key(QCryptoBlock *block,
5783e308f20SDaniel P. Berrange                             const char *password,
5793e308f20SDaniel P. Berrange                             QCryptoCipherAlgorithm cipheralg,
5803e308f20SDaniel P. Berrange                             QCryptoCipherMode ciphermode,
5813e308f20SDaniel P. Berrange                             QCryptoHashAlgorithm hash,
5823e308f20SDaniel P. Berrange                             QCryptoIVGenAlgorithm ivalg,
5833e308f20SDaniel P. Berrange                             QCryptoCipherAlgorithm ivcipheralg,
5843e308f20SDaniel P. Berrange                             QCryptoHashAlgorithm ivhash,
5853e308f20SDaniel P. Berrange                             uint8_t **masterkey,
5863e308f20SDaniel P. Berrange                             size_t *masterkeylen,
5873e308f20SDaniel P. Berrange                             QCryptoBlockReadFunc readfunc,
5883e308f20SDaniel P. Berrange                             void *opaque,
5893e308f20SDaniel P. Berrange                             Error **errp)
5903e308f20SDaniel P. Berrange {
5913e308f20SDaniel P. Berrange     QCryptoBlockLUKS *luks = block->opaque;
5923e308f20SDaniel P. Berrange     size_t i;
5933e308f20SDaniel P. Berrange     int rv;
5943e308f20SDaniel P. Berrange 
5953e308f20SDaniel P. Berrange     *masterkey = g_new0(uint8_t, luks->header.key_bytes);
5963e308f20SDaniel P. Berrange     *masterkeylen = luks->header.key_bytes;
5973e308f20SDaniel P. Berrange 
5983e308f20SDaniel P. Berrange     for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
5993e308f20SDaniel P. Berrange         rv = qcrypto_block_luks_load_key(block,
6003e308f20SDaniel P. Berrange                                          &luks->header.key_slots[i],
6013e308f20SDaniel P. Berrange                                          password,
6023e308f20SDaniel P. Berrange                                          cipheralg,
6033e308f20SDaniel P. Berrange                                          ciphermode,
6043e308f20SDaniel P. Berrange                                          hash,
6053e308f20SDaniel P. Berrange                                          ivalg,
6063e308f20SDaniel P. Berrange                                          ivcipheralg,
6073e308f20SDaniel P. Berrange                                          ivhash,
6083e308f20SDaniel P. Berrange                                          *masterkey,
6093e308f20SDaniel P. Berrange                                          *masterkeylen,
6103e308f20SDaniel P. Berrange                                          readfunc,
6113e308f20SDaniel P. Berrange                                          opaque,
6123e308f20SDaniel P. Berrange                                          errp);
6133e308f20SDaniel P. Berrange         if (rv < 0) {
6143e308f20SDaniel P. Berrange             goto error;
6153e308f20SDaniel P. Berrange         }
6163e308f20SDaniel P. Berrange         if (rv == 1) {
6173e308f20SDaniel P. Berrange             return 0;
6183e308f20SDaniel P. Berrange         }
6193e308f20SDaniel P. Berrange     }
6203e308f20SDaniel P. Berrange 
6213e308f20SDaniel P. Berrange     error_setg(errp, "Invalid password, cannot unlock any keyslot");
6223e308f20SDaniel P. Berrange 
6233e308f20SDaniel P. Berrange  error:
6243e308f20SDaniel P. Berrange     g_free(*masterkey);
6253e308f20SDaniel P. Berrange     *masterkey = NULL;
6263e308f20SDaniel P. Berrange     *masterkeylen = 0;
6273e308f20SDaniel P. Berrange     return -1;
6283e308f20SDaniel P. Berrange }
6293e308f20SDaniel P. Berrange 
6303e308f20SDaniel P. Berrange 
6313e308f20SDaniel P. Berrange static int
6323e308f20SDaniel P. Berrange qcrypto_block_luks_open(QCryptoBlock *block,
6333e308f20SDaniel P. Berrange                         QCryptoBlockOpenOptions *options,
6343e308f20SDaniel P. Berrange                         QCryptoBlockReadFunc readfunc,
6353e308f20SDaniel P. Berrange                         void *opaque,
6363e308f20SDaniel P. Berrange                         unsigned int flags,
6373e308f20SDaniel P. Berrange                         Error **errp)
6383e308f20SDaniel P. Berrange {
6393e308f20SDaniel P. Berrange     QCryptoBlockLUKS *luks;
6403e308f20SDaniel P. Berrange     Error *local_err = NULL;
6413e308f20SDaniel P. Berrange     int ret = 0;
6423e308f20SDaniel P. Berrange     size_t i;
6433e308f20SDaniel P. Berrange     ssize_t rv;
6443e308f20SDaniel P. Berrange     uint8_t *masterkey = NULL;
6453e308f20SDaniel P. Berrange     size_t masterkeylen;
6463e308f20SDaniel P. Berrange     char *ivgen_name, *ivhash_name;
6473e308f20SDaniel P. Berrange     QCryptoCipherMode ciphermode;
6483e308f20SDaniel P. Berrange     QCryptoCipherAlgorithm cipheralg;
6493e308f20SDaniel P. Berrange     QCryptoIVGenAlgorithm ivalg;
6503e308f20SDaniel P. Berrange     QCryptoCipherAlgorithm ivcipheralg;
6513e308f20SDaniel P. Berrange     QCryptoHashAlgorithm hash;
6523e308f20SDaniel P. Berrange     QCryptoHashAlgorithm ivhash;
6533e308f20SDaniel P. Berrange     char *password = NULL;
6543e308f20SDaniel P. Berrange 
6553e308f20SDaniel P. Berrange     if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) {
6563e308f20SDaniel P. Berrange         if (!options->u.luks.key_secret) {
6573e308f20SDaniel P. Berrange             error_setg(errp, "Parameter 'key-secret' is required for cipher");
6583e308f20SDaniel P. Berrange             return -1;
6593e308f20SDaniel P. Berrange         }
6603e308f20SDaniel P. Berrange         password = qcrypto_secret_lookup_as_utf8(
6613e308f20SDaniel P. Berrange             options->u.luks.key_secret, errp);
6623e308f20SDaniel P. Berrange         if (!password) {
6633e308f20SDaniel P. Berrange             return -1;
6643e308f20SDaniel P. Berrange         }
6653e308f20SDaniel P. Berrange     }
6663e308f20SDaniel P. Berrange 
6673e308f20SDaniel P. Berrange     luks = g_new0(QCryptoBlockLUKS, 1);
6683e308f20SDaniel P. Berrange     block->opaque = luks;
6693e308f20SDaniel P. Berrange 
6703e308f20SDaniel P. Berrange     /* Read the entire LUKS header, minus the key material from
6713e308f20SDaniel P. Berrange      * the underlying device */
6723e308f20SDaniel P. Berrange     rv = readfunc(block, 0,
6733e308f20SDaniel P. Berrange                   (uint8_t *)&luks->header,
6743e308f20SDaniel P. Berrange                   sizeof(luks->header),
6753e308f20SDaniel P. Berrange                   errp,
6763e308f20SDaniel P. Berrange                   opaque);
6773e308f20SDaniel P. Berrange     if (rv < 0) {
6783e308f20SDaniel P. Berrange         ret = rv;
6793e308f20SDaniel P. Berrange         goto fail;
6803e308f20SDaniel P. Berrange     }
6813e308f20SDaniel P. Berrange 
6823e308f20SDaniel P. Berrange     /* The header is always stored in big-endian format, so
6833e308f20SDaniel P. Berrange      * convert everything to native */
6843e308f20SDaniel P. Berrange     be16_to_cpus(&luks->header.version);
6853e308f20SDaniel P. Berrange     be32_to_cpus(&luks->header.payload_offset);
6863e308f20SDaniel P. Berrange     be32_to_cpus(&luks->header.key_bytes);
6873e308f20SDaniel P. Berrange     be32_to_cpus(&luks->header.master_key_iterations);
6883e308f20SDaniel P. Berrange 
6893e308f20SDaniel P. Berrange     for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
6903e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].active);
6913e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].iterations);
6923e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].key_offset);
6933e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].stripes);
6943e308f20SDaniel P. Berrange     }
6953e308f20SDaniel P. Berrange 
6963e308f20SDaniel P. Berrange     if (memcmp(luks->header.magic, qcrypto_block_luks_magic,
6973e308f20SDaniel P. Berrange                QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) {
6983e308f20SDaniel P. Berrange         error_setg(errp, "Volume is not in LUKS format");
6993e308f20SDaniel P. Berrange         ret = -EINVAL;
7003e308f20SDaniel P. Berrange         goto fail;
7013e308f20SDaniel P. Berrange     }
7023e308f20SDaniel P. Berrange     if (luks->header.version != QCRYPTO_BLOCK_LUKS_VERSION) {
7033e308f20SDaniel P. Berrange         error_setg(errp, "LUKS version %" PRIu32 " is not supported",
7043e308f20SDaniel P. Berrange                    luks->header.version);
7053e308f20SDaniel P. Berrange         ret = -ENOTSUP;
7063e308f20SDaniel P. Berrange         goto fail;
7073e308f20SDaniel P. Berrange     }
7083e308f20SDaniel P. Berrange 
7093e308f20SDaniel P. Berrange     /*
7103e308f20SDaniel P. Berrange      * The cipher_mode header contains a string that we have
7113e308f20SDaniel P. Berrange      * to further parse, of the format
7123e308f20SDaniel P. Berrange      *
7133e308f20SDaniel P. Berrange      *    <cipher-mode>-<iv-generator>[:<iv-hash>]
7143e308f20SDaniel P. Berrange      *
7153e308f20SDaniel P. Berrange      * eg  cbc-essiv:sha256, cbc-plain64
7163e308f20SDaniel P. Berrange      */
7173e308f20SDaniel P. Berrange     ivgen_name = strchr(luks->header.cipher_mode, '-');
7183e308f20SDaniel P. Berrange     if (!ivgen_name) {
7193e308f20SDaniel P. Berrange         ret = -EINVAL;
7203e308f20SDaniel P. Berrange         error_setg(errp, "Unexpected cipher mode string format %s",
7213e308f20SDaniel P. Berrange                    luks->header.cipher_mode);
7223e308f20SDaniel P. Berrange         goto fail;
7233e308f20SDaniel P. Berrange     }
7243e308f20SDaniel P. Berrange     *ivgen_name = '\0';
7253e308f20SDaniel P. Berrange     ivgen_name++;
7263e308f20SDaniel P. Berrange 
7273e308f20SDaniel P. Berrange     ivhash_name = strchr(ivgen_name, ':');
7283e308f20SDaniel P. Berrange     if (!ivhash_name) {
7293e308f20SDaniel P. Berrange         ivhash = 0;
7303e308f20SDaniel P. Berrange     } else {
7313e308f20SDaniel P. Berrange         *ivhash_name = '\0';
7323e308f20SDaniel P. Berrange         ivhash_name++;
7333e308f20SDaniel P. Berrange 
7343e308f20SDaniel P. Berrange         ivhash = qcrypto_block_luks_hash_name_lookup(ivhash_name,
7353e308f20SDaniel P. Berrange                                                      &local_err);
7363e308f20SDaniel P. Berrange         if (local_err) {
7373e308f20SDaniel P. Berrange             ret = -ENOTSUP;
7383e308f20SDaniel P. Berrange             error_propagate(errp, local_err);
7393e308f20SDaniel P. Berrange             goto fail;
7403e308f20SDaniel P. Berrange         }
7413e308f20SDaniel P. Berrange     }
7423e308f20SDaniel P. Berrange 
7433e308f20SDaniel P. Berrange     ciphermode = qcrypto_block_luks_cipher_mode_lookup(luks->header.cipher_mode,
7443e308f20SDaniel P. Berrange                                                        &local_err);
7453e308f20SDaniel P. Berrange     if (local_err) {
7463e308f20SDaniel P. Berrange         ret = -ENOTSUP;
7473e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
7483e308f20SDaniel P. Berrange         goto fail;
7493e308f20SDaniel P. Berrange     }
7503e308f20SDaniel P. Berrange 
7513e308f20SDaniel P. Berrange     cipheralg = qcrypto_block_luks_cipher_name_lookup(luks->header.cipher_name,
7523e308f20SDaniel P. Berrange                                                       ciphermode,
7533e308f20SDaniel P. Berrange                                                       luks->header.key_bytes,
7543e308f20SDaniel P. Berrange                                                       &local_err);
7553e308f20SDaniel P. Berrange     if (local_err) {
7563e308f20SDaniel P. Berrange         ret = -ENOTSUP;
7573e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
7583e308f20SDaniel P. Berrange         goto fail;
7593e308f20SDaniel P. Berrange     }
7603e308f20SDaniel P. Berrange 
7613e308f20SDaniel P. Berrange     hash = qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec,
7623e308f20SDaniel P. Berrange                                                &local_err);
7633e308f20SDaniel P. Berrange     if (local_err) {
7643e308f20SDaniel P. Berrange         ret = -ENOTSUP;
7653e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
7663e308f20SDaniel P. Berrange         goto fail;
7673e308f20SDaniel P. Berrange     }
7683e308f20SDaniel P. Berrange 
7693e308f20SDaniel P. Berrange     ivalg = qcrypto_block_luks_ivgen_name_lookup(ivgen_name,
7703e308f20SDaniel P. Berrange                                                  &local_err);
7713e308f20SDaniel P. Berrange     if (local_err) {
7723e308f20SDaniel P. Berrange         ret = -ENOTSUP;
7733e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
7743e308f20SDaniel P. Berrange         goto fail;
7753e308f20SDaniel P. Berrange     }
7763e308f20SDaniel P. Berrange 
7773e308f20SDaniel P. Berrange     if (ivalg == QCRYPTO_IVGEN_ALG_ESSIV) {
7783e308f20SDaniel P. Berrange         ivcipheralg = qcrypto_block_luks_essiv_cipher(cipheralg,
7793e308f20SDaniel P. Berrange                                                       ivhash,
7803e308f20SDaniel P. Berrange                                                       &local_err);
7813e308f20SDaniel P. Berrange         if (local_err) {
7823e308f20SDaniel P. Berrange             ret = -ENOTSUP;
7833e308f20SDaniel P. Berrange             error_propagate(errp, local_err);
7843e308f20SDaniel P. Berrange             goto fail;
7853e308f20SDaniel P. Berrange         }
7863e308f20SDaniel P. Berrange     } else {
7873e308f20SDaniel P. Berrange         ivcipheralg = cipheralg;
7883e308f20SDaniel P. Berrange     }
7893e308f20SDaniel P. Berrange 
7903e308f20SDaniel P. Berrange     if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) {
7913e308f20SDaniel P. Berrange         /* Try to find which key slot our password is valid for
7923e308f20SDaniel P. Berrange          * and unlock the master key from that slot.
7933e308f20SDaniel P. Berrange          */
7943e308f20SDaniel P. Berrange         if (qcrypto_block_luks_find_key(block,
7953e308f20SDaniel P. Berrange                                         password,
7963e308f20SDaniel P. Berrange                                         cipheralg, ciphermode,
7973e308f20SDaniel P. Berrange                                         hash,
7983e308f20SDaniel P. Berrange                                         ivalg,
7993e308f20SDaniel P. Berrange                                         ivcipheralg,
8003e308f20SDaniel P. Berrange                                         ivhash,
8013e308f20SDaniel P. Berrange                                         &masterkey, &masterkeylen,
8023e308f20SDaniel P. Berrange                                         readfunc, opaque,
8033e308f20SDaniel P. Berrange                                         errp) < 0) {
8043e308f20SDaniel P. Berrange             ret = -EACCES;
8053e308f20SDaniel P. Berrange             goto fail;
8063e308f20SDaniel P. Berrange         }
8073e308f20SDaniel P. Berrange 
8083e308f20SDaniel P. Berrange         /* We have a valid master key now, so can setup the
8093e308f20SDaniel P. Berrange          * block device payload decryption objects
8103e308f20SDaniel P. Berrange          */
8113e308f20SDaniel P. Berrange         block->kdfhash = hash;
8123e308f20SDaniel P. Berrange         block->niv = qcrypto_cipher_get_iv_len(cipheralg,
8133e308f20SDaniel P. Berrange                                                ciphermode);
8143e308f20SDaniel P. Berrange         block->ivgen = qcrypto_ivgen_new(ivalg,
8153e308f20SDaniel P. Berrange                                          ivcipheralg,
8163e308f20SDaniel P. Berrange                                          ivhash,
8173e308f20SDaniel P. Berrange                                          masterkey, masterkeylen,
8183e308f20SDaniel P. Berrange                                          errp);
8193e308f20SDaniel P. Berrange         if (!block->ivgen) {
8203e308f20SDaniel P. Berrange             ret = -ENOTSUP;
8213e308f20SDaniel P. Berrange             goto fail;
8223e308f20SDaniel P. Berrange         }
8233e308f20SDaniel P. Berrange 
8243e308f20SDaniel P. Berrange         block->cipher = qcrypto_cipher_new(cipheralg,
8253e308f20SDaniel P. Berrange                                            ciphermode,
8263e308f20SDaniel P. Berrange                                            masterkey, masterkeylen,
8273e308f20SDaniel P. Berrange                                            errp);
8283e308f20SDaniel P. Berrange         if (!block->cipher) {
8293e308f20SDaniel P. Berrange             ret = -ENOTSUP;
8303e308f20SDaniel P. Berrange             goto fail;
8313e308f20SDaniel P. Berrange         }
8323e308f20SDaniel P. Berrange     }
8333e308f20SDaniel P. Berrange 
8343e308f20SDaniel P. Berrange     block->payload_offset = luks->header.payload_offset *
8353e308f20SDaniel P. Berrange         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
8363e308f20SDaniel P. Berrange 
8373e308f20SDaniel P. Berrange     g_free(masterkey);
8383e308f20SDaniel P. Berrange     g_free(password);
8393e308f20SDaniel P. Berrange 
8403e308f20SDaniel P. Berrange     return 0;
8413e308f20SDaniel P. Berrange 
8423e308f20SDaniel P. Berrange  fail:
8433e308f20SDaniel P. Berrange     g_free(masterkey);
8443e308f20SDaniel P. Berrange     qcrypto_cipher_free(block->cipher);
8453e308f20SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
8463e308f20SDaniel P. Berrange     g_free(luks);
8473e308f20SDaniel P. Berrange     g_free(password);
8483e308f20SDaniel P. Berrange     return ret;
8493e308f20SDaniel P. Berrange }
8503e308f20SDaniel P. Berrange 
8513e308f20SDaniel P. Berrange 
8523e308f20SDaniel P. Berrange static int
8533e308f20SDaniel P. Berrange qcrypto_block_luks_uuid_gen(uint8_t *uuidstr, Error **errp)
8543e308f20SDaniel P. Berrange {
8553e308f20SDaniel P. Berrange #ifdef CONFIG_UUID
8563e308f20SDaniel P. Berrange     uuid_t uuid;
8573e308f20SDaniel P. Berrange     uuid_generate(uuid);
8583e308f20SDaniel P. Berrange     uuid_unparse(uuid, (char *)uuidstr);
8593e308f20SDaniel P. Berrange     return 0;
8603e308f20SDaniel P. Berrange #else
8613e308f20SDaniel P. Berrange     error_setg(errp, "Unable to generate uuids on this platform");
8623e308f20SDaniel P. Berrange     return -1;
8633e308f20SDaniel P. Berrange #endif
8643e308f20SDaniel P. Berrange }
8653e308f20SDaniel P. Berrange 
8663e308f20SDaniel P. Berrange static int
8673e308f20SDaniel P. Berrange qcrypto_block_luks_create(QCryptoBlock *block,
8683e308f20SDaniel P. Berrange                           QCryptoBlockCreateOptions *options,
8693e308f20SDaniel P. Berrange                           QCryptoBlockInitFunc initfunc,
8703e308f20SDaniel P. Berrange                           QCryptoBlockWriteFunc writefunc,
8713e308f20SDaniel P. Berrange                           void *opaque,
8723e308f20SDaniel P. Berrange                           Error **errp)
8733e308f20SDaniel P. Berrange {
8743e308f20SDaniel P. Berrange     QCryptoBlockLUKS *luks;
8753e308f20SDaniel P. Berrange     QCryptoBlockCreateOptionsLUKS luks_opts;
8763e308f20SDaniel P. Berrange     Error *local_err = NULL;
8773e308f20SDaniel P. Berrange     uint8_t *masterkey = NULL;
8783e308f20SDaniel P. Berrange     uint8_t *slotkey = NULL;
8793e308f20SDaniel P. Berrange     uint8_t *splitkey = NULL;
8803e308f20SDaniel P. Berrange     size_t splitkeylen = 0;
8813e308f20SDaniel P. Berrange     size_t i;
8823e308f20SDaniel P. Berrange     QCryptoCipher *cipher = NULL;
8833e308f20SDaniel P. Berrange     QCryptoIVGen *ivgen = NULL;
8843e308f20SDaniel P. Berrange     char *password;
8853e308f20SDaniel P. Berrange     const char *cipher_alg;
8863e308f20SDaniel P. Berrange     const char *cipher_mode;
8873e308f20SDaniel P. Berrange     const char *ivgen_alg;
8883e308f20SDaniel P. Berrange     const char *ivgen_hash_alg = NULL;
8893e308f20SDaniel P. Berrange     const char *hash_alg;
8903e308f20SDaniel P. Berrange     char *cipher_mode_spec = NULL;
8913e308f20SDaniel P. Berrange     QCryptoCipherAlgorithm ivcipheralg = 0;
8923e308f20SDaniel P. Berrange 
8933e308f20SDaniel P. Berrange     memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));
8943e308f20SDaniel P. Berrange     if (!luks_opts.has_cipher_alg) {
8953e308f20SDaniel P. Berrange         luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
8963e308f20SDaniel P. Berrange     }
8973e308f20SDaniel P. Berrange     if (!luks_opts.has_cipher_mode) {
8983e308f20SDaniel P. Berrange         luks_opts.cipher_mode = QCRYPTO_CIPHER_MODE_XTS;
8993e308f20SDaniel P. Berrange     }
9003e308f20SDaniel P. Berrange     if (!luks_opts.has_ivgen_alg) {
9013e308f20SDaniel P. Berrange         luks_opts.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64;
9023e308f20SDaniel P. Berrange     }
9033e308f20SDaniel P. Berrange     if (!luks_opts.has_hash_alg) {
9043e308f20SDaniel P. Berrange         luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256;
9053e308f20SDaniel P. Berrange     }
9063e308f20SDaniel P. Berrange 
9073e308f20SDaniel P. Berrange     if (!options->u.luks.key_secret) {
9083e308f20SDaniel P. Berrange         error_setg(errp, "Parameter 'key-secret' is required for cipher");
9093e308f20SDaniel P. Berrange         return -1;
9103e308f20SDaniel P. Berrange     }
9113e308f20SDaniel P. Berrange     password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp);
9123e308f20SDaniel P. Berrange     if (!password) {
9133e308f20SDaniel P. Berrange         return -1;
9143e308f20SDaniel P. Berrange     }
9153e308f20SDaniel P. Berrange 
9163e308f20SDaniel P. Berrange     luks = g_new0(QCryptoBlockLUKS, 1);
9173e308f20SDaniel P. Berrange     block->opaque = luks;
9183e308f20SDaniel P. Berrange 
9193e308f20SDaniel P. Berrange     memcpy(luks->header.magic, qcrypto_block_luks_magic,
9203e308f20SDaniel P. Berrange            QCRYPTO_BLOCK_LUKS_MAGIC_LEN);
9213e308f20SDaniel P. Berrange 
9223e308f20SDaniel P. Berrange     /* We populate the header in native endianness initially and
9233e308f20SDaniel P. Berrange      * then convert everything to big endian just before writing
9243e308f20SDaniel P. Berrange      * it out to disk
9253e308f20SDaniel P. Berrange      */
9263e308f20SDaniel P. Berrange     luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION;
9273e308f20SDaniel P. Berrange     if (qcrypto_block_luks_uuid_gen(luks->header.uuid,
9283e308f20SDaniel P. Berrange                                     errp) < 0) {
9293e308f20SDaniel P. Berrange         goto error;
9303e308f20SDaniel P. Berrange     }
9313e308f20SDaniel P. Berrange 
9323e308f20SDaniel P. Berrange     cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg,
9333e308f20SDaniel P. Berrange                                                       errp);
9343e308f20SDaniel P. Berrange     if (!cipher_alg) {
9353e308f20SDaniel P. Berrange         goto error;
9363e308f20SDaniel P. Berrange     }
9373e308f20SDaniel P. Berrange 
9383e308f20SDaniel P. Berrange     cipher_mode = QCryptoCipherMode_lookup[luks_opts.cipher_mode];
9393e308f20SDaniel P. Berrange     ivgen_alg = QCryptoIVGenAlgorithm_lookup[luks_opts.ivgen_alg];
9403e308f20SDaniel P. Berrange     if (luks_opts.has_ivgen_hash_alg) {
9413e308f20SDaniel P. Berrange         ivgen_hash_alg = QCryptoHashAlgorithm_lookup[luks_opts.ivgen_hash_alg];
9423e308f20SDaniel P. Berrange         cipher_mode_spec = g_strdup_printf("%s-%s:%s", cipher_mode, ivgen_alg,
9433e308f20SDaniel P. Berrange                                            ivgen_hash_alg);
9443e308f20SDaniel P. Berrange     } else {
9453e308f20SDaniel P. Berrange         cipher_mode_spec = g_strdup_printf("%s-%s", cipher_mode, ivgen_alg);
9463e308f20SDaniel P. Berrange     }
9473e308f20SDaniel P. Berrange     hash_alg = QCryptoHashAlgorithm_lookup[luks_opts.hash_alg];
9483e308f20SDaniel P. Berrange 
9493e308f20SDaniel P. Berrange 
9503e308f20SDaniel P. Berrange     if (strlen(cipher_alg) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) {
9513e308f20SDaniel P. Berrange         error_setg(errp, "Cipher name '%s' is too long for LUKS header",
9523e308f20SDaniel P. Berrange                    cipher_alg);
9533e308f20SDaniel P. Berrange         goto error;
9543e308f20SDaniel P. Berrange     }
9553e308f20SDaniel P. Berrange     if (strlen(cipher_mode_spec) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) {
9563e308f20SDaniel P. Berrange         error_setg(errp, "Cipher mode '%s' is too long for LUKS header",
9573e308f20SDaniel P. Berrange                    cipher_mode_spec);
9583e308f20SDaniel P. Berrange         goto error;
9593e308f20SDaniel P. Berrange     }
9603e308f20SDaniel P. Berrange     if (strlen(hash_alg) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) {
9613e308f20SDaniel P. Berrange         error_setg(errp, "Hash name '%s' is too long for LUKS header",
9623e308f20SDaniel P. Berrange                    hash_alg);
9633e308f20SDaniel P. Berrange         goto error;
9643e308f20SDaniel P. Berrange     }
9653e308f20SDaniel P. Berrange 
9663e308f20SDaniel P. Berrange     if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
9673e308f20SDaniel P. Berrange         ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg,
9683e308f20SDaniel P. Berrange                                                       luks_opts.ivgen_hash_alg,
9693e308f20SDaniel P. Berrange                                                       &local_err);
9703e308f20SDaniel P. Berrange         if (local_err) {
9713e308f20SDaniel P. Berrange             error_propagate(errp, local_err);
9723e308f20SDaniel P. Berrange             goto error;
9733e308f20SDaniel P. Berrange         }
9743e308f20SDaniel P. Berrange     } else {
9753e308f20SDaniel P. Berrange         ivcipheralg = luks_opts.cipher_alg;
9763e308f20SDaniel P. Berrange     }
9773e308f20SDaniel P. Berrange 
9783e308f20SDaniel P. Berrange     strcpy(luks->header.cipher_name, cipher_alg);
9793e308f20SDaniel P. Berrange     strcpy(luks->header.cipher_mode, cipher_mode_spec);
9803e308f20SDaniel P. Berrange     strcpy(luks->header.hash_spec, hash_alg);
9813e308f20SDaniel P. Berrange 
9823e308f20SDaniel P. Berrange     luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.cipher_alg);
9833e308f20SDaniel P. Berrange     if (luks_opts.cipher_mode == QCRYPTO_CIPHER_MODE_XTS) {
9843e308f20SDaniel P. Berrange         luks->header.key_bytes *= 2;
9853e308f20SDaniel P. Berrange     }
9863e308f20SDaniel P. Berrange 
9873e308f20SDaniel P. Berrange     /* Generate the salt used for hashing the master key
9883e308f20SDaniel P. Berrange      * with PBKDF later
9893e308f20SDaniel P. Berrange      */
9903e308f20SDaniel P. Berrange     if (qcrypto_random_bytes(luks->header.master_key_salt,
9913e308f20SDaniel P. Berrange                              QCRYPTO_BLOCK_LUKS_SALT_LEN,
9923e308f20SDaniel P. Berrange                              errp) < 0) {
9933e308f20SDaniel P. Berrange         goto error;
9943e308f20SDaniel P. Berrange     }
9953e308f20SDaniel P. Berrange 
9963e308f20SDaniel P. Berrange     /* Generate random master key */
9973e308f20SDaniel P. Berrange     masterkey = g_new0(uint8_t, luks->header.key_bytes);
9983e308f20SDaniel P. Berrange     if (qcrypto_random_bytes(masterkey,
9993e308f20SDaniel P. Berrange                              luks->header.key_bytes, errp) < 0) {
10003e308f20SDaniel P. Berrange         goto error;
10013e308f20SDaniel P. Berrange     }
10023e308f20SDaniel P. Berrange 
10033e308f20SDaniel P. Berrange 
10043e308f20SDaniel P. Berrange     /* Setup the block device payload encryption objects */
10053e308f20SDaniel P. Berrange     block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg,
10063e308f20SDaniel P. Berrange                                        luks_opts.cipher_mode,
10073e308f20SDaniel P. Berrange                                        masterkey, luks->header.key_bytes,
10083e308f20SDaniel P. Berrange                                        errp);
10093e308f20SDaniel P. Berrange     if (!block->cipher) {
10103e308f20SDaniel P. Berrange         goto error;
10113e308f20SDaniel P. Berrange     }
10123e308f20SDaniel P. Berrange 
10133e308f20SDaniel P. Berrange     block->kdfhash = luks_opts.hash_alg;
10143e308f20SDaniel P. Berrange     block->niv = qcrypto_cipher_get_iv_len(luks_opts.cipher_alg,
10153e308f20SDaniel P. Berrange                                            luks_opts.cipher_mode);
10163e308f20SDaniel P. Berrange     block->ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,
10173e308f20SDaniel P. Berrange                                      ivcipheralg,
10183e308f20SDaniel P. Berrange                                      luks_opts.ivgen_hash_alg,
10193e308f20SDaniel P. Berrange                                      masterkey, luks->header.key_bytes,
10203e308f20SDaniel P. Berrange                                      errp);
10213e308f20SDaniel P. Berrange 
10223e308f20SDaniel P. Berrange     if (!block->ivgen) {
10233e308f20SDaniel P. Berrange         goto error;
10243e308f20SDaniel P. Berrange     }
10253e308f20SDaniel P. Berrange 
10263e308f20SDaniel P. Berrange 
10273e308f20SDaniel P. Berrange     /* Determine how many iterations we need to hash the master
10283e308f20SDaniel P. Berrange      * key, in order to have 1 second of compute time used
10293e308f20SDaniel P. Berrange      */
10303e308f20SDaniel P. Berrange     luks->header.master_key_iterations =
10313e308f20SDaniel P. Berrange         qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
10323e308f20SDaniel P. Berrange                                    masterkey, luks->header.key_bytes,
10333e308f20SDaniel P. Berrange                                    luks->header.master_key_salt,
10343e308f20SDaniel P. Berrange                                    QCRYPTO_BLOCK_LUKS_SALT_LEN,
10353e308f20SDaniel P. Berrange                                    &local_err);
10363e308f20SDaniel P. Berrange     if (local_err) {
10373e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
10383e308f20SDaniel P. Berrange         goto error;
10393e308f20SDaniel P. Berrange     }
10403e308f20SDaniel P. Berrange 
10413e308f20SDaniel P. Berrange     /* Why /= 8 ?  That matches cryptsetup, but there's no
10423e308f20SDaniel P. Berrange      * explanation why they chose /= 8... Probably so that
10433e308f20SDaniel P. Berrange      * if all 8 keyslots are active we only spend 1 second
10443e308f20SDaniel P. Berrange      * in total time to check all keys */
10453e308f20SDaniel P. Berrange     luks->header.master_key_iterations /= 8;
10463e308f20SDaniel P. Berrange     luks->header.master_key_iterations = MAX(
10473e308f20SDaniel P. Berrange         luks->header.master_key_iterations,
10483e308f20SDaniel P. Berrange         QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
10493e308f20SDaniel P. Berrange 
10503e308f20SDaniel P. Berrange 
10513e308f20SDaniel P. Berrange     /* Hash the master key, saving the result in the LUKS
10523e308f20SDaniel P. Berrange      * header. This hash is used when opening the encrypted
10533e308f20SDaniel P. Berrange      * device to verify that the user password unlocked a
10543e308f20SDaniel P. Berrange      * valid master key
10553e308f20SDaniel P. Berrange      */
10563e308f20SDaniel P. Berrange     if (qcrypto_pbkdf2(luks_opts.hash_alg,
10573e308f20SDaniel P. Berrange                        masterkey, luks->header.key_bytes,
10583e308f20SDaniel P. Berrange                        luks->header.master_key_salt,
10593e308f20SDaniel P. Berrange                        QCRYPTO_BLOCK_LUKS_SALT_LEN,
10603e308f20SDaniel P. Berrange                        luks->header.master_key_iterations,
10613e308f20SDaniel P. Berrange                        luks->header.master_key_digest,
10623e308f20SDaniel P. Berrange                        QCRYPTO_BLOCK_LUKS_DIGEST_LEN,
10633e308f20SDaniel P. Berrange                        errp) < 0) {
10643e308f20SDaniel P. Berrange         goto error;
10653e308f20SDaniel P. Berrange     }
10663e308f20SDaniel P. Berrange 
10673e308f20SDaniel P. Berrange 
10683e308f20SDaniel P. Berrange     /* Although LUKS has multiple key slots, we're just going
10693e308f20SDaniel P. Berrange      * to use the first key slot */
10703e308f20SDaniel P. Berrange     splitkeylen = luks->header.key_bytes * QCRYPTO_BLOCK_LUKS_STRIPES;
10713e308f20SDaniel P. Berrange     for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
10723e308f20SDaniel P. Berrange         luks->header.key_slots[i].active = i == 0 ?
10733e308f20SDaniel P. Berrange             QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED :
10743e308f20SDaniel P. Berrange             QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
10753e308f20SDaniel P. Berrange         luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;
10763e308f20SDaniel P. Berrange 
10773e308f20SDaniel P. Berrange         /* This calculation doesn't match that shown in the spec,
10783e308f20SDaniel P. Berrange          * but instead follows the cryptsetup implementation.
10793e308f20SDaniel P. Berrange          */
10803e308f20SDaniel P. Berrange         luks->header.key_slots[i].key_offset =
10813e308f20SDaniel P. Berrange             (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
10823e308f20SDaniel P. Berrange              QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +
10833e308f20SDaniel P. Berrange             (ROUND_UP(((splitkeylen + (QCRYPTO_BLOCK_LUKS_SECTOR_SIZE - 1)) /
10843e308f20SDaniel P. Berrange                        QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),
10853e308f20SDaniel P. Berrange                       (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
10863e308f20SDaniel P. Berrange                        QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i);
10873e308f20SDaniel P. Berrange     }
10883e308f20SDaniel P. Berrange 
10893e308f20SDaniel P. Berrange     if (qcrypto_random_bytes(luks->header.key_slots[0].salt,
10903e308f20SDaniel P. Berrange                              QCRYPTO_BLOCK_LUKS_SALT_LEN,
10913e308f20SDaniel P. Berrange                              errp) < 0) {
10923e308f20SDaniel P. Berrange         goto error;
10933e308f20SDaniel P. Berrange     }
10943e308f20SDaniel P. Berrange 
10953e308f20SDaniel P. Berrange     /* Again we determine how many iterations are required to
10963e308f20SDaniel P. Berrange      * hash the user password while consuming 1 second of compute
10973e308f20SDaniel P. Berrange      * time */
10983e308f20SDaniel P. Berrange     luks->header.key_slots[0].iterations =
10993e308f20SDaniel P. Berrange         qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
11003e308f20SDaniel P. Berrange                                    (uint8_t *)password, strlen(password),
11013e308f20SDaniel P. Berrange                                    luks->header.key_slots[0].salt,
11023e308f20SDaniel P. Berrange                                    QCRYPTO_BLOCK_LUKS_SALT_LEN,
11033e308f20SDaniel P. Berrange                                    &local_err);
11043e308f20SDaniel P. Berrange     if (local_err) {
11053e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
11063e308f20SDaniel P. Berrange         goto error;
11073e308f20SDaniel P. Berrange     }
11083e308f20SDaniel P. Berrange     /* Why /= 2 ?  That matches cryptsetup, but there's no
11093e308f20SDaniel P. Berrange      * explanation why they chose /= 2... */
11103e308f20SDaniel P. Berrange     luks->header.key_slots[0].iterations /= 2;
11113e308f20SDaniel P. Berrange     luks->header.key_slots[0].iterations = MAX(
11123e308f20SDaniel P. Berrange         luks->header.key_slots[0].iterations,
11133e308f20SDaniel P. Berrange         QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
11143e308f20SDaniel P. Berrange 
11153e308f20SDaniel P. Berrange 
11163e308f20SDaniel P. Berrange     /* Generate a key that we'll use to encrypt the master
11173e308f20SDaniel P. Berrange      * key, from the user's password
11183e308f20SDaniel P. Berrange      */
11193e308f20SDaniel P. Berrange     slotkey = g_new0(uint8_t, luks->header.key_bytes);
11203e308f20SDaniel P. Berrange     if (qcrypto_pbkdf2(luks_opts.hash_alg,
11213e308f20SDaniel P. Berrange                        (uint8_t *)password, strlen(password),
11223e308f20SDaniel P. Berrange                        luks->header.key_slots[0].salt,
11233e308f20SDaniel P. Berrange                        QCRYPTO_BLOCK_LUKS_SALT_LEN,
11243e308f20SDaniel P. Berrange                        luks->header.key_slots[0].iterations,
11253e308f20SDaniel P. Berrange                        slotkey, luks->header.key_bytes,
11263e308f20SDaniel P. Berrange                        errp) < 0) {
11273e308f20SDaniel P. Berrange         goto error;
11283e308f20SDaniel P. Berrange     }
11293e308f20SDaniel P. Berrange 
11303e308f20SDaniel P. Berrange 
11313e308f20SDaniel P. Berrange     /* Setup the encryption objects needed to encrypt the
11323e308f20SDaniel P. Berrange      * master key material
11333e308f20SDaniel P. Berrange      */
11343e308f20SDaniel P. Berrange     cipher = qcrypto_cipher_new(luks_opts.cipher_alg,
11353e308f20SDaniel P. Berrange                                 luks_opts.cipher_mode,
11363e308f20SDaniel P. Berrange                                 slotkey, luks->header.key_bytes,
11373e308f20SDaniel P. Berrange                                 errp);
11383e308f20SDaniel P. Berrange     if (!cipher) {
11393e308f20SDaniel P. Berrange         goto error;
11403e308f20SDaniel P. Berrange     }
11413e308f20SDaniel P. Berrange 
11423e308f20SDaniel P. Berrange     ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,
11433e308f20SDaniel P. Berrange                               ivcipheralg,
11443e308f20SDaniel P. Berrange                               luks_opts.ivgen_hash_alg,
11453e308f20SDaniel P. Berrange                               slotkey, luks->header.key_bytes,
11463e308f20SDaniel P. Berrange                               errp);
11473e308f20SDaniel P. Berrange     if (!ivgen) {
11483e308f20SDaniel P. Berrange         goto error;
11493e308f20SDaniel P. Berrange     }
11503e308f20SDaniel P. Berrange 
11513e308f20SDaniel P. Berrange     /* Before storing the master key, we need to vastly
11523e308f20SDaniel P. Berrange      * increase its size, as protection against forensic
11533e308f20SDaniel P. Berrange      * disk data recovery */
11543e308f20SDaniel P. Berrange     splitkey = g_new0(uint8_t, splitkeylen);
11553e308f20SDaniel P. Berrange 
11563e308f20SDaniel P. Berrange     if (qcrypto_afsplit_encode(luks_opts.hash_alg,
11573e308f20SDaniel P. Berrange                                luks->header.key_bytes,
11583e308f20SDaniel P. Berrange                                luks->header.key_slots[0].stripes,
11593e308f20SDaniel P. Berrange                                masterkey,
11603e308f20SDaniel P. Berrange                                splitkey,
11613e308f20SDaniel P. Berrange                                errp) < 0) {
11623e308f20SDaniel P. Berrange         goto error;
11633e308f20SDaniel P. Berrange     }
11643e308f20SDaniel P. Berrange 
11653e308f20SDaniel P. Berrange     /* Now we encrypt the split master key with the key generated
11663e308f20SDaniel P. Berrange      * from the user's password, before storing it */
11673e308f20SDaniel P. Berrange     if (qcrypto_block_encrypt_helper(cipher, block->niv, ivgen,
11683e308f20SDaniel P. Berrange                                      QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
11693e308f20SDaniel P. Berrange                                      0,
11703e308f20SDaniel P. Berrange                                      splitkey,
11713e308f20SDaniel P. Berrange                                      splitkeylen,
11723e308f20SDaniel P. Berrange                                      errp) < 0) {
11733e308f20SDaniel P. Berrange         goto error;
11743e308f20SDaniel P. Berrange     }
11753e308f20SDaniel P. Berrange 
11763e308f20SDaniel P. Berrange 
11773e308f20SDaniel P. Berrange     /* The total size of the LUKS headers is the partition header + key
11783e308f20SDaniel P. Berrange      * slot headers, rounded up to the nearest sector, combined with
11793e308f20SDaniel P. Berrange      * the size of each master key material region, also rounded up
11803e308f20SDaniel P. Berrange      * to the nearest sector */
11813e308f20SDaniel P. Berrange     luks->header.payload_offset =
11823e308f20SDaniel P. Berrange         (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
11833e308f20SDaniel P. Berrange          QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +
11843e308f20SDaniel P. Berrange         (ROUND_UP(((splitkeylen + (QCRYPTO_BLOCK_LUKS_SECTOR_SIZE - 1)) /
11853e308f20SDaniel P. Berrange                    QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),
11863e308f20SDaniel P. Berrange                   (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
11873e308f20SDaniel P. Berrange                    QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
11883e308f20SDaniel P. Berrange          QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
11893e308f20SDaniel P. Berrange 
11903e308f20SDaniel P. Berrange     block->payload_offset = luks->header.payload_offset *
11913e308f20SDaniel P. Berrange         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
11923e308f20SDaniel P. Berrange 
11933e308f20SDaniel P. Berrange     /* Reserve header space to match payload offset */
11943e308f20SDaniel P. Berrange     initfunc(block, block->payload_offset, &local_err, opaque);
11953e308f20SDaniel P. Berrange     if (local_err) {
11963e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
11973e308f20SDaniel P. Berrange         goto error;
11983e308f20SDaniel P. Berrange     }
11993e308f20SDaniel P. Berrange 
12003e308f20SDaniel P. Berrange     /* Everything on disk uses Big Endian, so flip header fields
12013e308f20SDaniel P. Berrange      * before writing them */
12023e308f20SDaniel P. Berrange     cpu_to_be16s(&luks->header.version);
12033e308f20SDaniel P. Berrange     cpu_to_be32s(&luks->header.payload_offset);
12043e308f20SDaniel P. Berrange     cpu_to_be32s(&luks->header.key_bytes);
12053e308f20SDaniel P. Berrange     cpu_to_be32s(&luks->header.master_key_iterations);
12063e308f20SDaniel P. Berrange 
12073e308f20SDaniel P. Berrange     for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
12083e308f20SDaniel P. Berrange         cpu_to_be32s(&luks->header.key_slots[i].active);
12093e308f20SDaniel P. Berrange         cpu_to_be32s(&luks->header.key_slots[i].iterations);
12103e308f20SDaniel P. Berrange         cpu_to_be32s(&luks->header.key_slots[i].key_offset);
12113e308f20SDaniel P. Berrange         cpu_to_be32s(&luks->header.key_slots[i].stripes);
12123e308f20SDaniel P. Berrange     }
12133e308f20SDaniel P. Berrange 
12143e308f20SDaniel P. Berrange 
12153e308f20SDaniel P. Berrange     /* Write out the partition header and key slot headers */
12163e308f20SDaniel P. Berrange     writefunc(block, 0,
12173e308f20SDaniel P. Berrange               (const uint8_t *)&luks->header,
12183e308f20SDaniel P. Berrange               sizeof(luks->header),
12193e308f20SDaniel P. Berrange               &local_err,
12203e308f20SDaniel P. Berrange               opaque);
12213e308f20SDaniel P. Berrange 
12223e308f20SDaniel P. Berrange     /* Delay checking local_err until we've byte-swapped */
12233e308f20SDaniel P. Berrange 
12243e308f20SDaniel P. Berrange     /* Byte swap the header back to native, in case we need
12253e308f20SDaniel P. Berrange      * to read it again later */
12263e308f20SDaniel P. Berrange     be16_to_cpus(&luks->header.version);
12273e308f20SDaniel P. Berrange     be32_to_cpus(&luks->header.payload_offset);
12283e308f20SDaniel P. Berrange     be32_to_cpus(&luks->header.key_bytes);
12293e308f20SDaniel P. Berrange     be32_to_cpus(&luks->header.master_key_iterations);
12303e308f20SDaniel P. Berrange 
12313e308f20SDaniel P. Berrange     for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
12323e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].active);
12333e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].iterations);
12343e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].key_offset);
12353e308f20SDaniel P. Berrange         be32_to_cpus(&luks->header.key_slots[i].stripes);
12363e308f20SDaniel P. Berrange     }
12373e308f20SDaniel P. Berrange 
12383e308f20SDaniel P. Berrange     if (local_err) {
12393e308f20SDaniel P. Berrange         error_propagate(errp, local_err);
12403e308f20SDaniel P. Berrange         goto error;
12413e308f20SDaniel P. Berrange     }
12423e308f20SDaniel P. Berrange 
12433e308f20SDaniel P. Berrange     /* Write out the master key material, starting at the
12443e308f20SDaniel P. Berrange      * sector immediately following the partition header. */
12453e308f20SDaniel P. Berrange     if (writefunc(block,
12463e308f20SDaniel P. Berrange                   luks->header.key_slots[0].key_offset *
12473e308f20SDaniel P. Berrange                   QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
12483e308f20SDaniel P. Berrange                   splitkey, splitkeylen,
12493e308f20SDaniel P. Berrange                   errp,
12503e308f20SDaniel P. Berrange                   opaque) != splitkeylen) {
12513e308f20SDaniel P. Berrange         goto error;
12523e308f20SDaniel P. Berrange     }
12533e308f20SDaniel P. Berrange 
12543e308f20SDaniel P. Berrange     memset(masterkey, 0, luks->header.key_bytes);
12553e308f20SDaniel P. Berrange     g_free(masterkey);
12563e308f20SDaniel P. Berrange     memset(slotkey, 0, luks->header.key_bytes);
12573e308f20SDaniel P. Berrange     g_free(slotkey);
12583e308f20SDaniel P. Berrange     g_free(splitkey);
12593e308f20SDaniel P. Berrange     g_free(password);
12603e308f20SDaniel P. Berrange     g_free(cipher_mode_spec);
12613e308f20SDaniel P. Berrange 
12623e308f20SDaniel P. Berrange     qcrypto_ivgen_free(ivgen);
12633e308f20SDaniel P. Berrange     qcrypto_cipher_free(cipher);
12643e308f20SDaniel P. Berrange 
12653e308f20SDaniel P. Berrange     return 0;
12663e308f20SDaniel P. Berrange 
12673e308f20SDaniel P. Berrange  error:
12683e308f20SDaniel P. Berrange     if (masterkey) {
12693e308f20SDaniel P. Berrange         memset(masterkey, 0, luks->header.key_bytes);
12703e308f20SDaniel P. Berrange     }
12713e308f20SDaniel P. Berrange     g_free(masterkey);
12723e308f20SDaniel P. Berrange     if (slotkey) {
12733e308f20SDaniel P. Berrange         memset(slotkey, 0, luks->header.key_bytes);
12743e308f20SDaniel P. Berrange     }
12753e308f20SDaniel P. Berrange     g_free(slotkey);
12763e308f20SDaniel P. Berrange     g_free(splitkey);
12773e308f20SDaniel P. Berrange     g_free(password);
12783e308f20SDaniel P. Berrange     g_free(cipher_mode_spec);
12793e308f20SDaniel P. Berrange 
12803e308f20SDaniel P. Berrange     qcrypto_ivgen_free(ivgen);
12813e308f20SDaniel P. Berrange     qcrypto_cipher_free(cipher);
12823e308f20SDaniel P. Berrange 
12833e308f20SDaniel P. Berrange     g_free(luks);
12843e308f20SDaniel P. Berrange     return -1;
12853e308f20SDaniel P. Berrange }
12863e308f20SDaniel P. Berrange 
12873e308f20SDaniel P. Berrange 
12883e308f20SDaniel P. Berrange static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
12893e308f20SDaniel P. Berrange {
12903e308f20SDaniel P. Berrange     g_free(block->opaque);
12913e308f20SDaniel P. Berrange }
12923e308f20SDaniel P. Berrange 
12933e308f20SDaniel P. Berrange 
12943e308f20SDaniel P. Berrange static int
12953e308f20SDaniel P. Berrange qcrypto_block_luks_decrypt(QCryptoBlock *block,
12963e308f20SDaniel P. Berrange                            uint64_t startsector,
12973e308f20SDaniel P. Berrange                            uint8_t *buf,
12983e308f20SDaniel P. Berrange                            size_t len,
12993e308f20SDaniel P. Berrange                            Error **errp)
13003e308f20SDaniel P. Berrange {
13013e308f20SDaniel P. Berrange     return qcrypto_block_decrypt_helper(block->cipher,
13023e308f20SDaniel P. Berrange                                         block->niv, block->ivgen,
13033e308f20SDaniel P. Berrange                                         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
13043e308f20SDaniel P. Berrange                                         startsector, buf, len, errp);
13053e308f20SDaniel P. Berrange }
13063e308f20SDaniel P. Berrange 
13073e308f20SDaniel P. Berrange 
13083e308f20SDaniel P. Berrange static int
13093e308f20SDaniel P. Berrange qcrypto_block_luks_encrypt(QCryptoBlock *block,
13103e308f20SDaniel P. Berrange                            uint64_t startsector,
13113e308f20SDaniel P. Berrange                            uint8_t *buf,
13123e308f20SDaniel P. Berrange                            size_t len,
13133e308f20SDaniel P. Berrange                            Error **errp)
13143e308f20SDaniel P. Berrange {
13153e308f20SDaniel P. Berrange     return qcrypto_block_encrypt_helper(block->cipher,
13163e308f20SDaniel P. Berrange                                         block->niv, block->ivgen,
13173e308f20SDaniel P. Berrange                                         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
13183e308f20SDaniel P. Berrange                                         startsector, buf, len, errp);
13193e308f20SDaniel P. Berrange }
13203e308f20SDaniel P. Berrange 
13213e308f20SDaniel P. Berrange 
13223e308f20SDaniel P. Berrange const QCryptoBlockDriver qcrypto_block_driver_luks = {
13233e308f20SDaniel P. Berrange     .open = qcrypto_block_luks_open,
13243e308f20SDaniel P. Berrange     .create = qcrypto_block_luks_create,
13253e308f20SDaniel P. Berrange     .cleanup = qcrypto_block_luks_cleanup,
13263e308f20SDaniel P. Berrange     .decrypt = qcrypto_block_luks_decrypt,
13273e308f20SDaniel P. Berrange     .encrypt = qcrypto_block_luks_encrypt,
13283e308f20SDaniel P. Berrange     .has_format = qcrypto_block_luks_has_format,
13293e308f20SDaniel P. Berrange };
1330