static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry) { be64_to_cpus(&entry->bitmap_table_offset); be32_to_cpus(&entry->bitmap_table_size); be32_to_cpus(&entry->flags); be16_to_cpus(&entry->name_size); be32_to_cpus(&entry->extra_data_size); }
/* Reads a snapshot record from a qcow2-formatted file. * * The function assumes the file position of 'fd' points to the beginning of a * QcowSnapshotHeader record. When the call returns, the file position of fd is * at the place where the next QcowSnapshotHeader should start, if there is one. * * C.f. QCowSnapshotHeader in block/qcow2-snapshot.c for the complete layout of * the header. */ static void snapshot_info_read( int fd, SnapshotInfo* info ) { uint64_t start_offset = seek_or_die(fd, 0, SEEK_CUR); uint32_t extra_data_size; uint16_t id_str_size, name_size; /* read fixed-length fields */ seek_or_die(fd, 12, SEEK_CUR); /* skip l1 info */ read_or_die(fd, &id_str_size, sizeof(id_str_size)); read_or_die(fd, &name_size, sizeof(name_size)); read_or_die(fd, &info->date_sec, sizeof(info->date_sec)); read_or_die(fd, &info->date_nsec, sizeof(info->date_nsec)); read_or_die(fd, &info->vm_clock_nsec, sizeof(info->vm_clock_nsec)); read_or_die(fd, &info->vm_state_size, sizeof(info->vm_state_size)); read_or_die(fd, &extra_data_size, sizeof(extra_data_size)); /* convert to host endianness */ be16_to_cpus(&id_str_size); be16_to_cpus(&name_size); be32_to_cpus(&info->date_sec); be32_to_cpus(&info->date_nsec); be64_to_cpus(&info->vm_clock_nsec); be32_to_cpus(&info->vm_state_size); be32_to_cpus(&extra_data_size); be32_to_cpus(&extra_data_size); /* read variable-length buffers*/ info->id_str = android_alloc(id_str_size + 1); // +1: manual null-termination info->name = android_alloc(name_size + 1); seek_or_die(fd, extra_data_size, SEEK_CUR); /* skip extra data */ read_or_die(fd, info->id_str, id_str_size); read_or_die(fd, info->name, name_size); info->id_str[id_str_size] = '\0'; info->name[name_size] = '\0'; /* headers are 8 byte aligned, ceil to nearest multiple of 8 */ uint64_t end_offset = seek_or_die(fd, 0, SEEK_CUR); uint32_t total_size = end_offset - start_offset; uint32_t aligned_size = ((total_size - 1) / 8 + 1) * 8; /* skip to start of next record */ seek_or_die(fd, start_offset + aligned_size, SEEK_SET); }
static int bh1721fvc_get_luxvalue(struct bh1721fvc_data *bh1721fvc, u16 *value) { int retry; int i = 0; int j = 0; unsigned int als_total = 0; unsigned int als_index = 0; unsigned int als_max = 0; unsigned int als_min = 0; u8 als_high, als_low; for (retry = 0; retry < 10; retry++) { if (i2c_master_recv( bh1721fvc->client, (u8 *)value, 2) == 2) { be16_to_cpus(value); break; } } if(retry == 10) { printk("I2C read failed.. retry %d\n", retry); return -EIO; } als_index = (bh1721fvc->als_index_count++) % ALS_BUFFER_NUM; /*ALS buffer initialize (light sensor off ---> light sensor on) */ if (!bh1721fvc->als_buf_initialized) { bh1721fvc->als_buf_initialized = true; for (j = 0; j < ALS_BUFFER_NUM; j++) bh1721fvc->als_value_buf[j] = *value; } else bh1721fvc->als_value_buf[als_index] = *value; als_max = bh1721fvc->als_value_buf[0]; als_min = bh1721fvc->als_value_buf[0]; for (i = 0; i < ALS_BUFFER_NUM; i++) { als_total += bh1721fvc->als_value_buf[i]; if (als_max < bh1721fvc->als_value_buf[i]) als_max = bh1721fvc->als_value_buf[i]; if (als_min > bh1721fvc->als_value_buf[i]) als_min = bh1721fvc->als_value_buf[i]; } *value = (als_total-(als_max+als_min))/(ALS_BUFFER_NUM-2); if (bh1721fvc->als_index_count >= ALS_BUFFER_NUM) bh1721fvc->als_index_count = 0; return 0; }
/* nbd_receive_structured_reply_chunk * Read structured reply chunk except magic field (which should be already * read). * Payload is not read. */ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, NBDStructuredReplyChunk *chunk, Error **errp) { int ret; assert(chunk->magic == NBD_STRUCTURED_REPLY_MAGIC); ret = nbd_read(ioc, (uint8_t *)chunk + sizeof(chunk->magic), sizeof(*chunk) - sizeof(chunk->magic), errp); if (ret < 0) { return ret; } be16_to_cpus(&chunk->flags); be16_to_cpus(&chunk->type); be64_to_cpus(&chunk->handle); be32_to_cpus(&chunk->length); return 0; }
static ssize_t factory_file_illuminance_show(struct device *dev, struct device_attribute *attr, char *buf) { u16 lux; int retry; int err; unsigned int result; struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); if (bh1721fvc->state == POWER_DOWN) { err = bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_ON]); if (err) goto err_exit; err = bh1721fvc_write_byte(bh1721fvc->client, commands[AUTO_MEASURE]); if (err) goto err_exit; msleep(210); } for (retry = 0; retry < 10; retry++) { if (i2c_master_recv(bh1721fvc->client, (u8 *)&lux, 2) == 2) { be16_to_cpus(&lux); break; } } if (retry == 10) { printk(KERN_INFO "I2C read failed.. retry %d\n", retry); goto err_exit; } /* * result = (lux * 10) / 12; * result = result * 139 / 13; */ result = (lux * 89) / 10; if (result <= 8) result = 0; if (bh1721fvc->state == POWER_DOWN) bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); return sprintf(buf, "%u\n", result); err_exit: bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); return err; }
static void swap_2byte(unsigned char *buf, unsigned int size) { int i; u16 *psbuf = (u16 *)buf; if (size%2 == 1) { pr_err("%s: error size is odd. size=[%u]\n", __func__, size); return; } for (i = 0; i < size/2; i++) be16_to_cpus(psbuf+i); }
int bh1721fvc_test_luxvalue(struct bh1721fvc_data *bh1721fvc) { unsigned int result; int retry; u16 lux; int err; if (bh1721fvc->state == POWER_DOWN) { err = bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_ON]); if (err) return err; err = bh1721fvc_write_byte(bh1721fvc->client, commands[AUTO_MEASURE]); if (err) goto err_exit; msleep(210); } for (retry = 0; retry < 5; retry++) { if (i2c_master_recv(bh1721fvc->client, (u8 *)&lux, 2) == 2) { be16_to_cpus(&lux); break; } } if (retry == 5) { printk(KERN_INFO "I2C read failed.. retry %d\n", retry); goto err_exit; } result = (lux * 10) / 12; result = result * 139 / 13; if (bh1721fvc->state == POWER_DOWN) bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); return (int)result; err_exit: bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); return err; }
static int bh1721fvc_get_luxvalue(struct bh1721fvc_data *bh1721fvc, u16 * value) { int retry; for (retry = 0; retry < 10; retry++) { if (i2c_master_recv(bh1721fvc->client, (u8 *) value, 2) == 2) { be16_to_cpus(value); break; } } if (retry == 10) { pr_err("%s : I2C read failed.. retry %d\n", __func__, retry); return -EIO; } return 0; }
static ssize_t bh1721fvc_light_sensor_lux_show(struct device *dev, struct device_attribute *attr, char *buf) { u16 lux; int retry; int err; u32 result; struct bh1721fvc_data *bh1721fvc = dev_get_drvdata(dev); if (bh1721fvc->state == POWER_DOWN) { err = bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_ON]); if (err) goto err_exit; err = bh1721fvc_write_byte(bh1721fvc->client, commands[AUTO_MEASURE]); if (err) goto err_exit; msleep(210); } for (retry = 0; retry < 10; retry++) { if (i2c_master_recv(bh1721fvc->client, (u8 *) &lux, 2) == 2) { be16_to_cpus(&lux); break; } } if (retry == 10) { pr_err("%s : I2C read failed.. retry %d\n", __func__, retry); goto err_exit; } result = (lux * 89) / 10; if (bh1721fvc->state == POWER_DOWN) bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); return sprintf(buf, "%u\n", result); err_exit: bh1721fvc_write_byte(bh1721fvc->client, commands[POWER_DOWN]); return err; }
void ide_fixstring(u8 *s, const int bytecount, const int byteswap) { u8 *p, *end = &s[bytecount & ~1]; if (byteswap) { for (p = s ; p != end ; p += 2) be16_to_cpus((u16 *) p); } p = s; while (s != end && *s == ' ') ++s; while (s != end && *s) { if (*s++ != ' ' || (s != end && *s && *s != ' ')) *p++ = *(s-1); } while (p != end) *p++ = '\0'; }
void ide_fixstring(u8 *s, const int bytecount, const int byteswap) { u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */ if (byteswap) { /* convert from big-endian to host byte order */ for (p = s ; p != end ; p += 2) be16_to_cpus((u16 *) p); } /* strip leading blanks */ p = s; while (s != end && *s == ' ') ++s; /* compress internal blanks and strip trailing blanks */ while (s != end && *s) { if (*s++ != ' ' || (s != end && *s && *s != ' ')) *p++ = *(s-1); } /* wipe out trailing garbage */ while (p != end) *p++ = '\0'; }
static int qcrypto_block_luks_create(QCryptoBlock *block, QCryptoBlockCreateOptions *options, QCryptoBlockInitFunc initfunc, QCryptoBlockWriteFunc writefunc, void *opaque, Error **errp) { QCryptoBlockLUKS *luks; QCryptoBlockCreateOptionsLUKS luks_opts; Error *local_err = NULL; uint8_t *masterkey = NULL; uint8_t *slotkey = NULL; uint8_t *splitkey = NULL; size_t splitkeylen = 0; size_t i; QCryptoCipher *cipher = NULL; QCryptoIVGen *ivgen = NULL; char *password; const char *cipher_alg; const char *cipher_mode; const char *ivgen_alg; const char *ivgen_hash_alg = NULL; const char *hash_alg; char *cipher_mode_spec = NULL; QCryptoCipherAlgorithm ivcipheralg = 0; uint64_t iters; memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_iter_time) { luks_opts.iter_time = 2000; } if (!luks_opts.has_cipher_alg) { luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256; } if (!luks_opts.has_cipher_mode) { luks_opts.cipher_mode = QCRYPTO_CIPHER_MODE_XTS; } if (!luks_opts.has_ivgen_alg) { luks_opts.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64; } if (!luks_opts.has_hash_alg) { luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256; } if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) { if (!luks_opts.has_ivgen_hash_alg) { luks_opts.ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256; luks_opts.has_ivgen_hash_alg = true; } } /* Note we're allowing ivgen_hash_alg to be set even for * non-essiv iv generators that don't need a hash. It will * be silently ignored, for compatibility with dm-crypt */ if (!options->u.luks.key_secret) { error_setg(errp, "Parameter 'key-secret' is required for cipher"); return -1; } password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp); if (!password) { return -1; } luks = g_new0(QCryptoBlockLUKS, 1); block->opaque = luks; memcpy(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN); /* We populate the header in native endianness initially and * then convert everything to big endian just before writing * it out to disk */ luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION; qcrypto_block_luks_uuid_gen(luks->header.uuid); cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg, errp); if (!cipher_alg) { goto error; } cipher_mode = QCryptoCipherMode_lookup[luks_opts.cipher_mode]; ivgen_alg = QCryptoIVGenAlgorithm_lookup[luks_opts.ivgen_alg]; if (luks_opts.has_ivgen_hash_alg) { ivgen_hash_alg = QCryptoHashAlgorithm_lookup[luks_opts.ivgen_hash_alg]; cipher_mode_spec = g_strdup_printf("%s-%s:%s", cipher_mode, ivgen_alg, ivgen_hash_alg); } else { cipher_mode_spec = g_strdup_printf("%s-%s", cipher_mode, ivgen_alg); } hash_alg = QCryptoHashAlgorithm_lookup[luks_opts.hash_alg]; if (strlen(cipher_alg) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) { error_setg(errp, "Cipher name '%s' is too long for LUKS header", cipher_alg); goto error; } if (strlen(cipher_mode_spec) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) { error_setg(errp, "Cipher mode '%s' is too long for LUKS header", cipher_mode_spec); goto error; } if (strlen(hash_alg) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) { error_setg(errp, "Hash name '%s' is too long for LUKS header", hash_alg); goto error; } if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) { ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg, luks_opts.ivgen_hash_alg, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } } else { ivcipheralg = luks_opts.cipher_alg; } strcpy(luks->header.cipher_name, cipher_alg); strcpy(luks->header.cipher_mode, cipher_mode_spec); strcpy(luks->header.hash_spec, hash_alg); luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.cipher_alg); if (luks_opts.cipher_mode == QCRYPTO_CIPHER_MODE_XTS) { luks->header.key_bytes *= 2; } /* Generate the salt used for hashing the master key * with PBKDF later */ if (qcrypto_random_bytes(luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, errp) < 0) { goto error; } /* Generate random master key */ masterkey = g_new0(uint8_t, luks->header.key_bytes); if (qcrypto_random_bytes(masterkey, luks->header.key_bytes, errp) < 0) { goto error; } /* Setup the block device payload encryption objects */ block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg, luks_opts.cipher_mode, masterkey, luks->header.key_bytes, errp); if (!block->cipher) { goto error; } block->kdfhash = luks_opts.hash_alg; block->niv = qcrypto_cipher_get_iv_len(luks_opts.cipher_alg, luks_opts.cipher_mode); block->ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg, ivcipheralg, luks_opts.ivgen_hash_alg, masterkey, luks->header.key_bytes, errp); if (!block->ivgen) { goto error; } /* Determine how many iterations we need to hash the master * key, in order to have 1 second of compute time used */ iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, masterkey, luks->header.key_bytes, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, QCRYPTO_BLOCK_LUKS_DIGEST_LEN, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } if (iters > (ULLONG_MAX / luks_opts.iter_time)) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu too large to scale", (unsigned long long)iters); goto error; } /* iter_time was in millis, but count_iters reported for secs */ iters = iters * luks_opts.iter_time / 1000; /* Why /= 8 ? That matches cryptsetup, but there's no * explanation why they chose /= 8... Probably so that * if all 8 keyslots are active we only spend 1 second * in total time to check all keys */ iters /= 8; if (iters > UINT32_MAX) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu larger than %u", (unsigned long long)iters, UINT32_MAX); goto error; } iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS); luks->header.master_key_iterations = iters; /* Hash the master key, saving the result in the LUKS * header. This hash is used when opening the encrypted * device to verify that the user password unlocked a * valid master key */ if (qcrypto_pbkdf2(luks_opts.hash_alg, masterkey, luks->header.key_bytes, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.master_key_iterations, luks->header.master_key_digest, QCRYPTO_BLOCK_LUKS_DIGEST_LEN, errp) < 0) { goto error; } /* Although LUKS has multiple key slots, we're just going * to use the first key slot */ splitkeylen = luks->header.key_bytes * QCRYPTO_BLOCK_LUKS_STRIPES; for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { luks->header.key_slots[i].active = i == 0 ? QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED : QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED; luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES; /* This calculation doesn't match that shown in the spec, * but instead follows the cryptsetup implementation. */ luks->header.key_slots[i].key_offset = (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) + (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE), (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i); } if (qcrypto_random_bytes(luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, errp) < 0) { goto error; } /* Again we determine how many iterations are required to * hash the user password while consuming 1 second of compute * time */ iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, (uint8_t *)password, strlen(password), luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.key_bytes, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } if (iters > (ULLONG_MAX / luks_opts.iter_time)) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu too large to scale", (unsigned long long)iters); goto error; } /* iter_time was in millis, but count_iters reported for secs */ iters = iters * luks_opts.iter_time / 1000; if (iters > UINT32_MAX) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu larger than %u", (unsigned long long)iters, UINT32_MAX); goto error; } luks->header.key_slots[0].iterations = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS); /* Generate a key that we'll use to encrypt the master * key, from the user's password */ slotkey = g_new0(uint8_t, luks->header.key_bytes); if (qcrypto_pbkdf2(luks_opts.hash_alg, (uint8_t *)password, strlen(password), luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.key_slots[0].iterations, slotkey, luks->header.key_bytes, errp) < 0) { goto error; } /* Setup the encryption objects needed to encrypt the * master key material */ cipher = qcrypto_cipher_new(luks_opts.cipher_alg, luks_opts.cipher_mode, slotkey, luks->header.key_bytes, errp); if (!cipher) { goto error; } ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg, ivcipheralg, luks_opts.ivgen_hash_alg, slotkey, luks->header.key_bytes, errp); if (!ivgen) { goto error; } /* Before storing the master key, we need to vastly * increase its size, as protection against forensic * disk data recovery */ splitkey = g_new0(uint8_t, splitkeylen); if (qcrypto_afsplit_encode(luks_opts.hash_alg, luks->header.key_bytes, luks->header.key_slots[0].stripes, masterkey, splitkey, errp) < 0) { goto error; } /* Now we encrypt the split master key with the key generated * from the user's password, before storing it */ if (qcrypto_block_encrypt_helper(cipher, block->niv, ivgen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, 0, splitkey, splitkeylen, errp) < 0) { goto error; } /* The total size of the LUKS headers is the partition header + key * slot headers, rounded up to the nearest sector, combined with * the size of each master key material region, also rounded up * to the nearest sector */ luks->header.payload_offset = (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) + (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE), (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); block->payload_offset = luks->header.payload_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; /* Reserve header space to match payload offset */ initfunc(block, block->payload_offset, opaque, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } /* Everything on disk uses Big Endian, so flip header fields * before writing them */ cpu_to_be16s(&luks->header.version); cpu_to_be32s(&luks->header.payload_offset); cpu_to_be32s(&luks->header.key_bytes); cpu_to_be32s(&luks->header.master_key_iterations); for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { cpu_to_be32s(&luks->header.key_slots[i].active); cpu_to_be32s(&luks->header.key_slots[i].iterations); cpu_to_be32s(&luks->header.key_slots[i].key_offset); cpu_to_be32s(&luks->header.key_slots[i].stripes); } /* Write out the partition header and key slot headers */ writefunc(block, 0, (const uint8_t *)&luks->header, sizeof(luks->header), opaque, &local_err); /* Delay checking local_err until we've byte-swapped */ /* Byte swap the header back to native, in case we need * to read it again later */ be16_to_cpus(&luks->header.version); be32_to_cpus(&luks->header.payload_offset); be32_to_cpus(&luks->header.key_bytes); be32_to_cpus(&luks->header.master_key_iterations); for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { be32_to_cpus(&luks->header.key_slots[i].active); be32_to_cpus(&luks->header.key_slots[i].iterations); be32_to_cpus(&luks->header.key_slots[i].key_offset); be32_to_cpus(&luks->header.key_slots[i].stripes); } if (local_err) { error_propagate(errp, local_err); goto error; } /* Write out the master key material, starting at the * sector immediately following the partition header. */ if (writefunc(block, luks->header.key_slots[0].key_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, splitkey, splitkeylen, opaque, errp) != splitkeylen) { goto error; } luks->cipher_alg = luks_opts.cipher_alg; luks->cipher_mode = luks_opts.cipher_mode; luks->ivgen_alg = luks_opts.ivgen_alg; luks->ivgen_hash_alg = luks_opts.ivgen_hash_alg; luks->hash_alg = luks_opts.hash_alg; memset(masterkey, 0, luks->header.key_bytes); g_free(masterkey); memset(slotkey, 0, luks->header.key_bytes); g_free(slotkey); g_free(splitkey); g_free(password); g_free(cipher_mode_spec); qcrypto_ivgen_free(ivgen); qcrypto_cipher_free(cipher); return 0; error: if (masterkey) { memset(masterkey, 0, luks->header.key_bytes); } g_free(masterkey); if (slotkey) { memset(slotkey, 0, luks->header.key_bytes); } g_free(slotkey); g_free(splitkey); g_free(password); g_free(cipher_mode_spec); qcrypto_ivgen_free(ivgen); qcrypto_cipher_free(cipher); g_free(luks); return -1; }
static int qcrypto_block_luks_open(QCryptoBlock *block, QCryptoBlockOpenOptions *options, QCryptoBlockReadFunc readfunc, void *opaque, unsigned int flags, Error **errp) { QCryptoBlockLUKS *luks; Error *local_err = NULL; int ret = 0; size_t i; ssize_t rv; uint8_t *masterkey = NULL; size_t masterkeylen; char *ivgen_name, *ivhash_name; QCryptoCipherMode ciphermode; QCryptoCipherAlgorithm cipheralg; QCryptoIVGenAlgorithm ivalg; QCryptoCipherAlgorithm ivcipheralg; QCryptoHashAlgorithm hash; QCryptoHashAlgorithm ivhash; char *password = NULL; if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { if (!options->u.luks.key_secret) { error_setg(errp, "Parameter 'key-secret' is required for cipher"); return -1; } password = qcrypto_secret_lookup_as_utf8( options->u.luks.key_secret, errp); if (!password) { return -1; } } luks = g_new0(QCryptoBlockLUKS, 1); block->opaque = luks; /* Read the entire LUKS header, minus the key material from * the underlying device */ rv = readfunc(block, 0, (uint8_t *)&luks->header, sizeof(luks->header), opaque, errp); if (rv < 0) { ret = rv; goto fail; } /* The header is always stored in big-endian format, so * convert everything to native */ be16_to_cpus(&luks->header.version); be32_to_cpus(&luks->header.payload_offset); be32_to_cpus(&luks->header.key_bytes); be32_to_cpus(&luks->header.master_key_iterations); for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { be32_to_cpus(&luks->header.key_slots[i].active); be32_to_cpus(&luks->header.key_slots[i].iterations); be32_to_cpus(&luks->header.key_slots[i].key_offset); be32_to_cpus(&luks->header.key_slots[i].stripes); } if (memcmp(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) { error_setg(errp, "Volume is not in LUKS format"); ret = -EINVAL; goto fail; } if (luks->header.version != QCRYPTO_BLOCK_LUKS_VERSION) { error_setg(errp, "LUKS version %" PRIu32 " is not supported", luks->header.version); ret = -ENOTSUP; goto fail; } /* * The cipher_mode header contains a string that we have * to further parse, of the format * * <cipher-mode>-<iv-generator>[:<iv-hash>] * * eg cbc-essiv:sha256, cbc-plain64 */ ivgen_name = strchr(luks->header.cipher_mode, '-'); if (!ivgen_name) { ret = -EINVAL; error_setg(errp, "Unexpected cipher mode string format %s", luks->header.cipher_mode); goto fail; } *ivgen_name = '\0'; ivgen_name++; ivhash_name = strchr(ivgen_name, ':'); if (!ivhash_name) { ivhash = 0; } else { *ivhash_name = '\0'; ivhash_name++; ivhash = qcrypto_block_luks_hash_name_lookup(ivhash_name, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } } ciphermode = qcrypto_block_luks_cipher_mode_lookup(luks->header.cipher_mode, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } cipheralg = qcrypto_block_luks_cipher_name_lookup(luks->header.cipher_name, ciphermode, luks->header.key_bytes, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } hash = qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } ivalg = qcrypto_block_luks_ivgen_name_lookup(ivgen_name, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } if (ivalg == QCRYPTO_IVGEN_ALG_ESSIV) { if (!ivhash_name) { ret = -EINVAL; error_setg(errp, "Missing IV generator hash specification"); goto fail; } ivcipheralg = qcrypto_block_luks_essiv_cipher(cipheralg, ivhash, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } } else { /* Note we parsed the ivhash_name earlier in the cipher_mode * spec string even with plain/plain64 ivgens, but we * will ignore it, since it is irrelevant for these ivgens. * This is for compat with dm-crypt which will silently * ignore hash names with these ivgens rather than report * an error about the invalid usage */ ivcipheralg = cipheralg; } if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { /* Try to find which key slot our password is valid for * and unlock the master key from that slot. */ if (qcrypto_block_luks_find_key(block, password, cipheralg, ciphermode, hash, ivalg, ivcipheralg, ivhash, &masterkey, &masterkeylen, readfunc, opaque, errp) < 0) { ret = -EACCES; goto fail; } /* We have a valid master key now, so can setup the * block device payload decryption objects */ block->kdfhash = hash; block->niv = qcrypto_cipher_get_iv_len(cipheralg, ciphermode); block->ivgen = qcrypto_ivgen_new(ivalg, ivcipheralg, ivhash, masterkey, masterkeylen, errp); if (!block->ivgen) { ret = -ENOTSUP; goto fail; } block->cipher = qcrypto_cipher_new(cipheralg, ciphermode, masterkey, masterkeylen, errp); if (!block->cipher) { ret = -ENOTSUP; goto fail; } } block->payload_offset = luks->header.payload_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; luks->cipher_alg = cipheralg; luks->cipher_mode = ciphermode; luks->ivgen_alg = ivalg; luks->ivgen_hash_alg = ivhash; luks->hash_alg = hash; g_free(masterkey); g_free(password); return 0; fail: g_free(masterkey); qcrypto_cipher_free(block->cipher); qcrypto_ivgen_free(block->ivgen); g_free(luks); g_free(password); return ret; }
int nbd_receive_negotiate(QIOChannel *ioc, const char *name, QCryptoTLSCreds *tlscreds, const char *hostname, QIOChannel **outioc, NBDExportInfo *info, Error **errp) { char buf[256]; uint64_t magic; int rc; bool zeroes = true; trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : "<null>"); rc = -EINVAL; if (outioc) { *outioc = NULL; } if (tlscreds && !outioc) { error_setg(errp, "Output I/O channel required for TLS"); goto fail; } if (nbd_read(ioc, buf, 8, errp) < 0) { error_prepend(errp, "Failed to read data"); goto fail; } buf[8] = '\0'; if (strlen(buf) == 0) { error_setg(errp, "Server connection closed unexpectedly"); goto fail; } magic = ldq_be_p(buf); trace_nbd_receive_negotiate_magic(magic); if (memcmp(buf, "NBDMAGIC", 8) != 0) { error_setg(errp, "Invalid magic received"); goto fail; } if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { error_prepend(errp, "Failed to read magic"); goto fail; } magic = be64_to_cpu(magic); trace_nbd_receive_negotiate_magic(magic); if (magic == NBD_OPTS_MAGIC) { uint32_t clientflags = 0; uint16_t globalflags; bool fixedNewStyle = false; if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) { error_prepend(errp, "Failed to read server flags"); goto fail; } globalflags = be16_to_cpu(globalflags); trace_nbd_receive_negotiate_server_flags(globalflags); if (globalflags & NBD_FLAG_FIXED_NEWSTYLE) { fixedNewStyle = true; clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE; } if (globalflags & NBD_FLAG_NO_ZEROES) { zeroes = false; clientflags |= NBD_FLAG_C_NO_ZEROES; } /* client requested flags */ clientflags = cpu_to_be32(clientflags); if (nbd_write(ioc, &clientflags, sizeof(clientflags), errp) < 0) { error_prepend(errp, "Failed to send clientflags field"); goto fail; } if (tlscreds) { if (fixedNewStyle) { *outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp); if (!*outioc) { goto fail; } ioc = *outioc; } else { error_setg(errp, "Server does not support STARTTLS"); goto fail; } } if (!name) { trace_nbd_receive_negotiate_default_name(); name = ""; } if (fixedNewStyle) { int result; /* Try NBD_OPT_GO first - if it works, we are done (it * also gives us a good message if the server requires * TLS). If it is not available, fall back to * NBD_OPT_LIST for nicer error messages about a missing * export, then use NBD_OPT_EXPORT_NAME. */ result = nbd_opt_go(ioc, name, info, errp); if (result < 0) { goto fail; } if (result > 0) { return 0; } /* Check our desired export is present in the * server export list. Since NBD_OPT_EXPORT_NAME * cannot return an error message, running this * query gives us better error reporting if the * export name is not available. */ if (nbd_receive_query_exports(ioc, name, errp) < 0) { goto fail; } } /* write the export name request */ if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, name, errp) < 0) { goto fail; } /* Read the response */ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "Failed to read export length"); goto fail; } be64_to_cpus(&info->size); if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { error_prepend(errp, "Failed to read export flags"); goto fail; } be16_to_cpus(&info->flags); } else if (magic == NBD_CLIENT_MAGIC) { uint32_t oldflags; if (name) { error_setg(errp, "Server does not support export names"); goto fail; } if (tlscreds) { error_setg(errp, "Server does not support STARTTLS"); goto fail; } if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "Failed to read export length"); goto fail; } be64_to_cpus(&info->size); if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { error_prepend(errp, "Failed to read export flags"); goto fail; } be32_to_cpus(&oldflags); if (oldflags & ~0xffff) { error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); goto fail; } info->flags = oldflags; } else { error_setg(errp, "Bad magic received"); goto fail; } trace_nbd_receive_negotiate_size_flags(info->size, info->flags); if (zeroes && nbd_drop(ioc, 124, errp) < 0) { error_prepend(errp, "Failed to read reserved block"); goto fail; } rc = 0; fail: return rc; }
/* Returns -1 if NBD_OPT_GO proves the export @wantname cannot be * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to * go (with @info populated). */ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, NBDExportInfo *info, Error **errp) { nbd_opt_reply reply; uint32_t len = strlen(wantname); uint16_t type; int error; char *buf; /* The protocol requires that the server send NBD_INFO_EXPORT with * a non-zero flags (at least NBD_FLAG_HAS_FLAGS must be set); so * flags still 0 is a witness of a broken server. */ info->flags = 0; trace_nbd_opt_go_start(wantname); buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1); stl_be_p(buf, len); memcpy(buf + 4, wantname, len); /* At most one request, everything else up to server */ stw_be_p(buf + 4 + len, info->request_sizes); if (info->request_sizes) { stw_be_p(buf + 4 + len + 2, NBD_INFO_BLOCK_SIZE); } error = nbd_send_option_request(ioc, NBD_OPT_GO, 4 + len + 2 + 2 * info->request_sizes, buf, errp); g_free(buf); if (error < 0) { return -1; } while (1) { if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) { return -1; } error = nbd_handle_reply_err(ioc, &reply, errp); if (error <= 0) { return error; } len = reply.length; if (reply.type == NBD_REP_ACK) { /* Server is done sending info and moved into transmission phase, but make sure it sent flags */ if (len) { error_setg(errp, "server sent invalid NBD_REP_ACK"); return -1; } if (!info->flags) { error_setg(errp, "broken server omitted NBD_INFO_EXPORT"); return -1; } trace_nbd_opt_go_success(); return 1; } if (reply.type != NBD_REP_INFO) { error_setg(errp, "unexpected reply type %" PRIx32 " (%s), expected %x", reply.type, nbd_rep_lookup(reply.type), NBD_REP_INFO); nbd_send_opt_abort(ioc); return -1; } if (len < sizeof(type)) { error_setg(errp, "NBD_REP_INFO length %" PRIu32 " is too short", len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &type, sizeof(type), errp) < 0) { error_prepend(errp, "failed to read info type"); nbd_send_opt_abort(ioc); return -1; } len -= sizeof(type); be16_to_cpus(&type); switch (type) { case NBD_INFO_EXPORT: if (len != sizeof(info->size) + sizeof(info->flags)) { error_setg(errp, "remaining export info len %" PRIu32 " is unexpected size", len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "failed to read info size"); nbd_send_opt_abort(ioc); return -1; } be64_to_cpus(&info->size); if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { error_prepend(errp, "failed to read info flags"); nbd_send_opt_abort(ioc); return -1; } be16_to_cpus(&info->flags); trace_nbd_receive_negotiate_size_flags(info->size, info->flags); break; case NBD_INFO_BLOCK_SIZE: if (len != sizeof(info->min_block) * 3) { error_setg(errp, "remaining export info len %" PRIu32 " is unexpected size", len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->min_block, sizeof(info->min_block), errp) < 0) { error_prepend(errp, "failed to read info minimum block size"); nbd_send_opt_abort(ioc); return -1; } be32_to_cpus(&info->min_block); if (!is_power_of_2(info->min_block)) { error_setg(errp, "server minimum block size %" PRId32 "is not a power of two", info->min_block); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->opt_block, sizeof(info->opt_block), errp) < 0) { error_prepend(errp, "failed to read info preferred block size"); nbd_send_opt_abort(ioc); return -1; } be32_to_cpus(&info->opt_block); if (!is_power_of_2(info->opt_block) || info->opt_block < info->min_block) { error_setg(errp, "server preferred block size %" PRId32 "is not valid", info->opt_block); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->max_block, sizeof(info->max_block), errp) < 0) { error_prepend(errp, "failed to read info maximum block size"); nbd_send_opt_abort(ioc); return -1; } be32_to_cpus(&info->max_block); trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block, info->max_block); break; default: trace_nbd_opt_go_info_unknown(type, nbd_info_lookup(type)); if (nbd_drop(ioc, len, errp) < 0) { error_prepend(errp, "Failed to read info payload"); nbd_send_opt_abort(ioc); return -1; } break; } } }