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