void dc_update_volume(dev_hook *hook)
{
	void *p_buff = NULL;
	u64   old_sz = hook->dsk_size;

	wait_object_infinity(&hook->busy_lock);

	if (IS_STORAGE_ON_END(hook->flags) != 0)
	{
		if ( (p_buff = mm_alloc(hook->head_len, 0)) == NULL ) {
			goto exit;
		}
		if (NT_SUCCESS(io_device_rw(hook->hook_dev, p_buff, hook->head_len, 0, 1)) == FALSE) {
			goto exit;
		}
	}
	if (io_hook_ioctl(hook, IOCTL_VOLUME_UPDATE_PROPERTIES, NULL, 0, NULL, 0) != ST_OK) {
		goto exit;
	}	
	if ( (dc_fill_disk_info(hook) != ST_OK) || (hook->dsk_size == old_sz) ) {
		goto exit;
	} else {
		hook->use_size += hook->dsk_size - old_sz;
	}
	if (p_buff != NULL) {
		hook->stor_off = hook->dsk_size - hook->head_len;
		io_device_rw(hook->hook_dev, p_buff, hook->head_len, 0, 0);
	}
exit:
	if (p_buff != NULL) mm_free(p_buff);
	KeReleaseMutex(&hook->busy_lock, FALSE);
}
int dc_format_done(wchar_t *dev_name)
{
	dev_hook *hook = NULL;
	int       resl;

	DbgMsg("dc_format_done\n");

	do
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}
		wait_object_infinity(&hook->busy_lock);

		if ( !(hook->flags & F_FORMATTING) ) {
			resl = ST_ERROR; break;
		}
		/* set hook fields */
		hook->tmp_size = 0;
		hook->flags   &= ~F_FORMATTING;		
		/* free resources */
		dc_wipe_free(&hook->wp_ctx);
		mm_free(hook->tmp_buff);
		mm_free(hook->tmp_key);
		resl = ST_OK;
	} while (0);

	if (hook != NULL) {
		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}
	return resl;
}
int dc_backup_header(wchar_t *dev_name, dc_pass *password, void *out)
{
	dc_header *header = NULL;
	xts_key   *hdr_key = NULL;
	dev_hook  *hook    = NULL;
	int        resl;
	s8         salt[PKCS5_SALT_SIZE];

	do
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}
		wait_object_infinity(&hook->busy_lock);

		if (hook->flags & (F_SYNC | F_UNSUPRT | F_DISABLE | F_CDROM)) {
			resl = ST_ERROR; break;
		}
		if ( (hdr_key = mm_alloc(sizeof(xts_key), MEM_SECURE)) == NULL ) {
			resl = ST_NOMEM; break;
		}
		/* get device params */
		if (hook->dsk_size == 0) {
			if ( (resl = dc_fill_disk_info(hook)) != ST_OK ) break;
		}
		if ( (resl = io_read_header(hook, &header, NULL, password)) != ST_OK ) {
			break;
		}
		/* generate new salt */
		cp_rand_bytes(header->salt, PKCS5_SALT_SIZE);
		/* save original salt */
		memcpy(salt, header->salt, PKCS5_SALT_SIZE);		
		/* init new header key */
		cp_set_header_key(hdr_key, header->salt, header->alg_1, password);		
		/* encrypt header with new key */
		xts_encrypt(pv(header), pv(header), sizeof(dc_header), 0, hdr_key);
		/* restore original salt */
		memcpy(header->salt, salt, PKCS5_SALT_SIZE);

		/* copy header to output */
		memcpy(out, header, sizeof(dc_header));
		resl = ST_OK;
	} while (0);

	if (hook != NULL) {
		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}
	/* prevent leaks */
	burn(salt, sizeof(salt));
	/* free memory */	
	if (header != NULL) mm_free(header);
	if (hdr_key != NULL) mm_free(hdr_key);
	return resl;
}
Beispiel #4
0
static 
NTSTATUS dc_process_power_irp(dev_hook *hook, PIRP irp)
{
	NTSTATUS           status;
	PIO_STACK_LOCATION irp_sp;
	int                no_pass = 0;

	irp_sp = IoGetCurrentIrpStackLocation(irp);

	if ( (irp_sp->MinorFunction == IRP_MN_SET_POWER) && 
		 (irp_sp->Parameters.Power.Type == SystemPowerState) )
	{
		wait_object_infinity(&hook->busy_lock);

		if (irp_sp->Parameters.Power.State.SystemState == PowerSystemHibernate)
		{
			/* prevent device encryption to sync device and memory state */
			hook->flags |= F_PREVENT_ENC;
			dc_send_sync_packet(hook->dev_name, S_OP_SYNC, 0);
		}

		if (irp_sp->Parameters.Power.State.SystemState == PowerSystemWorking) {
			/* allow encryption requests */
			hook->flags &= ~F_PREVENT_ENC;
		}

		KeReleaseMutex(&hook->busy_lock, FALSE);
	}

	if ( (irp_sp->MinorFunction == IRP_MN_QUERY_POWER) && 
		 (irp_sp->Parameters.Power.Type == SystemPowerState) &&
		 (irp_sp->Parameters.Power.State.SystemState == PowerSystemHibernate) )
	{
		if ( (dc_is_vista_or_later == 0) && (dump_is_pverent_hibernate() != 0) ) {
			PoStartNextPowerIrp(irp);
			status  = dc_complete_irp(irp, STATUS_UNSUCCESSFUL, 0);
			no_pass = 1;
		}
	}

	if (no_pass == 0) {
		PoStartNextPowerIrp(irp);
		IoSkipCurrentIrpStackLocation(irp);
		status = PoCallDriver(hook->orig_dev, irp);
	}

	IoReleaseRemoveLock(&hook->remv_lock, irp);

	return status;
}
int dc_change_pass(wchar_t *dev_name, dc_pass *old_pass, dc_pass *new_pass)
{
	dc_header *header = NULL;
	dev_hook  *hook   = NULL;
	int        wp_init = 0;
	int        resl;
	wipe_ctx   wipe;	
	
	do
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}
		wait_object_infinity(&hook->busy_lock);

		if ( !(hook->flags & F_ENABLED) ) {
			resl = ST_NO_MOUNT; break;
		}
		if (hook->flags & (F_SYNC | F_FORMATTING | F_CDROM)) {
			resl = ST_ERROR; break;
		}
		/* read old volume header */
		if ( (resl = io_read_header(hook, &header, NULL, old_pass)) != ST_OK ) {
			break;
		}
		/* init data wipe */
		if ( (resl = dc_wipe_init(
			&wipe, hook, hook->head_len, WP_GUTMANN, hook->crypt.cipher_id)) == ST_OK )
		{
			wp_init = 1;
		} else break;

		/* wipe volume header */
		dc_wipe_process(&wipe, 0, hook->head_len);		
		/* write new volume header */
		resl = io_write_header(hook, header, NULL, new_pass);
	} while (0);

	if (wp_init != 0) {
		dc_wipe_free(&wipe);
	}
	if (hook != NULL) {
		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}	
	if (header != NULL) mm_free(header);
	return resl;
}
int dc_restore_header(wchar_t *dev_name, dc_pass *password, void *in)
{
	dc_header *header = NULL;
	xts_key   *hdr_key = NULL;
	dev_hook  *hook = NULL;
	int        resl;

	do
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}
		wait_object_infinity(&hook->busy_lock);

		if (hook->flags & (F_ENABLED | F_CDROM)) {
			resl = ST_ERROR; break;
		}
		/* get device params */
		if (hook->dsk_size == 0) {
			if ( (resl = dc_fill_disk_info(hook)) != ST_OK ) break;
		}
		if ( (header = mm_alloc(sizeof(dc_header), MEM_SECURE)) == NULL ) {
			resl = ST_NOMEM; break;
		}
		/* copy header from input */
		memcpy(header, in, sizeof(dc_header));

		if ( (hdr_key = mm_alloc(sizeof(xts_key), MEM_SECURE)) == NULL ) {
			resl = ST_NOMEM; break;
		}
		/* decrypt header */
		if (cp_decrypt_header(hdr_key, header, password) == 0) {
			resl = ST_PASS_ERR; break;
		}
		/* write new volume header */
		resl = io_write_header(hook, header, NULL, password);
	} while (0);

	if (hook != NULL) {
		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}
	if (hdr_key != NULL) mm_free(hdr_key);
	if (header != NULL) mm_free(header);

	return resl;
}
Beispiel #7
0
NTSTATUS dc_forward_irp_sync(dev_hook *hook, PIRP irp)
{
	KEVENT   sync;
	NTSTATUS status;

	KeInitializeEvent(&sync, NotificationEvent, FALSE);
	IoCopyCurrentIrpStackLocationToNext(irp);
    IoSetCompletionRoutine(irp, dc_sync_complete, &sync, TRUE, TRUE, TRUE);

	status = IoCallDriver(hook->orig_dev, irp);

    if (status == STATUS_PENDING) {
		wait_object_infinity(&sync);
		status = irp->IoStatus.Status;
    }
	return status;
}
Beispiel #8
0
int rnd_get_bytes(u8 *buf, int len)
{
	sha512_ctx sha_ctx;
	u8         hval[SHA512_DIGEST_SIZE];
	int        c_len, idx, i;
	ext_seed   seed;
	int        fail;

	if (reseed_cnt < 256) {
		DbgMsg("RNG not have sufficient entropy (%d reseeds), collect it now\n", reseed_cnt);
	}
	/* in RNG not have sufficient entropy, then collect it now */
	while (reseed_cnt < 256) 
	{
		dc_delay(1); /* wait 1 millisecond */
		rnd_reseed_now();
	}

	wait_object_infinity(&rnd_mutex);

	/* derive AES key from key pool */
	aes256_asm_set_key(key_pool, rnd_key);

	/* mix pool state before get data from it */
	rnd_pool_mix();

	/* idx - position for extraction pool data */
	idx = 0; fail = 0;
	do
	{
		c_len      = min(len, SHA512_DIGEST_SIZE);
		seed.seed1 = getrnd_cnt++;
		seed.seed2 = len;

		/* collect additional entropy before extract data block */
		rnd_reseed_now();

		sha512_init(&sha_ctx);
		sha512_hash(&sha_ctx, rnd_pool + idx, SHA512_DIGEST_SIZE);
		sha512_hash(&sha_ctx, pv(&seed), sizeof(seed));
		sha512_done(&sha_ctx, hval);

		/* encrypt hash value with AES in ECB mode */		
		for (i = 0; i < SHA512_DIGEST_SIZE; i += AES_BLOCK_SIZE) {
			aes256_asm_encrypt(hval + i, hval + i, rnd_key);
		}

		/* copy data to output */
		__try {
			memcpy(buf, hval, c_len);
		}
		__except(EXCEPTION_EXECUTE_HANDLER) {
			fail = 1;
		}

		/* increment extraction pointer */
		if ( (idx += SHA512_DIGEST_SIZE) == RNG_POOL_SIZE ) {
			/* if all data from pool extracted then 
			  mix pool for use new entropy added with reseeds */
			rnd_pool_mix(); idx = 0; 
		}

		/* collect additional entropy after extract data block */		
		rnd_reseed_now();

		/* update buffer pointer and remaining length */
		buf += c_len; len -= c_len;
	} while ( (len != 0) && (fail == 0) );

	/* mix pool after get data to prevent "could boot" attacks to generated keys */
	rnd_pool_mix();

	/* Prevent leaks */
	zeroauto(rnd_key, sizeof(aes256_key));
	zeroauto(&sha_ctx, sizeof(sha_ctx));
	zeroauto(hval, sizeof(hval));
	zeroauto(&seed, sizeof(seed));

	KeReleaseMutex(&rnd_mutex, FALSE);

	return fail == 0;
}
Beispiel #9
0
/*
   this routine process unmounting the device
   unmount options:
    UM_NOFSCTL - unmount without reporting to FS
	UM_FORCE   - force unmounting
*/
int dc_process_unmount(dev_hook *hook, int opt)
{
	IO_STATUS_BLOCK iosb;
	NTSTATUS        status;
	HANDLE          h_dev  = NULL;
	int             locked = 0;
	int             resl;	

	DbgMsg("dc_process_unmount, dev=%ws\n", hook->dev_name);
	
	if ((hook->flags & F_ENABLED) == 0)
	{
		return ST_NO_MOUNT;
	}

	wait_object_infinity(&hook->busy_lock);

	if ((hook->flags & F_ENABLED) == 0)
	{
		resl = ST_NO_MOUNT;
		goto cleanup;
	}

	do
	{
		if (hook->flags & F_FORMATTING) {
			dc_format_done(hook->dev_name);
		}

		if ( !(hook->flags & F_SYSTEM) && !(opt & MF_NOFSCTL) )
		{
			h_dev = io_open_device(hook->dev_name);

			if ( (h_dev == NULL) && !(opt & MF_FORCE) )	{
				resl = ST_LOCK_ERR; break;
			}

			if (h_dev != NULL)
			{
				status = ZwFsControlFile(h_dev, NULL, NULL, NULL, &iosb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);

				if ( (NT_SUCCESS(status) == FALSE) && !(opt & MF_FORCE) ) {
					resl = ST_LOCK_ERR; break;
				}
				locked = (NT_SUCCESS(status) != FALSE);

				ZwFsControlFile(h_dev, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);				
			}
		}

		if ((opt & MF_NOSYNC) == 0)
		{
			// temporary disable IRP processing
			hook->flags |= F_DISABLE;

			// wait for pending IRPs completion
			if ((opt & MF_NOWAIT_IO) == 0) {
				while (hook->remove_lock.Common.IoCount > 1) dc_delay(20);
			}
			if (hook->flags & F_SYNC) {
				// send signal to syncronous mode thread
				dc_send_sync_packet(hook->dev_name, S_OP_FINALIZE, 0);
			}			
		}

		hook->flags    &= ~F_CLEAR_ON_UNMOUNT;
		hook->use_size  = hook->dsk_size;
		hook->tmp_size  = 0;
		hook->mnt_flags = 0;
		resl            = ST_OK;

		// increment mount changes counter
		lock_inc(&hook->chg_mount);

		// free encryption key
		if (hook->dsk_key != NULL) {
			mm_secure_free(hook->dsk_key);
			hook->dsk_key = NULL;
		}

		if ( !(opt & MF_NOSYNC) ) {
			/* enable IRP processing */
			hook->flags &= ~F_DISABLE;
		}
	} while (0);

	if (h_dev != NULL) 
	{
		if (locked != 0) {
			ZwFsControlFile(h_dev, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0);
		}
		ZwClose(h_dev);
	}

cleanup:
	KeReleaseMutex(&hook->busy_lock, FALSE);	
	return resl;
}
Beispiel #10
0
int dc_mount_device(wchar_t *dev_name, dc_pass *password, u32 mnt_flags)
{
	dc_header *hcopy = NULL;
	dev_hook  *hook  = NULL;
	xts_key   *hdr_key = NULL;
	int        resl;
	
	DbgMsg("dc_mount_device %ws\n", dev_name);

	do 
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}

		wait_object_infinity(&hook->busy_lock);

		if (hook->flags & F_ENABLED) {
			resl = ST_ALR_MOUNT; break;
		}
		if (hook->flags & (F_UNSUPRT | F_DISABLE | F_FORMATTING)) {
			resl = ST_ERROR; break;
		}

		if ( !NT_SUCCESS(dc_fill_device_info(hook)) ) {
			resl = ST_IO_ERROR; break;
		}

		if ( ( (hook->flags & F_CDROM) && (hook->bps != CD_SECTOR_SIZE) ) ||
			 (!(hook->flags & F_CDROM) && IS_INVALID_SECTOR_SIZE(hook->bps) ) )
		{
			hook->flags |= F_UNSUPRT; resl = ST_ERROR; break;
		}
		if ( (resl = dc_probe_decrypt(hook, &hcopy, &hdr_key, password)) != ST_OK ) {
			break;
		}

		/* check volume header */		
		if ( (IS_INVALID_VOL_FLAGS(hcopy->flags) != 0) ||
			 ( (hcopy->flags & VF_STORAGE_FILE) && (hcopy->stor_off == 0) ) ||
			 (hcopy->alg_1 >= CF_CIPHERS_NUM) ||
			 (hcopy->alg_2 >= CF_CIPHERS_NUM) || 
			 (hcopy->tmp_wp_mode >= WP_NUM) ||
			 ( (hook->flags & F_CDROM) && (hcopy->flags & (VF_TMP_MODE | VF_STORAGE_FILE)) ) )
		{
			resl = ST_INV_VOLUME; break;
		}
		if (hcopy->version > DC_HDR_VERSION) {
			resl = ST_VOLUME_TOO_NEW; break;
		}
