Permalink
Browse files

make blksz agnostic, fix volume size

 * Make everything blksz agnostic, so that tcplay also works on disks
   with non-512-byte sectors. This hasn't been tested yet but *should*
   work.

 * Fix the volume size, which was 256 sectors too big before (as I
   wasn't considering the space at the end of the volume for the backup
   headers).

 * Change the /dev/random reader to read in smaller chunks and report
   progress.

 * Bump version to 0.9
  • Loading branch information...
1 parent ba6c404 commit 92f96b883b8548162a44b78ef4748fb566c5b6e4 @bwalex committed Jul 22, 2011
Showing with 113 additions and 27 deletions.
  1. +62 −3 io.c
  2. +2 −2 tcplay.3
  3. +37 −14 tcplay.c
  4. +8 −4 tcplay.h
  5. +2 −2 tcplay_api.c
  6. +1 −1 tcplay_api.h
  7. +1 −1 tcplay_api_test.c
View
65 io.c
@@ -85,12 +85,27 @@ read_to_safe_mem(const char *file, off_t offset, size_t *sz)
return NULL;
}
+static size_t get_random_total_bytes = 0;
+static size_t get_random_read_bytes = 0;
+
+static
+void
+get_random_summary(void)
+{
+ float pct_done;
+
+ pct_done = (1.0 * get_random_read_bytes) /
+ (1.0 * get_random_total_bytes) * 100.0;
+ tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done);
+}
+
int
get_random(unsigned char *buf, size_t len)
{
int fd;
ssize_t r;
size_t rd = 0;
+ size_t sz;
struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
@@ -99,17 +114,30 @@ get_random(unsigned char *buf, size_t len)
return -1;
}
+ summary_fn = get_random_summary;
+ get_random_total_bytes = len;
+
+ /* Get random data in 16-byte chunks */
+ sz = 16;
while (rd < len) {
- if ((r = read(fd, buf+rd, len-rd)) < 0) {
+ get_random_read_bytes = rd;
+
+ if ((len - rd) < sz)
+ sz = (len - rd);
+
+ if ((r = read(fd, buf+rd, sz)) < 0) {
tc_log(1, "Error reading from /dev/random\n");
close(fd);
+ summary_fn = NULL;
return -1;
}
rd += r;
nanosleep(&ts, NULL);
}
close(fd);
+ summary_fn = NULL;
+
return 0;
}
@@ -249,12 +277,40 @@ get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
#endif
int
-write_mem(const char *dev, off_t offset, size_t blksz __unused, void *mem,
+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;
@@ -266,13 +322,16 @@ write_mem(const char *dev, off_t offset, size_t blksz __unused, void *mem,
return -1;
}
- if ((w = write(fd, mem, bytes)) <= 0) {
+ 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;
}
View
4 tcplay.3
@@ -99,7 +99,7 @@ typedef struct tc_api_opts {
char *tc_prf_hash;
char *tc_cipher_hidden;
char *tc_prf_hash_hidden;
- size_t tc_size_hidden_in_blocks;
+ size_t tc_size_hidden_in_bytes;
char *tc_passphrase_hidden;
const char **tc_keyfiles_hidden;
} tc_api_opts;
@@ -145,7 +145,7 @@ and
.Fa tc_keyfiles
respectively.
If
-.Fa tc_size_hidden_in_blocks
+.Fa tc_size_hidden_in_bytes
is not zero, a hidden volume of the given size will be created, using
the cipher specified by
.Fa tc_cipher_hidden
View
51 tcplay.c
@@ -230,6 +230,9 @@ print_info(struct tcplay_info *info)
printf("CRC Key Data:\t\t%#x\n", info->hdr->crc_keys);
printf("Sector size:\t\t%d\n", info->hdr->sec_sz);
printf("Volume size:\t\t%zu sectors\n", info->size);
+ printf("Volume offset:\t\t%"PRIu64"\n", (uint64_t)info->start);
+ printf("IV offset:\t\t%"PRIu64"\n", (uint64_t)info->skip);
+ printf("Block offset:\t\t%"PRIu64"\n", (uint64_t)info->offset);
}
static
@@ -370,7 +373,7 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
const char *h_keyfiles[], int n_hkeyfiles, struct pbkdf_prf_algo *prf_algo,
struct tc_cipher_chain *cipher_chain, struct pbkdf_prf_algo *h_prf_algo,
struct tc_cipher_chain *h_cipher_chain, char *passphrase,
- char *h_passphrase, size_t hidden_blocks_in, int interactive)
+ char *h_passphrase, size_t size_hidden_bytes_in, int interactive)
{
char *pass, *pass_again;
char *h_pass = NULL;
@@ -394,9 +397,9 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
return -1;
}
- if (blocks <= MIN_VOL_BLOCKS) {
+ if ((blocks*blksz) <= MIN_VOL_BYTES) {
tc_log(1, "Cannot create volumes on devices with less "
- "than %d blocks/sectors\n", MIN_VOL_BLOCKS);
+ "than %d bytes\n", MIN_VOL_BYTES);
return -1;
}
@@ -488,12 +491,19 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if (interactive) {
hidden_blocks = 0;
} else {
- hidden_blocks = hidden_blocks_in;
+ hidden_blocks = size_hidden_bytes_in/blksz;
if (hidden_blocks == 0) {
tc_log(1, "hidden_blocks to create volume "
"cannot be zero!\n");
return -1;
}
+
+ if (size_hidden_bytes_in >=
+ (blocks*blksz) - MIN_VOL_BYTES) {
+ tc_log(1, "Hidden volume needs to be "
+ "smaller than the outer volume\n");
+ return -1;
+ }
}
/* This only happens in interactive mode */
@@ -521,14 +531,15 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
return -1;
}
- hidden_blocks = (size_t)tmp;
- hidden_blocks /= blksz;
- if (hidden_blocks >= blocks - MIN_VOL_BLOCKS) {
+ if (tmp >= (blocks*blksz) - MIN_VOL_BYTES) {
tc_log(1, "Hidden volume needs to be "
"smaller than the outer volume\n");
hidden_blocks = 0;
continue;
}
+
+ hidden_blocks = (size_t)tmp;
+ hidden_blocks /= blksz;
}
}
@@ -565,8 +576,8 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
/* create encrypted headers */
ehdr = create_hdr((unsigned char *)pass,
(nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
- prf_algo, cipher_chain, blksz, blocks, MIN_VOL_BLOCKS,
- blocks-MIN_VOL_BLOCKS, 0);
+ prf_algo, cipher_chain, blksz, blocks, VOL_RSVD_BYTES_START/blksz,
+ blocks - (MIN_VOL_BYTES/blksz), 0);
if (ehdr == NULL) {
tc_log(1, "Could not create header\n");
return -1;
@@ -576,20 +587,22 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
hehdr = create_hdr((unsigned char *)h_pass,
(n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), h_prf_algo,
h_cipher_chain,
- blksz, blocks, blocks - hidden_blocks, hidden_blocks, 1);
+ blksz, blocks,
+ blocks - (VOL_RSVD_BYTES_END/blksz) - hidden_blocks,
+ hidden_blocks, 1);
if (hehdr == NULL) {
tc_log(1, "Could not create hidden volume header\n");
return -1;
}
}
- if ((error = write_mem(dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
+ if ((error = write_to_disk(dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
tc_log(1, "Could not write volume header to device\n");
return -1;
}
if (hidden) {
- if ((error = write_mem(dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
+ if ((error = write_to_disk(dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
sizeof(*hehdr))) != 0) {
tc_log(1, "Could not write hidden volume header to "
"device\n");
@@ -613,6 +626,12 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
char *h_pass;
int error, error2 = 0;
size_t sz;
+ size_t blocks, blksz;
+
+ if ((error = get_disk_info(dev, &blocks, &blksz)) != 0) {
+ tc_log(1, "could not get disk information\n");
+ return NULL;
+ }
info = NULL;
if (retries < 1)
@@ -679,7 +698,9 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
}
}
- sz = HDRSZ;
+ /* Always read blksz-sized chunks */
+ sz = blksz;
+
ehdr = (struct tchdr_enc *)read_to_safe_mem((sflag) ? sys_dev : dev,
(sflag) ? HDR_OFFSET_SYS : 0, &sz);
if (ehdr == NULL) {
@@ -688,7 +709,9 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
}
if (!sflag) {
- sz = HDRSZ;
+ /* Always read blksz-sized chunks */
+ sz = blksz;
+
hehdr = (struct tchdr_enc *)read_to_safe_mem(dev,
HDR_OFFSET_HIDDEN, &sz);
if (hehdr == NULL) {
View
12 tcplay.h
@@ -29,7 +29,7 @@
/* Version of tcplay */
#define MAJ_VER 0
-#define MIN_VER 8
+#define MIN_VER 9
#define MAX_BLKSZ 4096
@@ -43,7 +43,10 @@
#define MAX_KEYFILES 256
#define HDR_OFFSET_HIDDEN 65536
#define SALT_LEN 64
-#define MIN_VOL_BLOCKS 256
+#define VOL_RSVD_BYTES_START (256*512) /* Reserved bytes at vol. start */
+#define VOL_RSVD_BYTES_END (256*512) /* Reserved bytes at vol. end */
+#define MIN_VOL_BYTES (VOL_RSVD_BYTES_START + VOL_RSVD_BYTES_END)
+
#define MAX_CIPHER_CHAINS 64
#define DEFAULT_RETRIES 3
#define ERASE_BUFFER_SIZE 4*1024*1024 /* 4 MB */
@@ -135,7 +138,8 @@ void *read_to_safe_mem(const char *file, off_t offset, size_t *sz);
int get_random(unsigned char *buf, size_t len);
int secure_erase(const char *dev, size_t bytes, size_t blksz);
int get_disk_info(const char *dev, size_t *blocks, size_t *bsize);
-int write_mem(const char *dev, off_t offset, size_t blksz, void *mem, size_t bytes);
+int write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem,
+ size_t bytes);
int read_passphrase(const char *prompt, char *pass, size_t passlen,
time_t timeout);
@@ -186,7 +190,7 @@ int create_volume(const char *dev, int hidden, const char *keyfiles[],
int nkeyfiles, const char *h_keyfiles[], int n_hkeyfiles,
struct pbkdf_prf_algo *prf_algo, struct tc_cipher_chain *cipher_chain,
struct pbkdf_prf_algo *h_prf_algo, struct tc_cipher_chain *h_cipher_chain,
- char *passphrase, char *h_passphrase, size_t hidden_blocks_in,
+ char *passphrase, char *h_passphrase, size_t hidden_bytes_in,
int interactive);
int info_volume(const char *device, int sflag, const char *sys_dev,
int protect_hidden, const char *keyfiles[], int nkeyfiles,
View
4 tcplay_api.c
@@ -97,7 +97,7 @@ tc_api_create_volume(tc_api_opts *api_opts)
create_hidden = 0;
- if (api_opts->tc_size_hidden_in_blocks > 0) {
+ if (api_opts->tc_size_hidden_in_bytes > 0) {
create_hidden = 1;
for (n_hkeyfiles = 0; (n_hkeyfiles < MAX_KEYFILES) &&
(api_opts->tc_keyfiles_hidden != NULL) &&
@@ -114,7 +114,7 @@ tc_api_create_volume(tc_api_opts *api_opts)
check_prf_algo(api_opts->tc_prf_hash_hidden, 1),
check_cipher_chain(api_opts->tc_cipher_hidden, 1),
api_opts->tc_passphrase, api_opts->tc_passphrase_hidden,
- api_opts->tc_size_hidden_in_blocks, 0 /* non-interactive */);
+ api_opts->tc_size_hidden_in_bytes, 0 /* non-interactive */);
return (err) ? TC_ERR : TC_OK;
}
View
2 tcplay_api.h
@@ -47,7 +47,7 @@ typedef struct tc_api_opts {
char *tc_prf_hash;
char *tc_cipher_hidden;
char *tc_prf_hash_hidden;
- size_t tc_size_hidden_in_blocks;
+ size_t tc_size_hidden_in_bytes;
char *tc_passphrase_hidden;
const char **tc_keyfiles_hidden;
} tc_api_opts;
View
2 tcplay_api_test.c
@@ -19,7 +19,7 @@ main(void)
api_opts.tc_passphrase = "apitest2";
api_opts.tc_keyfiles = NULL;
api_opts.tc_keyfiles_hidden = NULL;
- api_opts.tc_size_hidden_in_blocks = 12000;
+ api_opts.tc_size_hidden_in_bytes = 12000*512;
api_opts.tc_passphrase_hidden = "apihidden";
api_opts.tc_cipher = "AES-256-XTS,TWOFISH-256-XTS,SERPENT-256-XTS";
api_opts.tc_cipher_hidden = "SERPENT-256-XTS,TWOFISH-256-XTS";

0 comments on commit 92f96b8

Please sign in to comment.