/** * Create a new buffer with the replaced environment values. * * \param buf Buffer with values to be replaced. * \param len Length of original buffer and output of final. * \return The allocated buffer that should be freed with free. */ static char *tc_cmd_env_subs(const char *buf, uint32_t *len) { uint8_t state = 0; uint32_t l = 0; uint32_t alloc = 0; char *result = NULL; uint32_t i = 0; bool finished = false; while (true) { if (l == alloc) { alloc = alloc ? (alloc << 1) : 16; result = (char *)realloc(result, alloc); } if (i == *len) { finished = true; break; } if (buf[i] == '$') { i++; if (i == *len) { tc_log(TC_LOG_ERR, "Syntax error: $ at end of command"); break; } if (buf[i] != '$') { uint32_t endi; for (endi = i; endi < *len; endi++) if (!tc_cmd_env_ischar(buf[endi])) break; if (endi == i) { tc_log(TC_LOG_ERR, "Syntax error: $ not followed by variable name"); break; } tc_cmd_env_t *env = tc_cmd_env_find(buf + i, endi - i); if (!env) { tc_log(TC_LOG_ERR, "Syntax error: Variable \"%s\" not found", strndupa(buf + i, endi - i)); break; } uint32_t newl = l + strlen(env->value); while (alloc < newl) { alloc = alloc << 1; result = (char *)realloc(result, alloc); } memcpy(result + l, env->value, strlen(env->value)); l = newl; i = endi; continue; } } result[l++] = buf[i++]; } *len = l; if (!finished) { if (result) { free(result); result = NULL; } } return result; }
int tc_server_init(void) { /* Open the socket */ tc_server_fd = socket(PF_INET, SOCK_DGRAM, 0); if (tc_server_fd == -1) { tc_log(TC_LOG_ERR, "Error creating server socket"); return -1; } /* Bind for the address */ struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(1423); addr.sin_addr.s_addr = INADDR_ANY; int r = bind(tc_server_fd, (struct sockaddr *)&addr, sizeof(addr)); if (r) { tc_log(TC_LOG_ERR, "Error binding server socket"); tc_server_release(); return -1; } /* Create the event pipe */ if (tc_msg_queue_create(&tc_server_queue)) { tc_server_release(); return -1; } /* Return success */ return 0; }
int tc_cmd_env_set(const char *name, uint32_t namelen, const char *value, uint32_t valuelen) { /* Validate the name */ uint32_t i = 0; for (i = 0; i < namelen; i++) { if (!tc_cmd_env_ischar(name[i])) break; } if (i < namelen || namelen == 0) { tc_log(TC_LOG_ERR, "Invalid name for variable \"%s\"", strndupa(name, namelen)); return -1; } /* Replace an existing value if found */ tc_cmd_env_t *e = tc_cmd_env_find(name, namelen); if (e) { free((void *)e->value); e->value = strndup(value, valuelen); tc_log(TC_LOG_INFO, "Variable %s = \"%s\" (replaced value)", strndupa(name, namelen), strndupa(value, valuelen)); return 0; } /* Add the new value if not found */ e = (tc_cmd_env_t *)malloc(sizeof(tc_cmd_env_t)); e->name = strndup(name, namelen); e->value = strndup(value, valuelen); e->next = tc_cmd_env; tc_cmd_env = e; tc_log(TC_LOG_INFO, "Variable %s = \"%s\" (new value)", strndupa(name, namelen), strndupa(value, valuelen)); return 0; }
int write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem, size_t bytes) { unsigned char *mem_buf = NULL; ssize_t w; size_t sz; off_t internal_off; int fd; /* Align to block sizes */ internal_off = offset % blksz; #ifdef DEBUG printf("offset: %"PRIu64", internal offset: %"PRIu64"\n", (uint64_t)offset, (uint64_t)internal_off); #endif offset = (offset/blksz) * blksz; if ((internal_off + bytes) > blksz) { tc_log(1, "This should never happen: internal_off + bytes > " "blksz (write_to_disk)\n"); return -1; } if ((bytes < blksz) || (internal_off != 0)) { sz = blksz; if ((mem_buf = read_to_safe_mem(dev, offset, &sz)) == NULL) { tc_log(1, "Error buffering data on " "write_to_disk(%s)\n", dev); return -1; } memcpy(mem_buf + internal_off, mem, bytes); } if ((fd = open(dev, O_WRONLY)) < 0) { tc_log(1, "Error opening device %s\n", dev); return -1; } if ((lseek(fd, offset, (offset >= 0) ? SEEK_SET : SEEK_END) < 0)) { tc_log(1, "Error seeking on device %s\n", dev); close(fd); return -1; } if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) { tc_log(1, "Error writing to device %s\n", dev); close(fd); return -1; } close(fd); if (mem_buf != NULL) free_safe_mem(mem_buf); return 0; }
static struct tcplay_info * new_info(const char *dev, int flags, struct tc_cipher_chain *cipher_chain, struct pbkdf_prf_algo *prf, struct tchdr_dec *hdr, off_t start) { struct tc_cipher_chain *chain_start; struct tcplay_info *info; int i; int error; chain_start = cipher_chain; if ((info = (struct tcplay_info *)alloc_safe_mem(sizeof(*info))) == NULL) { tc_log(1, "could not allocate safe info memory\n"); return NULL; } strncpy(info->dev, dev, sizeof(info->dev)); info->cipher_chain = cipher_chain; info->pbkdf_prf = prf; info->start = start; info->hdr = hdr; info->blk_sz = hdr->sec_sz; info->size = hdr->sz_mk_scope / hdr->sec_sz; /* volume size */ info->skip = hdr->off_mk_scope / hdr->sec_sz; /* iv skip */ info->volflags = hdr->flags; info->flags = flags; if (TC_FLAG_SET(flags, SYS)) info->offset = 0; /* offset is 0 for system volumes */ else info->offset = hdr->off_mk_scope / hdr->sec_sz; /* block offset */ /* Associate a key out of the key pool with each cipher in the chain */ error = tc_cipher_chain_populate_keys(cipher_chain, hdr->keys); if (error) { tc_log(1, "could not populate keys in cipher chain\n"); return NULL; } for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) { for (i = 0; i < cipher_chain->cipher->klen; i++) sprintf(&cipher_chain->dm_key[i*2], "%02x", cipher_chain->key[i]); } tc_cipher_chain_free_keys(chain_start); return info; }
/* Update router table */ void router_update(tc_ip_header_t *ip_header, int len) { void *fd; uint32_t size_ip; uint64_t key; msg_server_t msg; struct tcphdr *tcp_header; size_ip = ip_header->ihl << 2; tcp_header = (struct tcphdr*)((char *)ip_header + size_ip); memcpy(&msg, ip_header, len); key = get_key(ip_header->daddr, tcp_header->dest); pthread_mutex_lock(&mutex); fd = hash_find(table, key); if ( NULL == fd ) { tc_log((LOG_DEBUG), 0, "fd is null"); delay_table_add(key, &msg); pthread_mutex_unlock(&mutex); return ; } pthread_mutex_unlock(&mutex); tc_socket_send((int) (long) fd, (char *) &msg, MSG_SERVER_SIZE); }
int get_disk_info(const char *dev, disksz_t *blocks, size_t *bsize) { uint64_t nbytes; int blocksz; int fd; if ((fd = open(dev, O_RDONLY)) < 0) { tc_log(1, "Error opening %s\n", dev); return -1; } if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) { close(fd); return -1; } if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) { close(fd); return -1; } *blocks = (disksz_t)(nbytes / blocksz); *bsize = (size_t)(blocksz); close(fd); return 0; }
const char *tc_cmd_env_csv(void) { /* Debug */ #ifdef TC_CMD_DEBUG tc_log(TC_LOG_DEBUG, "tc_cmd: env_csv"); #endif /* TC_CMD_DEBUG */ /* Calculate tht length */ uint32_t len = 1; tc_cmd_env_t *e = tc_cmd_env; while (e) { len += tc_cmd_env_csv_scape_len(e->name); len++; len += tc_cmd_env_csv_scape_len(e->value); len++; e = e->next; } /* Allocate the output */ #ifdef TC_CMD_DEBUG tc_log(TC_LOG_DEBUG, "tc_cmd: env_csv: alloc:%u", (unsigned)len); #endif /* TC_CMD_DEBUG */ char *output = (char *)malloc(len); /* Write each entry of the output */ char *o = output; e = tc_cmd_env; while (e) { o = tc_cmd_env_csv_scape(o, e->name); *o++ = ','; o = tc_cmd_env_csv_scape(o, e->value); *o++ = '\n'; e = e->next; } /* Write the end of text */ *o++ = 0; /* Debug */ #ifdef TC_CMD_DEBUG tc_log(TC_LOG_DEBUG, "tc_cmd: env_csv: finished"); #endif /* TC_CMD_DEBUG */ /* Return the output */ return output; }
static void get_random_summary(void) { float pct_done = get_random_read_progress(); tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done); }
int tc_server_event(const char *buffer, uint8_t len) { if (tc_msg_send(&tc_server_queue, buffer, len)) { tc_log(TC_LOG_ERR, "Error enqueuing event"); return -1; } return 0; }
/** * Internal function to execute an scripting command. * * \param cmd Pointer to the command to execute. * \param buf Buffer with the command to execute. * \param len Length of the command to execute * \retval 0 on success of normal command. * \retval 1 on exit command. * \retval -1 on error in command. */ static int tc_cmd_script_exec(tc_cmd_t *cmd, const char *buf, uint32_t len) { tc_cmd_script_t *s = tc_containerof(cmd, tc_cmd_script_t, cmd); tc_cmd_script_entry_t *e = s->entry; while (e) { tc_log(TC_LOG_INFO, "Subcommand \"%s\"", e->cmd); int r = tc_cmd(e->cmd, strlen(e->cmd)); if (r) { if (r < 0) tc_log(TC_LOG_ERR, "Error in subcommand \"%s\"", e->cmd); return r; } e = e->next; } return 0; }
/** * Add a new command to the list of available commands. * * \param cmd Command to be added. */ static void tc_cmd_add(tc_cmd_t *cmd) { cmd->next = tc_cmd_first; tc_cmd_first = cmd; #ifdef TC_CMD_DEBUG tc_log(TC_LOG_DEBUG, "cmd: add: \"%s\"", cmd->name); #endif /* TC_CMD_DEBUG */ }
void tc_server_exec(void) { /* Wait for anything to be received */ while (true) { /* Check if there is any reception event */ struct pollfd fds[2]; fds[0].fd = tc_server_fd; fds[0].events = POLLIN; fds[1].fd = TC_MSG_QUEUE_POLLFD(&tc_server_queue); fds[1].events = POLLIN; int r = poll(fds, 2, -1); if (fds[0].revents & POLLIN) { /* We have received a message */ struct sockaddr_in src; socklen_t src_len = sizeof(src); char buf[257]; ssize_t r = recvfrom(tc_server_fd, buf, sizeof(buf)-1, 0, (struct sockaddr *)&src, &src_len); if (r > 0) { buf[r] = 0; tc_log(TC_LOG_INFO, "Command: \"%s\"", buf); int ret = tc_cmd(buf, r); if (ret > 0) break; if (ret < 0) tc_log(TC_LOG_ERR, "Error in command: \"%s\"", buf); } } if (fds[1].revents & POLLIN) { /* We have received an event */ tc_msg_t msg; if (tc_msg_recv(&tc_server_queue, &msg)) { tc_log(TC_LOG_ERR, "server: Error reading from event pipe"); break; } /* Execute the event */ tc_log(TC_LOG_INFO, "Event: \"%s\"", msg.buf); int ret = tc_cmd((const char *)msg.buf, msg.len); if (ret > 0) break; if (ret < 0) tc_log(TC_LOG_ERR, "Error in event: \"%s\"", msg.buf); } } }
/** * Load a file to add new commands * * \param path Path of the file with the new commands. * \retval -1 on error (with a log entry). * \retval 1 on file not possible to be read. * \retval 0 on success. */ static int tc_cmd_load(const char *path) { /* Try to open the file */ FILE *f = fopen(path, "rt"); if (!f) { tc_log(TC_LOG_WARN, "Script file \"%s\" not present", path); return 1; } tc_log(TC_LOG_INFO, "Executing script file \"%s\"", path); /* Try to read a line until it finishes */ int result = 0; while (true) { /* Get a new line without carry return */ char buf[256]; char *r = fgets(buf, sizeof(buf), f); if (!r) break; int buf_len = strlen(buf); if (!buf_len) continue; if (buf[buf_len-1] == '\n') { buf[--buf_len] = 0; if (!buf_len) continue; } /* Execute the commands */ tc_log(TC_LOG_INFO, "Command \"%s\"", strndupa(buf, buf_len)); int nr = tc_cmd(buf, buf_len); if (nr) { if (nr < 0) result = -1; break; } } /* Close the file */ fclose(f); /* Return the result */ return result; }
/** * Execute an process command * * \param cmd Pointer to the command to execute. * \param buf Buffer with the command to execute. * \param len Length of the command to execute * \retval 0 on success of normal command. * \retval 1 on exit command. * \retval -1 on error in command. */ static int tc_cmd_exec_exec(tc_cmd_t *cmd, const char *buf, uint32_t len) { /* exec <process> <arguments> */ char *command = (char *)malloc(len + 1); memcpy(command, buf, len); command[len] = 0; tc_log(TC_LOG_INFO, "Executing command: \"%s\"", command); int r = system(command); return r ? -1 : 0; }
int write_to_file(const char *file, void *mem, size_t bytes) { int fd; ssize_t w; if ((fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { tc_log(1, "Error opening file %s\n", file); return -1; } if ((w = write(fd, mem, bytes)) < 0) { tc_log(1, "Error writing to file %s\n", file); close(fd); return -1; } close(fd); return 0; }
int verify_hdr(int veracrypt_mode, struct tchdr_dec *hdr) { uint32_t crc; if ( (!veracrypt_mode && (memcmp(hdr->tc_str, TC_SIG, sizeof(hdr->tc_str)) != 0)) || ( veracrypt_mode && (memcmp(hdr->tc_str, VC_SIG, sizeof(hdr->tc_str)) != 0))) { #ifdef DEBUG fprintf(stderr, "Signature mismatch\n"); #endif return 0; } crc = crc32((void *)&hdr->keys, 256); if (crc != hdr->crc_keys) { #ifdef DEBUG fprintf(stderr, "CRC32 mismatch (crc_keys)\n"); #endif return 0; } switch(hdr->tc_ver) { case 1: case 2: /* Unsupported header version */ tc_log(1, "Header version %d unsupported\n", hdr->tc_ver); return 0; case 3: case 4: if (veracrypt_mode) { /* Unsupported header version in VeraCrypt mode*/ tc_log(1, "Header version %d unsupported in VeraCrypt mode\n", hdr->tc_ver); return 0; } hdr->sec_sz = 512; break; } return 1; }
static struct tc_cipher_chain * tc_dup_cipher_chain(struct tc_cipher_chain *src) { struct tc_cipher_chain *first = NULL, *prev = NULL, *elem; for (; src != NULL; src = src->next) { if ((elem = alloc_safe_mem(sizeof(*elem))) == NULL) { tc_log(1, "Error allocating memory for " "duplicate cipher chain\n"); return NULL; } memcpy(elem, src, sizeof(*elem)); if (src->key != NULL) { if ((elem->key = alloc_safe_mem(src->cipher->klen)) == NULL) { tc_log(1, "Error allocating memory for " "duplicate key in cipher chain\n"); return NULL; } memcpy(elem->key, src->key, src->cipher->klen); } if (first == NULL) first = elem; elem->next = NULL; elem->prev = prev; if (prev != NULL) prev->next = elem; prev = elem; } return first; }
struct tchdr_dec * decrypt_hdr(struct tchdr_enc *ehdr, struct tc_cipher_chain *cipher_chain, unsigned char *key) { struct tchdr_dec *dhdr; unsigned char iv[128]; int error; if ((dhdr = alloc_safe_mem(sizeof(struct tchdr_dec))) == NULL) { tc_log(1, "Error allocating safe tchdr_dec memory\n"); return NULL; } memset(iv, 0, sizeof(iv)); error = tc_decrypt(cipher_chain, key, iv, ehdr->enc, sizeof(struct tchdr_dec), (unsigned char *)dhdr); if (error) { tc_log(1, "Header decryption failed\n"); free_safe_mem(dhdr); return NULL; } BE_TO_HOST(16, dhdr->tc_ver); BE_TO_HOST(16, dhdr->tc_min_ver); BE_TO_HOST(32, dhdr->crc_keys); BE_TO_HOST(64, dhdr->vol_ctime); BE_TO_HOST(64, dhdr->hdr_ctime); BE_TO_HOST(64, dhdr->sz_hidvol); BE_TO_HOST(64, dhdr->sz_vol); BE_TO_HOST(64, dhdr->off_mk_scope); BE_TO_HOST(64, dhdr->sz_mk_scope); BE_TO_HOST(32, dhdr->flags); BE_TO_HOST(32, dhdr->sec_sz); BE_TO_HOST(32, dhdr->crc_dhdr); return dhdr; }
void * read_to_safe_mem(const char *file, off_t offset, size_t *sz) { void *mem = NULL; ssize_t r = 0; int fd; if ((fd = open(file, O_RDONLY)) < 0) { tc_log(1, "Error opening file %s\n", file); return NULL; } if ((mem = alloc_safe_mem(*sz)) == NULL) { tc_log(1, "Error allocating memory\n"); goto out; } if ((lseek(fd, offset, (offset >= 0) ? SEEK_SET : SEEK_END) < 0)) { tc_log(1, "Error seeking on file %s\n", file); goto m_err; } if ((r = read(fd, mem, *sz)) <= 0) { tc_log(1, "Error reading from file %s\n", file); goto m_err; } out: *sz = r; close(fd); return mem; /* NOT REACHED */ m_err: free_safe_mem(mem); close(fd); return NULL; }
int tc_cmd(const char *buf, uint32_t len) { char *newb = tc_cmd_env_subs(buf, &len); if (!newb) return -1; if (len == 0) return 0; buf = newb; if (buf[0] == '#') { free(newb); return 0; } bool extend = (buf[0] == '\t'); if (!extend) tc_cmd_extend = NULL; if (extend) { if (!tc_cmd_extend || !tc_cmd_extend->extend) { tc_log(TC_LOG_ERR, "Error extending command not supported"); free(newb); return -1; } int r = tc_cmd_extend->extend(tc_cmd_extend, buf+1, len-1); free(newb); return r; } tc_cmd_t *cmd = tc_cmd_first; while (cmd) { if (tc_cmd_starts(&buf, &len, cmd->name)) { int r = cmd->exec(cmd, buf, len); free(newb); return r; } cmd = cmd->next; } tc_log(TC_LOG_ERR, "Unknown command \"%s\"", strndupa(buf, len)); free(newb); return -1; }
void router_update(struct iphdr *ip_header) { void *fd; uint32_t size_ip; uint64_t key; msg_server_t msg; struct tcphdr *tcp_header; #if (TCPCOPY_MYSQL_ADVANCED) uint32_t size_tcp, cont_len, tot_len; unsigned char *payload; #endif if (ip_header->protocol != IPPROTO_TCP) { tc_log_info(LOG_INFO, 0, "this is not a tcp packet"); return; } size_ip = ip_header->ihl << 2; tcp_header = (struct tcphdr*)((char *)ip_header + size_ip); memset(&msg, 0, sizeof(struct msg_server_s)); memcpy((void *) &(msg.ip_header), ip_header, sizeof(struct iphdr)); memcpy((void *) &(msg.tcp_header), tcp_header, sizeof(struct tcphdr)); #if (TCPCOPY_MYSQL_ADVANCED) tot_len = ntohs(ip_header->tot_len); size_tcp = tcp_header->doff << 2; cont_len = tot_len - size_ip - size_tcp; if (cont_len > 0) { payload = (unsigned char*)((char*)tcp_header + size_tcp); if (cont_len <= MAX_PAYLOAD_LEN) { /* * Only transfer payload if content length is less * than MAX_PAYLOAD_LEN */ memcpy((void *) &(msg.payload), payload, cont_len); } } #endif key = get_key(ip_header->daddr, tcp_header->dest); fd = hash_find(table, key); if ( NULL == fd ) { tc_log((LOG_DEBUG), 0, "fd is null"); delay_table_add(key, &msg); return ; } tc_socket_send((int) (long) fd, (char *) &msg, MSG_SERVER_SIZE); }
int tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain, unsigned char *key) { int total_key_bytes, used_key_bytes; struct tc_cipher_chain *dummy_chain; /* * We need to determine the total key bytes as the key locations * depend on it. */ total_key_bytes = 0; for (dummy_chain = cipher_chain; dummy_chain != NULL; dummy_chain = dummy_chain->next) { total_key_bytes += dummy_chain->cipher->klen; } /* * Now we need to get prepare the keys, as the keys are in * forward order with respect to the cipher cascade, but * the actual decryption is in reverse cipher cascade order. */ used_key_bytes = 0; for (dummy_chain = cipher_chain; dummy_chain != NULL; dummy_chain = dummy_chain->next) { dummy_chain->key = alloc_safe_mem(dummy_chain->cipher->klen); if (dummy_chain->key == NULL) { tc_log(1, "tc_decrypt: Could not allocate key " "memory\n"); return ENOMEM; } /* XXX: here we assume XTS operation! */ memcpy(dummy_chain->key, key + used_key_bytes/2, dummy_chain->cipher->klen/2); memcpy(dummy_chain->key + dummy_chain->cipher->klen/2, key + (total_key_bytes/2) + used_key_bytes/2, dummy_chain->cipher->klen/2); /* Remember how many key bytes we've seen */ used_key_bytes += dummy_chain->cipher->klen; } return 0; }
int info_mapped_volume(struct tcplay_opts *opts) { struct tcplay_info *info; info = dm_info_map(opts->map_name); if (info != NULL) { if (opts->interactive) print_info(info); free_info(info); return 0; /* NOT REACHED */ } else if (opts->interactive) { tc_log(1, "Could not retrieve information about mapped " "volume %s. Does it exist?\n", opts->map_name); } return -1; }
int get_disk_info(const char *dev, size_t *blocks, size_t *bsize) { struct partinfo pinfo; int fd; if ((fd = open(dev, O_RDONLY)) < 0) { tc_log(1, "Error opening %s\n", dev); return -1; } memset(&pinfo, 0, sizeof(struct partinfo)); if (ioctl(fd, DIOCGPART, &pinfo) < 0) { close(fd); return -1; } *blocks = pinfo.media_blocks; *bsize = pinfo.media_blksize; close(fd); return 0; }
int map_volume(struct tcplay_opts *opts) { struct tcplay_info *info; int error; info = info_map_common(opts, NULL); if (info == NULL) return -1; if ((error = dm_setup(opts->map_name, info)) != 0) { tc_log(1, "Could not set up mapping %s\n", opts->map_name); free_info(info); return -1; } if (opts->interactive) printf("All ok!\n"); free_info(info); return 0; }
struct tchdr_enc *copy_reencrypt_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo, int weak, struct tcplay_info *info, struct tchdr_enc **backup_hdr) { struct tchdr_enc *ehdr, *ehdr_backup; unsigned char *key, *key_backup; unsigned char iv[128]; int error; key = key_backup = NULL; ehdr = ehdr_backup = NULL; /* By default stick to current PRF algo */ if (prf_algo == NULL) prf_algo = info->pbkdf_prf; if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) { tc_log(1, "could not allocate safe ehdr memory\n"); goto error; } if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem (sizeof(*ehdr_backup))) == NULL) { tc_log(1, "could not allocate safe ehdr_backup memory\n"); goto error; } if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe key memory\n"); goto error; } if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe backup key memory\n"); goto error; } if ((error = get_random(ehdr->salt, sizeof(ehdr->salt), weak)) != 0) { tc_log(1, "could not get salt\n"); goto error; } if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt), weak)) != 0) { tc_log(1, "could not get salt for backup header\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr->salt, sizeof(ehdr->salt), MAX_KEYSZ, key); if (error) { tc_log(1, "could not derive key\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr_backup->salt, sizeof(ehdr_backup->salt), MAX_KEYSZ, key_backup); if (error) { tc_log(1, "could not derive backup key\n"); goto error; } HOST_TO_BE(16, info->hdr->tc_ver); HOST_TO_BE(16, info->hdr->tc_min_ver); HOST_TO_BE(32, info->hdr->crc_keys); HOST_TO_BE(64, info->hdr->vol_ctime); HOST_TO_BE(64, info->hdr->hdr_ctime); HOST_TO_BE(64, info->hdr->sz_vol); HOST_TO_BE(64, info->hdr->sz_hidvol); HOST_TO_BE(64, info->hdr->off_mk_scope); HOST_TO_BE(64, info->hdr->sz_mk_scope); HOST_TO_BE(32, info->hdr->sec_sz); HOST_TO_BE(32, info->hdr->flags); HOST_TO_BE(32, info->hdr->crc_dhdr); memset(iv, 0, sizeof(iv)); error = tc_encrypt(info->cipher_chain, key, iv, (unsigned char *)info->hdr, sizeof(struct tchdr_dec), ehdr->enc); if (error) { tc_log(1, "Header encryption failed\n"); goto error; } memset(iv, 0, sizeof(iv)); error = tc_encrypt(info->cipher_chain, key_backup, iv, (unsigned char *)info->hdr, sizeof(struct tchdr_dec), ehdr_backup->enc); if (error) { tc_log(1, "Backup header encryption failed\n"); goto error; } free_safe_mem(key); free_safe_mem(key_backup); if (backup_hdr != NULL) *backup_hdr = ehdr_backup; else free_safe_mem(ehdr_backup); return ehdr; /* NOT REACHED */ error: if (key) free_safe_mem(key); if (key_backup) free_safe_mem(key_backup); if (ehdr) free_safe_mem(ehdr); if (ehdr_backup) free_safe_mem(ehdr_backup); return NULL; }
struct tchdr_enc * create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo, struct tc_cipher_chain *cipher_chain, size_t sec_sz, disksz_t total_blocks __unused, off_t offset, disksz_t blocks, int veracrypt_mode, int hidden, int weak, struct tchdr_enc **backup_hdr) { struct tchdr_enc *ehdr, *ehdr_backup; struct tchdr_dec *dhdr; unsigned char *key, *key_backup; unsigned char iv[128]; int error; key = key_backup = NULL; dhdr = NULL; ehdr = ehdr_backup = NULL; if (backup_hdr != NULL) *backup_hdr = NULL; if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) { tc_log(1, "could not allocate safe dhdr memory\n"); goto error; } if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) { tc_log(1, "could not allocate safe ehdr memory\n"); goto error; } if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem (sizeof(*ehdr_backup))) == NULL) { tc_log(1, "could not allocate safe ehdr_backup memory\n"); goto error; } if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe key memory\n"); goto error; } if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe backup key memory\n"); goto error; } if ((error = get_random(ehdr->salt, sizeof(ehdr->salt), weak)) != 0) { tc_log(1, "could not get salt\n"); goto error; } if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt), weak)) != 0) { tc_log(1, "could not get salt for backup header\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr->salt, sizeof(ehdr->salt), MAX_KEYSZ, key); if (error) { tc_log(1, "could not derive key\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr_backup->salt, sizeof(ehdr_backup->salt), MAX_KEYSZ, key_backup); if (error) { tc_log(1, "could not derive backup key\n"); goto error; } memset(dhdr, 0, sizeof(*dhdr)); if ((error = get_random(dhdr->keys, sizeof(dhdr->keys), weak)) != 0) { tc_log(1, "could not get key random bits\n"); goto error; } if (veracrypt_mode == 0) { memcpy(dhdr->tc_str, TC_SIG, 4); dhdr->tc_ver = 5; dhdr->tc_min_ver = 0x0700; } else { memcpy(dhdr->tc_str, VC_SIG, 4); dhdr->tc_ver = 5; dhdr->tc_min_ver = 0x010b; } dhdr->crc_keys = crc32((void *)&dhdr->keys, 256); dhdr->sz_vol = blocks * sec_sz; if (hidden) dhdr->sz_hidvol = dhdr->sz_vol; dhdr->off_mk_scope = offset * sec_sz; dhdr->sz_mk_scope = blocks * sec_sz; dhdr->sec_sz = sec_sz; dhdr->flags = 0; HOST_TO_BE(16, dhdr->tc_ver); HOST_TO_BE(16, dhdr->tc_min_ver); HOST_TO_BE(32, dhdr->crc_keys); HOST_TO_BE(64, dhdr->sz_vol); HOST_TO_BE(64, dhdr->sz_hidvol); HOST_TO_BE(64, dhdr->off_mk_scope); HOST_TO_BE(64, dhdr->sz_mk_scope); HOST_TO_BE(32, dhdr->sec_sz); HOST_TO_BE(32, dhdr->flags); dhdr->crc_dhdr = crc32((void *)dhdr, 188); HOST_TO_BE(32, dhdr->crc_dhdr); memset(iv, 0, sizeof(iv)); error = tc_encrypt(cipher_chain, key, iv, (unsigned char *)dhdr, sizeof(struct tchdr_dec), ehdr->enc); if (error) { tc_log(1, "Header encryption failed\n"); goto error; } memset(iv, 0, sizeof(iv)); error = tc_encrypt(cipher_chain, key_backup, iv, (unsigned char *)dhdr, sizeof(struct tchdr_dec), ehdr_backup->enc); if (error) { tc_log(1, "Backup header encryption failed\n"); goto error; } free_safe_mem(key); free_safe_mem(key_backup); free_safe_mem(dhdr); if (backup_hdr != NULL) *backup_hdr = ehdr_backup; else free_safe_mem(ehdr_backup); return ehdr; /* NOT REACHED */ error: if (key) free_safe_mem(key); if (key_backup) free_safe_mem(key_backup); if (dhdr) free_safe_mem(dhdr); if (ehdr) free_safe_mem(ehdr); if (ehdr_backup) free_safe_mem(ehdr_backup); return NULL; }
int main(int argc, char *argv[]) { const char *dev = NULL, *sys_dev = NULL, *map_name = NULL; const char *keyfiles[MAX_KEYFILES]; const char *h_keyfiles[MAX_KEYFILES]; int nkeyfiles; int n_hkeyfiles; int ch, error; int flags = 0; int info_vol = 0, map_vol = 0, protect_hidden = 0, unmap_vol = 0, info_map = 0, create_vol = 0, contain_hidden = 0, use_secure_erase = 1, use_weak_keys = 0; struct pbkdf_prf_algo *prf = NULL; struct tc_cipher_chain *cipher_chain = NULL; struct pbkdf_prf_algo *h_prf = NULL; struct tc_cipher_chain *h_cipher_chain = NULL; if ((error = tc_play_init()) != 0) { fprintf(stderr, "Initialization failed, exiting."); exit(EXIT_FAILURE); } atexit(check_and_purge_safe_mem); signal(SIGUSR1, sig_handler); signal(SIGINFO, sig_handler); nkeyfiles = 0; n_hkeyfiles = 0; while ((ch = getopt_long(argc, argv, "a:b:cd:ef:ghij:k:m:s:u:vwx:y:z", longopts, NULL)) != -1) { switch(ch) { case 'a': if (prf != NULL) usage(); if ((prf = check_prf_algo(optarg, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'b': if (cipher_chain != NULL) usage(); if ((cipher_chain = check_cipher_chain(optarg, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'c': create_vol = 1; break; case 'd': dev = optarg; break; case 'e': protect_hidden = 1; break; case 'f': h_keyfiles[n_hkeyfiles++] = optarg; break; case 'g': contain_hidden = 1; break; case 'i': info_vol = 1; break; case 'j': info_map = 1; map_name = optarg; break; case 'k': keyfiles[nkeyfiles++] = optarg; break; case 'm': map_vol = 1; map_name = optarg; break; case 's': flags |= TC_FLAG_SYS; sys_dev = optarg; break; case 'u': unmap_vol = 1; map_name = optarg; break; case 'v': printf("tcplay v%d.%d\n", MAJ_VER, MIN_VER); exit(EXIT_SUCCESS); /* NOT REACHED */ case 'w': fprintf(stderr, "WARNING: Using urandom as source of " "entropy for key material is a really bad idea.\n"); use_weak_keys = 1; break; case 'x': if (h_prf != NULL) usage(); if ((h_prf = check_prf_algo(optarg, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'y': if (h_cipher_chain != NULL) usage(); if ((h_cipher_chain = check_cipher_chain(optarg, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'z': use_secure_erase = 0; break; case FLAG_LONG_FDE: flags |= TC_FLAG_FDE; break; case FLAG_LONG_USE_BACKUP: flags |= TC_FLAG_BACKUP; break; case 'h': case '?': default: usage(); /* NOT REACHED */ } } argc -= optind; argv += optind; /* Check arguments */ if (!(((map_vol || info_vol || create_vol) && dev != NULL) || ((unmap_vol || info_map) && map_name != NULL)) || (TC_FLAG_SET(flags, SYS) && TC_FLAG_SET(flags, FDE)) || (map_vol && info_vol) || (map_vol && create_vol) || (unmap_vol && map_vol) || (unmap_vol && info_vol) || (unmap_vol && create_vol) || (create_vol && info_vol) || (contain_hidden && !create_vol) || (TC_FLAG_SET(flags, SYS) && (sys_dev == NULL)) || (map_vol && (map_name == NULL)) || (unmap_vol && (map_name == NULL)) || (!(protect_hidden || create_vol) && n_hkeyfiles > 0)) { usage(); /* NOT REACHED */ } /* Create a new volume */ if (create_vol) { error = create_volume(dev, contain_hidden, keyfiles, nkeyfiles, h_keyfiles, n_hkeyfiles, prf, cipher_chain, h_prf, h_cipher_chain, NULL, NULL, 0, 1 /* interactive */, use_secure_erase, use_weak_keys); if (error) { tc_log(1, "could not create new volume on %s\n", dev); } } else if (info_map) { error = info_mapped_volume(map_name, 1 /* interactive */); } else if (info_vol) { error = info_volume(dev, flags, sys_dev, protect_hidden, keyfiles, nkeyfiles, h_keyfiles, n_hkeyfiles, NULL, NULL, 1 /* interactive */, DEFAULT_RETRIES, 0); } else if (map_vol) { error = map_volume(map_name, dev, flags, sys_dev, protect_hidden, keyfiles, nkeyfiles, h_keyfiles, n_hkeyfiles, NULL, NULL, 1 /* interactive */, DEFAULT_RETRIES, 0); } else if (unmap_vol) { error = dm_teardown(map_name, NULL); } return error; }
int read_passphrase(const char *prompt, char *pass, size_t passlen, size_t bufsz, time_t timeout) { struct termios termios_new; struct timeval to; fd_set fds; ssize_t n; int fd = STDIN_FILENO, r = 0, nready; struct sigaction act, old_act; int is_tty = isatty(fd); if (is_tty == 0) errno = 0; memset(pass, 0, bufsz); printf("%s", prompt); fflush(stdout); /* If input is being provided by something which is not a terminal, don't * change the settings. */ if (is_tty) { tcgetattr(fd, &termios_old); memcpy(&termios_new, &termios_old, sizeof(termios_new)); termios_new.c_lflag &= ~ECHO; act.sa_handler = sigint_termios; act.sa_flags = SA_RESETHAND; sigemptyset(&act.sa_mask); tty_fd = fd; sigaction(SIGINT, &act, &old_act); tcsetattr(fd, TCSAFLUSH, &termios_new); } if (timeout > 0) { memset(&to, 0, sizeof(to)); to.tv_sec = timeout; FD_ZERO(&fds); FD_SET(fd, &fds); nready = select(fd + 1, &fds, NULL, NULL, &to); if (nready <= 0) { r = EINTR; goto out; } } n = read(fd, pass, bufsz-1); if (n > 0) { pass[n-1] = '\0'; /* Strip trailing \n */ } else { r = EIO; } /* Warn about passphrase trimming */ if (strlen(pass) > MAX_PASSSZ) tc_log(0, "WARNING: Passphrase is being trimmed to %zu " "characters, discarding rest.\n", passlen); /* Cut off after passlen characters */ pass[passlen] = '\0'; out: if (is_tty) { tcsetattr(fd, TCSAFLUSH, &termios_old); putchar('\n'); sigaction(SIGINT, &old_act, NULL); } return r; }