#if 0
		/* update volume header if needed */
		if ( (hcopy->version < DC_HDR_VERSION) && !(hook->flags & F_CDROM) )
		{
			hcopy->version = DC_HDR_VERSION;
			memset(hcopy->deprecated, 0, sizeof(hcopy->deprecated));
			
			io_write_header(hook, hcopy, hdr_key, NULL);
		}
#endif

		DbgMsg("hdr_key=%p, dsk_key=%p\n", hdr_key, hook->dsk_key);

		// initialize volume key
		if ( (hook->dsk_key = (xts_key*)mm_secure_alloc(sizeof(xts_key))) == NULL ) {
			resl = ST_NOMEM;
			break;
		}
		xts_set_key(hcopy->key_1, hcopy->alg_1, hook->dsk_key);

		DbgMsg("device mounted\n");

		if (hcopy->flags & VF_STORAGE_FILE) {
			hook->use_size = hook->dsk_size;
			hook->stor_off = hcopy->stor_off;
		} else {
			hook->use_size = hook->dsk_size - hook->head_len;
			hook->stor_off = hook->use_size;
		}		
		hook->crypt.cipher_id = d8(hcopy->alg_1);
		hook->disk_id    = hcopy->disk_id;
		hook->vf_version = hcopy->version;		
		hook->tmp_size   = 0;
		hook->mnt_flags  = mnt_flags;

		DbgMsg("hook->vf_version %d\n", hook->vf_version);
		DbgMsg("hook->bps %d\n", hook->bps);
		DbgMsg("hook->head_len %d\n", hook->head_len);		
		DbgMsg("flags %x\n", hcopy->flags);

		if (hcopy->flags & VF_STORAGE_FILE) {
			hook->flags |= F_PROTECT_DCSYS;
		}
		if (hcopy->flags & VF_NO_REDIR) {
			hook->flags   |= F_NO_REDIRECT;
			hook->stor_off = 0;			
		}

		if (hcopy->flags & VF_TMP_MODE)
		{
			hook->tmp_size      = hcopy->tmp_size;
			hook->hdr_key       = hdr_key;
			hook->crypt.wp_mode = hcopy->tmp_wp_mode;			

			if (hcopy->flags & VF_REENCRYPT) {
				hook->sync_init_type = S_CONTINUE_RE_ENC;
			} else {
				hook->sync_init_type = S_CONTINUE_ENC;
			}
				
			/* copy decrypted header to device data */
			memcpy(&hook->tmp_header, hcopy, sizeof(dc_header));
				
			if ( (resl = dc_enable_sync_mode(hook)) != ST_OK ) 
			{
				burn(&hook->tmp_header, sizeof(dc_header));
				hdr_key = hook->hdr_key;
			} else  {				
				hdr_key = NULL; /* prevent key wiping */
			}
		} else {			
			hook->flags |= F_ENABLED;
			resl = ST_OK;
		}
		if (resl == ST_OK) {
			/* increment mount changes counter */
			lock_inc(&hook->chg_mount);
		}
	} while (0);

	if (hdr_key != NULL) mm_secure_free(hdr_key);
	if (hcopy != NULL)   mm_secure_free(hcopy);

	if (hook != NULL)
	{
		if ((hook->flags & F_ENABLED) == 0 && hook->dsk_key != NULL) {
			mm_secure_free(hook->dsk_key);
			hook->dsk_key = NULL;
		}

		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}
	return resl;
}
int dc_format_step(wchar_t *dev_name, int wp_mode)
{
	dev_hook *hook = NULL;
	u8       *buff;
	int       resl;
	u64       offs;
	u32       size;

	do
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}

		wait_object_infinity(&hook->busy_lock);

		if ( !(hook->flags & F_FORMATTING) ) {
			resl = ST_ERROR; break;
		}

		offs = hook->tmp_size;
		buff = hook->tmp_buff;
		size = d32(min(hook->dsk_size - offs, ENC_BLOCK_SIZE));

		if (size == 0) {
			dc_format_done(dev_name);
			resl = ST_FINISHED; break;
		}

		if (hook->crypt.wp_mode != wp_mode)
		{
			dc_wipe_free(&hook->wp_ctx);

			resl = dc_wipe_init(
				&hook->wp_ctx, hook, ENC_BLOCK_SIZE, wp_mode, hook->crypt.cipher_id);

			if (resl == ST_OK) {
				hook->crypt.wp_mode = d8(wp_mode);
			} else {
				dc_wipe_init(&hook->wp_ctx, hook, ENC_BLOCK_SIZE, WP_NONE, 0);
				hook->crypt.wp_mode = WP_NONE;
			}
		}

		/* wipe sectors */
		dc_wipe_process(&hook->wp_ctx, offs, size);

		/* zero buffer */
		memset(buff, 0, size);
		/* encrypt buffer with temporary key */
		cp_fast_encrypt(buff, buff, size, offs, hook->tmp_key);

		/* write pseudo-random data to device */
		resl = io_hook_rw(hook, buff, size, offs, 0);

		if ( (resl == ST_OK) || (resl == ST_RW_ERR) ) {
			hook->tmp_size += size;
		}
		if ( (resl == ST_MEDIA_CHANGED) || (resl == ST_NO_MEDIA) ) {			
			dc_process_unmount(hook, MF_NOFSCTL); resl = ST_FINISHED;
		}
	} while (0);

	if (hook != NULL) {
		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}
	return resl;
}
int dc_format_start(wchar_t *dev_name, dc_pass *password, crypt_info *crypt)
{
	IO_STATUS_BLOCK iosb;
	NTSTATUS        status;
	dc_header      *header  = NULL;
	dev_hook       *hook    = NULL;
	xts_key        *tmp_key = NULL;
	HANDLE          h_dev   = NULL;
	u8             *buff    = NULL;
	int             w_init  = 0;
	u8              key_buf[32];
	int             resl;

	DbgMsg("dc_format_start\n");

	do
	{
		if ( (hook = dc_find_hook(dev_name)) == NULL ) {
			resl = ST_NF_DEVICE; break;
		}

		wait_object_infinity(&hook->busy_lock);

		if (hook->flags & (F_ENABLED | F_UNSUPRT | F_DISABLE | F_CDROM)) {
			resl = ST_ERROR; break;
		}

		/* verify encryption info */
		if ( (crypt->cipher_id >= CF_CIPHERS_NUM) || (crypt->wp_mode >= WP_NUM) ) {
			resl = ST_ERROR; break;
		}

		/* get device params */
		if ( (resl = dc_fill_disk_info(hook)) != ST_OK ) {
			break;
		}

		if ( (header = mm_alloc(sizeof(dc_header), MEM_SECURE)) == NULL ) {
			resl = ST_NOMEM; break;
		}
		if ( (buff = mm_alloc(ENC_BLOCK_SIZE, 0)) == NULL ) {
			resl = ST_NOMEM; break;
		}
		if ( (tmp_key = mm_alloc(sizeof(xts_key), MEM_SECURE)) == NULL ) {
			resl = ST_NOMEM; break;
		}		

		/* temporary disable automounting */
		hook->flags |= F_NO_AUTO_MOUNT;

		/* open volume device */
		if ( (h_dev = io_open_device(hook->dev_name)) == NULL ) {
			resl = ST_LOCK_ERR; break; 
		}		
		/* lock volume */
		status = ZwFsControlFile(
			h_dev, NULL, NULL, NULL, &iosb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);

		if (NT_SUCCESS(status) == FALSE) {
			resl = ST_LOCK_ERR; break; 
		}

		/* enable automounting */
		hook->flags &= ~F_NO_AUTO_MOUNT;
		/* set encryption info */
		hook->crypt = *crypt;

		/* init data wiping */
		resl = dc_wipe_init(
			&hook->wp_ctx, hook, ENC_BLOCK_SIZE, crypt->wp_mode, crypt->cipher_id);

		if (resl == ST_OK) {
			w_init = 1;			
		} else break;

		/* wipe first sectors */
		dc_wipe_process(&hook->wp_ctx, 0, hook->head_len);

		/* create random temporary key */
		cp_rand_bytes(key_buf, sizeof(key_buf));

		xts_set_key(key_buf, crypt->cipher_id, tmp_key);

		/* create volume header */
		memset(header, 0, sizeof(dc_header));

		cp_rand_bytes(pv(header->salt),     PKCS5_SALT_SIZE);
		cp_rand_bytes(pv(&header->disk_id), sizeof(u32));
		cp_rand_bytes(pv(header->key_1),    DISKKEY_SIZE);

		header->sign    = DC_VOLM_SIGN;
		header->version = DC_HDR_VERSION;
		header->alg_1   = crypt->cipher_id;		

		/* write volume header */
		if ( (resl = io_write_header(hook, header, NULL, password)) != ST_OK ) {
			break;
		}
		/* mount device */
		if ( (resl = dc_mount_device(dev_name, password, 0)) != ST_OK ) {
			break;
		}		
		/* set hook fields */
		hook->flags    |= F_FORMATTING;
		hook->tmp_size  = hook->head_len;
		hook->tmp_buff  = buff;
		hook->tmp_key   = tmp_key;
	} while (0);

	if ( (resl != ST_OK) )
	{
		if (w_init != 0) {
			dc_wipe_free(&hook->wp_ctx);
		}
		if (buff != NULL)    { mm_free(buff); }
		if (tmp_key != NULL) { mm_free(tmp_key); }
	}
	if (header != NULL) {
		mm_free(header);
	}
	if (hook != NULL) { 
		KeReleaseMutex(&hook->busy_lock, FALSE);
		dc_deref_hook(hook);
	}
	/* prevent leaks */
	burn(key_buf, sizeof(key_buf));
	
	if (h_dev != NULL)
	{
		if (resl != ST_LOCK_ERR)
		{
			/* dismount volume */
			ZwFsControlFile(
				h_dev, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);

			/* unlock volume */
			ZwFsControlFile(
				h_dev, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0);
		}
		/* close device */
		ZwClose(h_dev);
	}		

	return resl;
}