int LUKS_read_phdr_backup(const char *backup_file, struct luks_phdr *hdr, int require_luks_device, struct crypt_device *ctx) { ssize_t hdr_size = sizeof(struct luks_phdr); int devfd = 0, r = 0; log_dbg("Reading LUKS header of size %d from backup file %s", (int)hdr_size, backup_file); devfd = open(backup_file, O_RDONLY); if(-1 == devfd) { log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file); return -ENOENT; } if (read(devfd, hdr, hdr_size) < hdr_size) r = -EIO; else { LUKS_fix_header_compatible(hdr); r = _check_and_convert_hdr(backup_file, hdr, require_luks_device, 0, ctx); } close(devfd); return r; }
int LUKS_generate_phdr(struct luks_phdr *header, const struct volume_key *vk, const char *cipherName, const char *cipherMode, const char *hashSpec, const char *uuid, unsigned int stripes, unsigned int alignPayload, unsigned int alignOffset, uint32_t iteration_time_ms, uint64_t *PBKDF2_per_sec, int detached_metadata_device, struct crypt_device *ctx) { unsigned int i = 0, hdr_sectors = LUKS_device_sectors(vk->keylength); size_t blocksPerStripeSet, currentSector; int r; uuid_t partitionUuid; char luksMagic[] = LUKS_MAGIC; /* For separate metadata device allow zero alignment */ if (alignPayload == 0 && !detached_metadata_device) alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE; if (alignPayload && detached_metadata_device && alignPayload < hdr_sectors) { log_err(ctx, _("Data offset for detached LUKS header must be " "either 0 or higher than header size (%d sectors).\n"), hdr_sectors); return -EINVAL; } if (crypt_hmac_size(hashSpec) < LUKS_DIGESTSIZE) { log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hashSpec); return -EINVAL; } if (uuid && uuid_parse(uuid, partitionUuid) == -1) { log_err(ctx, _("Wrong LUKS UUID format provided.\n")); return -EINVAL; } if (!uuid) uuid_generate(partitionUuid); memset(header,0,sizeof(struct luks_phdr)); /* Set Magic */ memcpy(header->magic,luksMagic,LUKS_MAGIC_L); header->version=1; strncpy(header->cipherName,cipherName,LUKS_CIPHERNAME_L); strncpy(header->cipherMode,cipherMode,LUKS_CIPHERMODE_L); strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L); header->keyBytes=vk->keylength; LUKS_fix_header_compatible(header); r = LUKS_check_cipher(header, ctx); if (r < 0) return r; log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes", header->version, header->hashSpec ,header->cipherName, header->cipherMode, header->keyBytes); r = crypt_random_get(ctx, header->mkDigestSalt, LUKS_SALTSIZE, CRYPT_RND_SALT); if(r < 0) { log_err(ctx, _("Cannot create LUKS header: reading random salt failed.\n")); return r; } r = crypt_benchmark_kdf(ctx, "pbkdf2", header->hashSpec, "foo", 3, "bar", 3, PBKDF2_per_sec); if (r < 0) { log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"), header->hashSpec); return r; } /* Compute master key digest */ iteration_time_ms /= 8; header->mkDigestIterations = at_least((uint32_t)(*PBKDF2_per_sec/1024) * iteration_time_ms, LUKS_MKD_ITERATIONS_MIN); r = crypt_pbkdf("pbkdf2", header->hashSpec, vk->key,vk->keylength, header->mkDigestSalt, LUKS_SALTSIZE, header->mkDigest,LUKS_DIGESTSIZE, header->mkDigestIterations); if(r < 0) { log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s).\n"), header->hashSpec); return r; } currentSector = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE; blocksPerStripeSet = AF_split_sectors(vk->keylength, stripes); for(i = 0; i < LUKS_NUMKEYS; ++i) { header->keyblock[i].active = LUKS_KEY_DISABLED; header->keyblock[i].keyMaterialOffset = currentSector; header->keyblock[i].stripes = stripes; currentSector = size_round_up(currentSector + blocksPerStripeSet, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE); } if (detached_metadata_device) { /* for separate metadata device use alignPayload directly */ header->payloadOffset = alignPayload; } else { /* alignOffset - offset from natural device alignment provided by topology info */ currentSector = size_round_up(currentSector, alignPayload); header->payloadOffset = currentSector + alignOffset; } uuid_unparse(partitionUuid, header->uuid); log_dbg("Data offset %d, UUID %s, digest iterations %" PRIu32, header->payloadOffset, header->uuid, header->mkDigestIterations); return 0; }
int LUKS_generate_phdr(struct luks_phdr *header, const struct volume_key *vk, const char *cipherName, const char *cipherMode, const char *hashSpec, const char *uuid, uint64_t data_offset, /* in bytes */ uint64_t align_offset, /* in bytes */ uint64_t required_alignment, /* in bytes */ struct crypt_device *ctx) { int i, r; size_t keyslot_sectors, header_sectors; uuid_t partitionUuid; struct crypt_pbkdf_type *pbkdf; double PBKDF2_temp; char luksMagic[] = LUKS_MAGIC; if (data_offset % SECTOR_SIZE || align_offset % SECTOR_SIZE || required_alignment % SECTOR_SIZE) return -EINVAL; memset(header, 0, sizeof(struct luks_phdr)); keyslot_sectors = AF_split_sectors(vk->keylength, LUKS_STRIPES); header_sectors = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE; for (i = 0; i < LUKS_NUMKEYS; i++) { header->keyblock[i].active = LUKS_KEY_DISABLED; header->keyblock[i].keyMaterialOffset = header_sectors; header->keyblock[i].stripes = LUKS_STRIPES; header_sectors = size_round_up(header_sectors + keyslot_sectors, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE); } /* In sector is now size of all keyslot material space */ /* Data offset has priority */ if (data_offset) header->payloadOffset = data_offset / SECTOR_SIZE; else if (required_alignment) { header->payloadOffset = size_round_up(header_sectors, (required_alignment / SECTOR_SIZE)); header->payloadOffset += (align_offset / SECTOR_SIZE); } else header->payloadOffset = 0; if (header->payloadOffset && header->payloadOffset < header_sectors) { log_err(ctx, _("Data offset for LUKS header must be " "either 0 or higher than header size.")); return -EINVAL; } if (crypt_hmac_size(hashSpec) < LUKS_DIGESTSIZE) { log_err(ctx, _("Requested LUKS hash %s is not supported."), hashSpec); return -EINVAL; } if (uuid && uuid_parse(uuid, partitionUuid) == -1) { log_err(ctx, _("Wrong LUKS UUID format provided.")); return -EINVAL; } if (!uuid) uuid_generate(partitionUuid); /* Set Magic */ memcpy(header->magic,luksMagic,LUKS_MAGIC_L); header->version=1; strncpy(header->cipherName,cipherName,LUKS_CIPHERNAME_L-1); strncpy(header->cipherMode,cipherMode,LUKS_CIPHERMODE_L-1); strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L-1); header->keyBytes=vk->keylength; LUKS_fix_header_compatible(header); log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes", header->version, header->hashSpec ,header->cipherName, header->cipherMode, header->keyBytes); r = crypt_random_get(ctx, header->mkDigestSalt, LUKS_SALTSIZE, CRYPT_RND_SALT); if(r < 0) { log_err(ctx, _("Cannot create LUKS header: reading random salt failed.")); return r; } /* Compute master key digest */ pbkdf = crypt_get_pbkdf(ctx); r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength); if (r < 0) return r; assert(pbkdf->iterations); PBKDF2_temp = (double)pbkdf->iterations * LUKS_MKD_ITERATIONS_MS / pbkdf->time_ms; if (PBKDF2_temp > (double)UINT32_MAX) return -EINVAL; header->mkDigestIterations = at_least((uint32_t)PBKDF2_temp, LUKS_MKD_ITERATIONS_MIN); r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec, vk->key,vk->keylength, header->mkDigestSalt, LUKS_SALTSIZE, header->mkDigest,LUKS_DIGESTSIZE, header->mkDigestIterations, 0, 0); if (r < 0) { log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s)."), header->hashSpec); return r; } uuid_unparse(partitionUuid, header->uuid); log_dbg(ctx, "Data offset %d, UUID %s, digest iterations %" PRIu32, header->payloadOffset, header->uuid, header->mkDigestIterations); return 0; }