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; }
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; }
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; }
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; }
/* 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; }
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; }