static int _check_and_convert_hdr(const char *device, struct luks_phdr *hdr, int require_luks_device, int repair, struct crypt_device *ctx) { int r = 0; unsigned int i; char luksMagic[] = LUKS_MAGIC; if(memcmp(hdr->magic, luksMagic, LUKS_MAGIC_L)) { /* Check magic */ log_dbg("LUKS header not detected."); if (require_luks_device) log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device); return -EINVAL; } else if((hdr->version = ntohs(hdr->version)) != 1) { /* Convert every uint16/32_t item from network byte order */ log_err(ctx, _("Unsupported LUKS version %d.\n"), hdr->version); return -EINVAL; } hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0'; if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) { log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hdr->hashSpec); return -EINVAL; } /* Header detected */ hdr->payloadOffset = ntohl(hdr->payloadOffset); hdr->keyBytes = ntohl(hdr->keyBytes); hdr->mkDigestIterations = ntohl(hdr->mkDigestIterations); for(i = 0; i < LUKS_NUMKEYS; ++i) { hdr->keyblock[i].active = ntohl(hdr->keyblock[i].active); hdr->keyblock[i].passwordIterations = ntohl(hdr->keyblock[i].passwordIterations); hdr->keyblock[i].keyMaterialOffset = ntohl(hdr->keyblock[i].keyMaterialOffset); hdr->keyblock[i].stripes = ntohl(hdr->keyblock[i].stripes); if (LUKS_check_keyslot_size(hdr, i)) { log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i); r = -EINVAL; } } /* Avoid unterminated strings */ hdr->cipherName[LUKS_CIPHERNAME_L - 1] = '\0'; hdr->cipherMode[LUKS_CIPHERMODE_L - 1] = '\0'; hdr->uuid[UUID_STRING_L - 1] = '\0'; if (repair) { if (r == -EINVAL) r = _keyslot_repair(hdr, ctx); else log_verbose(ctx, _("No known problems detected for LUKS header.\n")); } 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 pkcs5_pbkdf2(const char *hash, const char *P, size_t Plen, const char *S, size_t Slen, unsigned int c, unsigned int dkLen, char *DK, unsigned int hash_block_size) { struct crypt_hmac *hmac; char U[MAX_PRF_BLOCK_LEN]; char T[MAX_PRF_BLOCK_LEN]; char P_hash[MAX_PRF_BLOCK_LEN]; int i, k, rc = -EINVAL; unsigned int u, hLen, l, r; size_t tmplen = Slen + 4; char *tmp; tmp = alloca(tmplen); if (tmp == NULL) return -ENOMEM; hLen = crypt_hmac_size(hash); if (hLen == 0 || hLen > MAX_PRF_BLOCK_LEN) return -EINVAL; if (c == 0) return -EINVAL; if (dkLen == 0) return -EINVAL; /* * * Steps: * * 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and * stop. */ if (dkLen > 4294967295U) return -EINVAL; /* * 2. Let l be the number of hLen-octet blocks in the derived key, * rounding up, and let r be the number of octets in the last * block: * * l = CEIL (dkLen / hLen) , * r = dkLen - (l - 1) * hLen . * * Here, CEIL (x) is the "ceiling" function, i.e. the smallest * integer greater than, or equal to, x. */ l = dkLen / hLen; if (dkLen % hLen) l++; r = dkLen - (l - 1) * hLen; /* * 3. For each block of the derived key apply the function F defined * below to the password P, the salt S, the iteration count c, and * the block index to compute the block: * * T_1 = F (P, S, c, 1) , * T_2 = F (P, S, c, 2) , * ... * T_l = F (P, S, c, l) , * * where the function F is defined as the exclusive-or sum of the * first c iterates of the underlying pseudorandom function PRF * applied to the password P and the concatenation of the salt S * and the block index i: * * F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c * * where * * U_1 = PRF (P, S || INT (i)) , * U_2 = PRF (P, U_1) , * ... * U_c = PRF (P, U_{c-1}) . * * Here, INT (i) is a four-octet encoding of the integer i, most * significant octet first. * * 4. Concatenate the blocks and extract the first dkLen octets to * produce a derived key DK: * * DK = T_1 || T_2 || ... || T_l<0..r-1> * * 5. Output the derived key DK. * * Note. The construction of the function F follows a "belt-and- * suspenders" approach. The iterates U_i are computed recursively to * remove a degree of parallelism from an opponent; they are exclusive- * ored together to reduce concerns about the recursion degenerating * into a small set of values. * */ /* If hash_block_size is provided, hash password in advance. */ if (hash_block_size > 0 && Plen > hash_block_size) { if (hash_buf(P, Plen, P_hash, hLen, hash)) return -EINVAL; if (crypt_hmac_init(&hmac, hash, P_hash, hLen)) return -EINVAL; memset(P_hash, 0, sizeof(P_hash)); } else { if (crypt_hmac_init(&hmac, hash, P, Plen)) return -EINVAL; } for (i = 1; (unsigned int) i <= l; i++) { memset(T, 0, hLen); for (u = 1; u <= c ; u++) { if (u == 1) { memcpy(tmp, S, Slen); tmp[Slen + 0] = (i & 0xff000000) >> 24; tmp[Slen + 1] = (i & 0x00ff0000) >> 16; tmp[Slen + 2] = (i & 0x0000ff00) >> 8; tmp[Slen + 3] = (i & 0x000000ff) >> 0; if (crypt_hmac_write(hmac, tmp, tmplen)) goto out; } else { if (crypt_hmac_write(hmac, U, hLen)) goto out; } if (crypt_hmac_final(hmac, U, hLen)) goto out; for (k = 0; (unsigned int) k < hLen; k++) T[k] ^= U[k]; }
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; }