+ // 0 secs for encrypted data area
+ params.data_alignment = 2048;
+ params.data_device = NULL;
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_0S));
+ OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms));
+ crypt_free(cd);
+ // load should be ok
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_0S));
+ OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
+ FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Device too small");
+ EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE);
+ crypt_free(cd);
+
+ // damaged header
+ OK_(_system("dd if=/dev/zero of=" DMDIR L_DEVICE_OK " bs=512 count=8 2>/dev/null", 1));
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
+ FAIL_(crypt_load(cd, CRYPT_LUKS1, NULL), "Header not found");
+ crypt_free(cd);
+
+ // plain device
+ OK_(crypt_init(&cd, DMDIR H_DEVICE));
+ FAIL_(crypt_load(cd, CRYPT_PLAIN, NULL), "Can't load nonLUKS device type");
+ crypt_free(cd);
+ OK_(crypt_init(&cd, DMDIR H_DEVICE));
+ OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, key, key_size, &pl_params));
+ FAIL_(crypt_load(cd, CRYPT_LUKS1, NULL), "Can't load over nonLUKS device type");
+ crypt_free(cd);
+
+ _cleanup_dmdevices();
+}
+
+static void LuksHeaderBackup(void)
+{
+ struct crypt_device *cd;
+ struct crypt_params_luks1 params = {
+ .hash = "sha512",
+ .data_alignment = 2048,
+ };
+ char key[128];
+
+ const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a";
+ size_t key_size = strlen(mk_hex) / 2;
+ const char *cipher = "aes";
+ const char *cipher_mode = "cbc-essiv:sha256";
+ uint64_t r_payload_offset;
+
+ crypt_decode_key(key, mk_hex, key_size);
+
+ OK_(get_luks_offsets(0, key_size, params.data_alignment, 0, NULL, &r_payload_offset));
+ OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1));
+
+ // create LUKS device and backup the header
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
+ OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms));
+ OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
+ OK_(crypt_header_backup(cd, CRYPT_LUKS1, BACKUP_FILE));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ crypt_free(cd);
+
+ // restore header from backup
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
+ OK_(crypt_header_restore(cd, CRYPT_LUKS1, BACKUP_FILE));
+ OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
+ OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
+ EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ crypt_free(cd);
+
+ _cleanup_dmdevices();
+}
+
+static void ResizeDeviceLuks(void)
+{
+ struct crypt_device *cd;
+ struct crypt_params_luks1 params = {
+ .hash = "sha512",
+ .data_alignment = 2048,
+ };
+ char key[128];
+
+ const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a";
+ size_t key_size = strlen(mk_hex) / 2;
+ const char *cipher = "aes";
+ const char *cipher_mode = "cbc-essiv:sha256";
+ uint64_t r_payload_offset, r_header_size, r_size;
+
+ crypt_decode_key(key, mk_hex, key_size);
+
+ // prepare env
+ OK_(get_luks_offsets(0, key_size, params.data_alignment, 0, NULL, &r_payload_offset));
+ OK_(get_luks_offsets(1, key_size, 0, 0, &r_header_size, NULL));
+ OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
+ OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1000));
+ OK_(create_dmdevice_over_loop(L_DEVICE_0S, 1000));
+
+ // test header and encrypted payload all in one device
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
+ OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms));
+ OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
+ OK_(crypt_resize(cd, CDEVICE_1, 42));
+ if (!device_size(DMDIR CDEVICE_1, &r_size))
+ EQ_(42, r_size >> SECTOR_SHIFT);
+ // autodetect encrypted device area size
+ OK_(crypt_resize(cd, CDEVICE_1, 0));
+ if (!device_size(DMDIR CDEVICE_1, &r_size))
+ EQ_(1000, r_size >> SECTOR_SHIFT);
+ FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small");
+ if (!device_size(DMDIR CDEVICE_1, &r_size))
+ EQ_(1000, r_size >> SECTOR_SHIFT);
+ EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ crypt_free(cd);
+
+ params.data_alignment = 0;
+ params.data_device = DMDIR L_DEVICE_0S;
+ // test case for external header
+ OK_(crypt_init(&cd, DMDIR H_DEVICE));
+ OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms));
+ OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
+ OK_(crypt_resize(cd, CDEVICE_1, 666));
+ if (!device_size(DMDIR CDEVICE_1, &r_size))
+ EQ_(666, r_size >> SECTOR_SHIFT);
+ // autodetect encrypted device size
+ OK_(crypt_resize(cd, CDEVICE_1, 0));
+ if (!device_size(DMDIR CDEVICE_1, &r_size))
+ EQ_(1000, r_size >> SECTOR_SHIFT);
+ FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small");
+ if (!device_size(DMDIR CDEVICE_1, &r_size))
+ EQ_(1000, r_size >> SECTOR_SHIFT);
+ EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ crypt_free(cd);
+
+ _cleanup_dmdevices();
+}
+
+static void HashDevicePlain(void)
+{
+ struct crypt_device *cd;
+ struct crypt_params_plain params = {
+ .hash = NULL,
+ .skip = 0,
+ .offset = 0,
+ };
+
+ size_t key_size;
+ const char *mk_hex, *keystr;
+ char key[256];
+
+ OK_(crypt_init(&cd, DEVICE_1));
+ OK_(crypt_format(cd, CRYPT_PLAIN, "aes", "cbc-essiv:sha256", NULL, NULL, 16, ¶ms));
+
+ // hash PLAIN, short key
+ OK_(_prepare_keyfile(KEYFILE1, "tooshort", 8));
+ FAIL_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 16, 0), "not enough data in keyfile");
+ _remove_keyfiles();
+
+ // hash PLAIN, exact key
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ mk_hex = "caffeecaffeecaffeecaffeecaffee88";
+ key_size = 16;
+ crypt_decode_key(key, mk_hex, key_size);
+ OK_(_prepare_keyfile(KEYFILE1, key, key_size));
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, key_size, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ OK_(strcmp(key, mk_hex));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ // Limit plain key
+ mk_hex = "caffeecaffeecaffeecaffeeca000000";
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, key_size - 3, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ OK_(strcmp(key, mk_hex));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ _remove_keyfiles();
+
+ // hash PLAIN, long key
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ mk_hex = "caffeecaffeecaffeecaffeecaffee88babebabe";
+ key_size = 16;
+ crypt_decode_key(key, mk_hex, key_size);
+ OK_(_prepare_keyfile(KEYFILE1, key, strlen(mk_hex) / 2));
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, key_size, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ FAIL_(strcmp(key, mk_hex), "only key length used");
+ OK_(strncmp(key, mk_hex, key_size));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+
+ // Now without explicit limit
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ FAIL_(strcmp(key, mk_hex), "only key length used");
+ OK_(strncmp(key, mk_hex, key_size));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ crypt_free(cd);
+
+ _remove_keyfiles();
+
+ // hash sha256
+ params.hash = "sha256";
+ OK_(crypt_init(&cd, DEVICE_1));
+ OK_(crypt_format(cd, CRYPT_PLAIN, "aes", "cbc-essiv:sha256", NULL, NULL, 16, ¶ms));
+
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ mk_hex = "c62e4615bd39e222572f3a1bf7c2132e";
+ keystr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+ key_size = strlen(keystr); // 32
+ OK_(_prepare_keyfile(KEYFILE1, keystr, strlen(keystr)));
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, key_size, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ OK_(strcmp(key, mk_hex));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ // Read full keyfile
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ OK_(strcmp(key, mk_hex));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ _remove_keyfiles();
+
+ // Limit keyfile read
+ keystr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAAAAAAAA";
+ OK_(_prepare_keyfile(KEYFILE1, keystr, strlen(keystr)));
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, key_size, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ OK_(strcmp(key, mk_hex));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ // Full keyfile
+ OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0));
+ OK_(_get_key_dm(CDEVICE_1, key, sizeof(key)));
+ OK_(strcmp(key, "0e49cb34a1dee1df33f6505e4de44a66"));
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ _remove_keyfiles();
+
+ // FIXME: add keyfile="-" tests somehow
+
+ crypt_free(cd);
+}
+
+static void VerityTest(void)
+{
+ struct crypt_device *cd;
+ const char *salt_hex = "20c28ffc129c12360ba6ceea2b6cf04e89c2b41cfe6b8439eb53c1897f50df7b";
+ const char *root_hex = "ab018b003a967fc782effb293b6dccb60b4f40c06bf80d16391acf686d28b5d6";
+ char salt[256], root_hash[256];
+ struct crypt_active_device cad;
+ struct crypt_params_verity params = {
+ .data_device = DEVICE_EMPTY,
+ .salt = salt,
+ .data_size = 0, /* whole device */
+ .hash_area_offset = 0,
+ .flags = CRYPT_VERITY_CREATE_HASH,
+ };
+
+ crypt_decode_key(salt, salt_hex, strlen(salt_hex) / 2);
+ crypt_decode_key(root_hash, root_hex, strlen(root_hex) / 2);
+
+ /* Format */
+ OK_(crypt_init(&cd, DEVICE_2));
+
+ /* block size */
+ params.data_block_size = 333;
+ FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
+ "Unsupppored block size.");
+ params.data_block_size = 4096;
+ params.hash_block_size = 333;
+ FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
+ "Unsupppored block size.");
+ params.hash_block_size = 4096;
+
+ /* salt size */
+ params.salt_size = 257;
+ FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
+ "Too large salt.");
+ params.salt_size = 32;
+
+ /* hash_type */
+ params.hash_type = 3;
+ FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
+ "Unsupported hash type.");
+ params.hash_type = 1;
+ params.hash_name = "blah";
+ FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
+ "Unsupported hash name.");
+ params.hash_name = "sha256";
+
+ OK_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms));
+ crypt_free(cd);
+
+ /* Verify */
+ OK_(crypt_init(&cd, DEVICE_2));
+ memset(¶ms, 0, sizeof(params));
+ params.data_device = DEVICE_EMPTY;
+ params.flags = CRYPT_VERITY_CHECK_HASH;
+ OK_(crypt_load(cd, CRYPT_VERITY, ¶ms));
+
+ /* check verity params */
+ EQ_(crypt_get_volume_key_size(cd), 32);
+ OK_(strcmp(CRYPT_VERITY, crypt_get_type(cd)));
+ memset(¶ms, 0, sizeof(params));
+ OK_(crypt_get_verity_info(cd, ¶ms));
+ OK_(strcmp("sha256", params.hash_name));
+ EQ_(strlen(salt_hex) / 2, params.salt_size);
+ OK_(memcmp(salt, params.salt, params.salt_size));
+ EQ_(4096, params.data_block_size);
+ EQ_(4096, params.hash_block_size);
+ EQ_(1, params.hash_type);
+ EQ_(crypt_get_volume_key_size(cd), 32);
+
+ OK_(crypt_activate_by_volume_key(cd, NULL, root_hash, 32, 0));
+ OK_(crypt_set_data_device(cd, DEVICE_1));
+ FAIL_(crypt_activate_by_volume_key(cd, NULL, root_hash, 32, 0), "Data corrupted");;
+
+ OK_(crypt_set_data_device(cd, DEVICE_EMPTY));
+ if (crypt_activate_by_volume_key(cd, CDEVICE_1, root_hash, 32,
+ CRYPT_ACTIVATE_READONLY) == -ENOTSUP) {
+ printf("WARNING: kernel dm-verity not supported, skipping test.\n");
+ crypt_free(cd);