Add 8 bytes of random data to the start of every encrypted compressed block and use it along with 8 bytes from the stored salt to make a unique key and IV for encryption.

This commit is contained in:
Con Kolivas 2011-03-18 00:06:11 +11:00
parent 9049263f6f
commit a3e80871c2
7 changed files with 69 additions and 44 deletions

38
lrzip.c
View file

@ -475,16 +475,16 @@ static void get_hash(rzip_control *control, int make_hash)
passphrase = calloc(PASS_LEN, 1); passphrase = calloc(PASS_LEN, 1);
testphrase = calloc(PASS_LEN, 1); testphrase = calloc(PASS_LEN, 1);
control->pass_hash = calloc(HASH_LEN, 1);
control->hash = calloc(HASH_LEN, 1); control->hash = calloc(HASH_LEN, 1);
control->hash_iv = calloc(SALT_LEN, 1); control->hash_iv = calloc(SALT_LEN, 1);
control->rehash_iv = calloc(SALT_LEN, 1); if (unlikely(!passphrase || !testphrase || !control->pass_hash || !control->hash || !control->hash_iv))
if (unlikely(!passphrase || !testphrase || !control->hash || !control->hash_iv || !control->rehash_iv))
fatal("Failed to calloc encrypt buffers in compress_file\n"); fatal("Failed to calloc encrypt buffers in compress_file\n");
mlock(passphrase, PASS_LEN); mlock(passphrase, PASS_LEN);
mlock(testphrase, PASS_LEN); mlock(testphrase, PASS_LEN);
mlock(control->pass_hash, HASH_LEN);
mlock(control->hash, HASH_LEN); mlock(control->hash, HASH_LEN);
mlock(control->hash_iv, SALT_LEN); mlock(control->hash_iv, SALT_LEN);
mlock(control->rehash_iv, SALT_LEN);
/* Disable stdin echo to screen */ /* Disable stdin echo to screen */
tcgetattr(fileno(stdin), &termios_p); tcgetattr(fileno(stdin), &termios_p);
@ -510,25 +510,18 @@ retry_pass:
free(testphrase); free(testphrase);
memcpy(passphrase + PASS_LEN - SALT_LEN, control->salt, SALT_LEN); memcpy(passphrase + PASS_LEN - SALT_LEN, control->salt, SALT_LEN);
sha4(passphrase, PASS_LEN, passphrase, 0); sha4(passphrase, PASS_LEN, control->pass_hash, 0);
print_maxverbose("Hashing passphrase %lld times\n", control->encloops); print_maxverbose("Hashing passphrase %lld times\n", control->encloops);
for (i = 0; i < control->encloops; i++) { for (i = 0; i < control->encloops; i++) {
for (j = 0; j < HASH_LEN; j++) for (j = 0; j < HASH_LEN; j++)
control->hash[j] ^= passphrase[j]; control->hash[j] ^= control->pass_hash[j];
sha4(control->hash, HASH_LEN, control->hash, 0); sha4(control->hash, HASH_LEN, control->hash, 0);
if (unlikely(i == control->encloops - 1024)) { if (unlikely(i == control->encloops - 1024)) {
for (j = 0; j < SALT_LEN; j++) for (j = 0; j < SALT_LEN; j++)
control->hash_iv[j] = control->hash[j]; control->hash_iv[j] = control->hash[j];
} }
} }
memcpy(control->rehash_iv, control->hash_iv, SALT_LEN);
memset(control->hash + SALT_LEN, 0, HASH_LEN - SALT_LEN);
munlock(control->hash + SALT_LEN, HASH_LEN - SALT_LEN);
control->hash = realloc(control->hash, SALT_LEN);
if (unlikely(!control->hash))
fatal("Failed to realloc control->hash in get_hash\n");
memset(passphrase, 0, PASS_LEN); memset(passphrase, 0, PASS_LEN);
munlock(passphrase, PASS_LEN); munlock(passphrase, PASS_LEN);
free(passphrase); free(passphrase);
@ -536,13 +529,13 @@ retry_pass:
static void release_hashes(rzip_control *control) static void release_hashes(rzip_control *control)
{ {
memset(control->pass_hash, 0, HASH_LEN);
memset(control->hash, 0, SALT_LEN); memset(control->hash, 0, SALT_LEN);
memset(control->hash_iv, 0, SALT_LEN); memset(control->hash_iv, 0, SALT_LEN);
memset(control->rehash_iv, 0, SALT_LEN);
munlockall(); munlockall();
free(control->pass_hash);
free(control->hash); free(control->hash);
free(control->hash_iv); free(control->hash_iv);
free(control->rehash_iv);
} }
/* /*
@ -678,11 +671,8 @@ void decompress_file(rzip_control *control)
print_verbose("CRC32 "); print_verbose("CRC32 ");
print_verbose("being used for integrity testing.\n"); print_verbose("being used for integrity testing.\n");
if (ENCRYPT) { if (ENCRYPT)
get_hash(control, 0); get_hash(control, 0);
if (unlikely(aes_setkey_dec(&control->aes_ctx, control->hash, 128)))
failure("Failed to aes_setkey_dec in decompress_file\n");
}
print_progress("Decompressing...\n"); print_progress("Decompressing...\n");
@ -876,8 +866,15 @@ next_chunk:
} while (last_head); } while (last_head);
++stream; ++stream;
} }
if (ENCRYPT) {
if (unlikely((ofs = lseek(fd_in, c_len + 8, SEEK_CUR)) == -1))
fatal("Failed to lseek c_len in get_fileinfo\n");
} else {
if (unlikely((ofs = lseek(fd_in, c_len, SEEK_CUR)) == -1)) if (unlikely((ofs = lseek(fd_in, c_len, SEEK_CUR)) == -1))
fatal("Failed to lseek c_len in get_fileinfo\n"); fatal("Failed to lseek c_len in get_fileinfo\n");
}
/* Chunk byte entry */ /* Chunk byte entry */
if (control->major_version == 0 && control->minor_version > 4) { if (control->major_version == 0 && control->minor_version > 4) {
if (unlikely(read(fd_in, &chunk_byte, 1) != 1)) if (unlikely(read(fd_in, &chunk_byte, 1) != 1))
@ -969,11 +966,8 @@ void compress_file(rzip_control *control)
int fd_in, fd_out; int fd_in, fd_out;
char header[MAGIC_LEN]; char header[MAGIC_LEN];
if (ENCRYPT) { if (ENCRYPT)
get_hash(control, 1); get_hash(control, 1);
if (unlikely(aes_setkey_enc(&control->aes_ctx, control->hash, 128)))
failure("Failed to aes_setkey_enc in compress_file\n");
}
memset(header, 0, sizeof(header)); memset(header, 0, sizeof(header));
if (!STDIN) { if (!STDIN) {

View file

@ -201,9 +201,9 @@ struct rzip_control {
i64 encloops; i64 encloops;
i64 secs; i64 secs;
uchar salt[16]; uchar salt[16];
uchar *pass_hash;
uchar *hash; uchar *hash;
uchar *hash_iv; uchar *hash_iv;
uchar *rehash_iv;
aes_context aes_ctx; aes_context aes_ctx;
unsigned char eof; unsigned char eof;
unsigned char magic_written; unsigned char magic_written;

View file

@ -377,7 +377,7 @@ i64 runzip_fd(rzip_control *control, int fd_in, int fd_out, int fd_hist, i64 exp
if (unlikely(read_1g(control, fd_in, md5_stored, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE)) if (unlikely(read_1g(control, fd_in, md5_stored, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
fatal("Failed to read md5 data in runzip_fd\n"); fatal("Failed to read md5 data in runzip_fd\n");
if (ENCRYPT) if (ENCRYPT)
lrz_crypt(control, md5_stored, MD5_DIGEST_SIZE, 0, 1); lrz_crypt(control, md5_stored, MD5_DIGEST_SIZE, control->hash_iv, 0);
for (i = 0; i < MD5_DIGEST_SIZE; i++) for (i = 0; i < MD5_DIGEST_SIZE; i++)
if (md5_stored[i] != md5_resblock[i]) { if (md5_stored[i] != md5_resblock[i]) {
print_output("MD5 CHECK FAILED.\nStored:"); print_output("MD5 CHECK FAILED.\nStored:");

2
rzip.c
View file

@ -978,7 +978,7 @@ retry:
} }
/* When encrypting data, we encrypt the MD5 value as well */ /* When encrypting data, we encrypt the MD5 value as well */
if (ENCRYPT) if (ENCRYPT)
lrz_crypt(control, md5_resblock, MD5_DIGEST_SIZE, 1, 1); lrz_crypt(control, md5_resblock, MD5_DIGEST_SIZE, control->hash_iv, 1);
if (unlikely(write_1g(control, md5_resblock, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE)) if (unlikely(write_1g(control, md5_resblock, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
fatal("Failed to write md5 in rzip_fd\n"); fatal("Failed to write md5 in rzip_fd\n");

View file

@ -66,6 +66,7 @@ static struct compress_thread{
pthread_mutex_t mutex; /* This thread's mutex */ pthread_mutex_t mutex; /* This thread's mutex */
struct stream_info *sinfo; struct stream_info *sinfo;
int streamno; int streamno;
uchar salt[16];
} *cthread; } *cthread;
static struct uncomp_thread{ static struct uncomp_thread{
@ -1183,8 +1184,11 @@ retry:
get_rand(cti->s_buf + cti->c_len, MIN_SIZE - cti->c_len); get_rand(cti->s_buf + cti->c_len, MIN_SIZE - cti->c_len);
} }
if (!ret && ENCRYPT) if (!ret && ENCRYPT) {
lrz_crypt(control, cti->s_buf, padded_len, 1, 0); get_rand(cti->salt, 8);
memcpy(cti->salt + 8, control->salt + 8, 8);
lrz_crypt(control, cti->s_buf, padded_len, cti->salt, 1);
}
/* If compression fails for whatever reason multithreaded, then wait /* If compression fails for whatever reason multithreaded, then wait
* for the previous thread to finish, serialising the work to decrease * for the previous thread to finish, serialising the work to decrease
@ -1254,8 +1258,14 @@ retry:
} }
ctis->cur_pos += 25; ctis->cur_pos += 25;
if (ENCRYPT) {
ctis->cur_pos += 8;
if (unlikely(write_buf(control, ctis->fd, cti->salt, 8)))
fatal("Failed to write_buf salt in compthread %d\n", i);
}
if (unlikely(write_buf(control, ctis->fd, cti->s_buf, padded_len))) if (unlikely(write_buf(control, ctis->fd, cti->s_buf, padded_len)))
fatal("Failed to write_buf in compthread %d\n", i); fatal("Failed to write_buf s_buf in compthread %d\n", i);
ctis->cur_pos += padded_len; ctis->cur_pos += padded_len;
free(cti->s_buf); free(cti->s_buf);
@ -1380,6 +1390,7 @@ static int fill_buffer(rzip_control *control, struct stream_info *sinfo, int str
struct stream *s = &sinfo->s[streamno]; struct stream *s = &sinfo->s[streamno];
stream_thread_struct *st; stream_thread_struct *st;
uchar c_type, *s_buf; uchar c_type, *s_buf;
uchar salt[16];
if (s->buf) if (s->buf)
free(s->buf); free(s->buf);
@ -1419,6 +1430,14 @@ fill_another:
header_length = 25; header_length = 25;
} }
if (ENCRYPT) {
if (unlikely(read_buf(control, sinfo->fd, salt, 8))) {
print_err("Failed to read_buf salt in fill_buffer\n");
return -1;
}
memcpy(salt + 8, control->salt + 8, 8);
}
padded_len = MAX(c_len, MIN_SIZE); padded_len = MAX(c_len, MIN_SIZE);
fsync(control->fd_out); fsync(control->fd_out);
@ -1431,7 +1450,7 @@ fill_another:
return -1; return -1;
if (ENCRYPT) if (ENCRYPT)
lrz_crypt(control, s_buf, padded_len, 0, 0); lrz_crypt(control, s_buf, padded_len, salt, 0);
ucthread[s->uthread_no].s_buf = s_buf; ucthread[s->uthread_no].s_buf = s_buf;
ucthread[s->uthread_no].c_len = c_len; ucthread[s->uthread_no].c_len = c_len;

38
util.c
View file

@ -160,23 +160,34 @@ static void xor128 (void *pa, const void *pb)
a [1] ^= b [1]; a [1] ^= b [1];
} }
void lrz_crypt(rzip_control *control, uchar *buf, i64 len, int encrypt, int carry_iv) void lrz_crypt(rzip_control *control, uchar *buf, i64 len, uchar *salt, int encrypt)
{ {
/* Encryption requires CBC_LEN blocks so we can use ciphertext /* Encryption requires CBC_LEN blocks so we can use ciphertext
* stealing to not have to pad the block */ * stealing to not have to pad the block */
unsigned char ivec[CBC_LEN], tmp0[CBC_LEN], tmp1[CBC_LEN]; uchar ivec[80], tmp0[CBC_LEN], tmp1[CBC_LEN];
uchar key[80], iv[80];
i64 N, M; i64 N, M;
int i;
/* Generate unique key and IV for each block of data based on salt */
mlock(key, 80);
mlock(iv, 80);
for (i = 0; i < 64; i++)
key[i] = control->pass_hash[i] ^ control->hash[i];
memcpy(key + 64, salt, 16);
sha4(key, 80, key, 0);
for (i = 0; i < 64; i++)
ivec[i] = key[i] ^ control->pass_hash[i];
memcpy(ivec + 64, salt, 16);
sha4(ivec, 80, ivec, 0);
mlock(ivec, CBC_LEN);
if (carry_iv)
memcpy(ivec, control->rehash_iv, CBC_LEN);
else
memcpy(ivec, control->hash_iv, CBC_LEN);
M = len % CBC_LEN; M = len % CBC_LEN;
N = len - M; N = len - M;
if (encrypt) { if (encrypt) {
print_maxverbose("Encrypting data \n"); print_maxverbose("Encrypting data \n");
if (unlikely(aes_setkey_enc(&control->aes_ctx, key, 128)))
failure("Failed to aes_setkey_enc in lrz_crypt\n");
aes_crypt_cbc(&control->aes_ctx, AES_ENCRYPT, N, ivec, buf, buf); aes_crypt_cbc(&control->aes_ctx, AES_ENCRYPT, N, ivec, buf, buf);
if (M) { if (M) {
@ -188,6 +199,8 @@ void lrz_crypt(rzip_control *control, uchar *buf, i64 len, int encrypt, int carr
memcpy(buf + N - CBC_LEN, tmp1, CBC_LEN); memcpy(buf + N - CBC_LEN, tmp1, CBC_LEN);
} }
} else { } else {
if (unlikely(aes_setkey_dec(&control->aes_ctx, key, 128)))
failure("Failed to aes_setkey_dec in lrz_crypt\n");
print_maxverbose("Decrypting data \n"); print_maxverbose("Decrypting data \n");
if (M) { if (M) {
aes_crypt_cbc(&control->aes_ctx, AES_DECRYPT, N - CBC_LEN, aes_crypt_cbc(&control->aes_ctx, AES_DECRYPT, N - CBC_LEN,
@ -206,10 +219,9 @@ void lrz_crypt(rzip_control *control, uchar *buf, i64 len, int encrypt, int carr
aes_crypt_cbc(&control->aes_ctx, AES_DECRYPT, len, aes_crypt_cbc(&control->aes_ctx, AES_DECRYPT, len,
ivec, buf, buf); ivec, buf, buf);
} }
/* The carry_iv flag tells us if we want to update the value in
* control->rehash_iv for later encryption */ memset(ivec, 0, 80);
if (carry_iv) memset(key, 0, 80);
memcpy(control->rehash_iv, ivec, CBC_LEN); munlock(ivec, 80);
memset(ivec, 0, CBC_LEN); munlock(key, 80);
munlock(ivec, CBC_LEN);
} }

2
util.h
View file

@ -29,6 +29,6 @@ void fatal(const char *format, ...);
void failure(const char *format, ...); void failure(const char *format, ...);
void round_to_page(i64 *size); void round_to_page(i64 *size);
void get_rand(uchar *buf, int len); void get_rand(uchar *buf, int len);
void lrz_crypt(rzip_control *control, uchar *buf, i64 len, int encrypt, int carry_iv); void lrz_crypt(rzip_control *control, uchar *buf, i64 len, uchar *salt, int encrypt);
#endif #endif