void cp_set_header_key(xts_key *hdr_key, u8 salt[PKCS5_SALT_SIZE], int cipher, dc_pass *password) { u8 dkey[DISKKEY_SIZE]; sha512_pkcs5_2( 1000, password->pass, password->size, salt, PKCS5_SALT_SIZE, dkey, PKCS_DERIVE_MAX); xts_set_key(dkey, cipher, hdr_key); /* prevent leaks */ burn(dkey, sizeof(dkey)); }
static void dc_simple_encryption_test() { PXTS_TEST_CONTEXT ctx; unsigned char dk[256]; unsigned long e_crc, d_crc, i; // test PKDBF2 for (i = 0; i < (sizeof(pkcs5_vectors) / sizeof(pkcs5_vectors[0])); i++) { sha512_pkcs5_2(pkcs5_vectors[i].i_count, pkcs5_vectors[i].password, strlen(pkcs5_vectors[i].password), pkcs5_vectors[i].salt, strlen(pkcs5_vectors[i].salt), dk, pkcs5_vectors[i].dklen); if (memcmp(dk, pkcs5_vectors[i].key, pkcs5_vectors[i].dklen) != 0) { KeBugCheckEx(STATUS_ENCRYPTION_FAILED, 'DCRP', i, 0, 0); } } DbgMsg("PKDBF2 test passed\n"); // test XTS engine if memory may be allocated if ( (KeGetCurrentIrql() <= DISPATCH_LEVEL) && (ctx = (PXTS_TEST_CONTEXT)mm_secure_alloc(sizeof(XTS_TEST_CONTEXT))) != NULL ) { // fill key and test buffer for (i = 0; i < (sizeof(ctx->key) / sizeof(ctx->key[0])); i++) ctx->key[i] = (unsigned char)i; for (i = 0; i < (sizeof(ctx->test) / sizeof(ctx->test[0])); i++) ctx->test[i] = (unsigned short)i; // run test cases for (i = 0; i < (sizeof(xts_crc_vectors) / sizeof(xts_crc_vectors[0])); i++) { xts_set_key(ctx->key, xts_crc_vectors[i].alg, &ctx->xkey); xts_encrypt((const unsigned char*)ctx->test, (unsigned char*)ctx->buff, sizeof(ctx->test), 0x3FFFFFFFC00, &ctx->xkey); e_crc = crc32((const unsigned char*)ctx->buff, sizeof(ctx->buff)); xts_decrypt((const unsigned char*)ctx->test, (unsigned char*)ctx->buff, sizeof(ctx->test), 0x3FFFFFFFC00, &ctx->xkey); d_crc = crc32((const unsigned char*)ctx->buff, sizeof(ctx->buff)); if ( e_crc != xts_crc_vectors[i].e_crc || d_crc != xts_crc_vectors[i].d_crc ) { KeBugCheckEx(STATUS_ENCRYPTION_FAILED, 'DCRP', 0xFF00 | i, e_crc, d_crc); } } DbgMsg("XTS test passed\n"); mm_secure_free(ctx); } }
int dc_wipe_init(wipe_ctx *ctx, void *hook, int max_size, int method, int cipher) { char key[32]; int resl; do { zeroauto(ctx, sizeof(wipe_ctx)); if (method > sizeof(wipe_modes) / sizeof(wipe_mode)) { resl = ST_INV_WIPE_MODE; break; } ctx->mode = wipe_modes[method]; resl = ST_NOMEM; if (ctx->mode != NULL) { if ( (ctx->buff = mm_alloc(max_size, MEM_SECURE)) == NULL ) { break; } if ( (ctx->key = mm_alloc(sizeof(xts_key), MEM_SECURE)) == NULL ) { break; } /* generate random key */ rnd_get_bytes(key, sizeof(key)); xts_set_key(key, cipher, ctx->key); } ctx->hook = hook; ctx->size = max_size; resl = ST_OK; } while (0); /* prevent leaks */ zeroauto(key, sizeof(key)); if (resl != ST_OK) { if (ctx->buff != NULL) { mm_free(ctx->buff); } if (ctx->key != NULL) { mm_free(ctx->key); } } return resl; }
int cp_decrypt_header(xts_key *hdr_key, dc_header *header, dc_pass *password) { u8 dk[DISKKEY_SIZE]; int i, succs = 0; dc_header *hcopy; if ( (hcopy = mm_alloc(sizeof(dc_header), MEM_SECURE)) == NULL ) { return 0; } sha512_pkcs5_2( 1000, password->pass, password->size, header->salt, PKCS5_SALT_SIZE, dk, PKCS_DERIVE_MAX); for (i = 0; i < CF_CIPHERS_NUM; i++) { xts_set_key(dk, i, hdr_key); xts_decrypt( pv(header), pv(hcopy), sizeof(dc_header), 0, hdr_key); /* Magic 'DCRP' */ if (hcopy->sign != DC_VOLM_SIGN) { continue; } /* Check CRC of header */ if (hcopy->hdr_crc != crc32(pv(&hcopy->version), DC_CRC_AREA_SIZE)) { continue; } /* copy decrypted part to output */ memcpy(&header->sign, &hcopy->sign, DC_ENCRYPTEDDATASIZE); succs = 1; break; } /* prevent leaks */ burn(dk, sizeof(dk)); mm_free(hcopy); return succs; }
int dc_encrypt_cd( wchar_t *src_path, wchar_t *dst_path, dc_pass *pass, int cipher, cd_callback callback, void *param ) { dc_conf_data conf; HANDLE h_src = NULL; HANDLE h_dst = NULL; xts_key *v_key = NULL; xts_key *h_key = NULL; dc_header head; int resl; u64 iso_sz; u32 bytes; u8 salt[PKCS5_SALT_SIZE]; u8 dk[DISKKEY_SIZE]; if (alg_ok == 0) { if (dc_load_conf(&conf) == ST_OK) { xts_init(conf.conf_flags & CONF_HW_CRYPTO); } else { xts_init(0); } alg_ok = 1; } do { if ( (resl = dc_lock_memory(dk, sizeof(dk))) != ST_OK ) { break; } if ( (resl = dc_lock_memory(&head, sizeof(head))) != ST_OK ) { break; } h_src = CreateFile( src_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); if (h_src == INVALID_HANDLE_VALUE) { h_src = NULL; resl = ST_NO_OPEN_FILE; break; } h_dst = CreateFile( dst_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0); if (h_dst == INVALID_HANDLE_VALUE) { h_dst = NULL; resl = ST_NO_CREATE_FILE; break; } if (GetFileSizeEx(h_src, pv(&iso_sz)) == 0) { resl = ST_IO_ERROR; break; } v_key = VirtualAlloc(NULL, sizeof(xts_key), MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE); h_key = VirtualAlloc(NULL, sizeof(xts_key), MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE); if ( (v_key == NULL) || (h_key == NULL) ) { resl = ST_NOMEM; break; } /* lock keys in memory */ if ( (resl = dc_lock_memory(v_key, sizeof(xts_key))) != ST_OK ) { break; } if ( (resl = dc_lock_memory(h_key, sizeof(xts_key))) != ST_OK ) { break; } /* create volume header */ zeroauto(&head, sizeof(dc_header)); dc_get_random(pv(salt), PKCS5_SALT_SIZE); dc_get_random(pv(&head.disk_id), sizeof(u32)); dc_get_random(pv(head.key_1), DISKKEY_SIZE); head.sign = DC_VOLM_SIGN; head.version = DC_HDR_VERSION; head.flags = VF_NO_REDIR; head.alg_1 = cipher; head.use_size = iso_sz; head.data_off = sizeof(dc_header); head.hdr_crc = crc32(pv(&head.version), DC_CRC_AREA_SIZE); /* initialize volume key */ xts_set_key(head.key_1, cipher, v_key); /* initialize header key */ sha512_pkcs5_2( 1000, pass->pass, pass->size, salt, PKCS5_SALT_SIZE, dk, PKCS_DERIVE_MAX); xts_set_key(dk, cipher, h_key); /* encrypt volume header */ xts_encrypt(pv(&head), pv(&head), sizeof(dc_header), 0, h_key); /* save salt */ autocpy(head.salt, salt, PKCS5_SALT_SIZE); /* write volume header to file */ if (WriteFile(h_dst, &head, sizeof(head), &bytes, NULL) == 0) { resl = ST_IO_ERROR; break; } resl = do_cd_encrypt(h_src, h_dst, iso_sz, v_key, callback, param); } while (0); /* prevent leaks */ zeroauto(dk, sizeof(dk)); zeroauto(&head, sizeof(head)); dc_unlock_memory(dk); dc_unlock_memory(&head); if (v_key != NULL) { zeroauto(v_key, sizeof(xts_key)); dc_unlock_memory(v_key); VirtualFree(v_key, 0, MEM_RELEASE); } if (h_key != NULL) { zeroauto(h_key, sizeof(xts_key)); dc_unlock_memory(h_key); VirtualFree(h_key, 0, MEM_RELEASE); } if (h_src != NULL) { CloseHandle(h_src); } if (h_dst != NULL) { CloseHandle(h_dst); if (resl != ST_OK) { DeleteFile(dst_path); } } 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_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; }