diff --git a/lrzip.c b/lrzip.c index 086c3a6..3fe651f 100644 --- a/lrzip.c +++ b/lrzip.c @@ -475,16 +475,16 @@ static void get_hash(rzip_control *control, int make_hash) passphrase = calloc(PASS_LEN, 1); testphrase = calloc(PASS_LEN, 1); + control->pass_hash = calloc(HASH_LEN, 1); control->hash = calloc(HASH_LEN, 1); control->hash_iv = calloc(SALT_LEN, 1); - control->rehash_iv = calloc(SALT_LEN, 1); - if (unlikely(!passphrase || !testphrase || !control->hash || !control->hash_iv || !control->rehash_iv)) + if (unlikely(!passphrase || !testphrase || !control->pass_hash || !control->hash || !control->hash_iv)) fatal("Failed to calloc encrypt buffers in compress_file\n"); mlock(passphrase, PASS_LEN); mlock(testphrase, PASS_LEN); + mlock(control->pass_hash, HASH_LEN); mlock(control->hash, HASH_LEN); mlock(control->hash_iv, SALT_LEN); - mlock(control->rehash_iv, SALT_LEN); /* Disable stdin echo to screen */ tcgetattr(fileno(stdin), &termios_p); @@ -510,25 +510,18 @@ retry_pass: free(testphrase); 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); for (i = 0; i < control->encloops; i++) { 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); if (unlikely(i == control->encloops - 1024)) { for (j = 0; j < SALT_LEN; 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); munlock(passphrase, PASS_LEN); free(passphrase); @@ -536,13 +529,13 @@ retry_pass: static void release_hashes(rzip_control *control) { + memset(control->pass_hash, 0, HASH_LEN); memset(control->hash, 0, SALT_LEN); memset(control->hash_iv, 0, SALT_LEN); - memset(control->rehash_iv, 0, SALT_LEN); munlockall(); + free(control->pass_hash); free(control->hash); free(control->hash_iv); - free(control->rehash_iv); } /* @@ -678,11 +671,8 @@ void decompress_file(rzip_control *control) print_verbose("CRC32 "); print_verbose("being used for integrity testing.\n"); - if (ENCRYPT) { + if (ENCRYPT) 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"); @@ -876,8 +866,15 @@ next_chunk: } while (last_head); ++stream; } - if (unlikely((ofs = lseek(fd_in, c_len, SEEK_CUR)) == -1)) + + 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)) fatal("Failed to lseek c_len in get_fileinfo\n"); + } + /* Chunk byte entry */ if (control->major_version == 0 && control->minor_version > 4) { if (unlikely(read(fd_in, &chunk_byte, 1) != 1)) @@ -969,11 +966,8 @@ void compress_file(rzip_control *control) int fd_in, fd_out; char header[MAGIC_LEN]; - if (ENCRYPT) { + if (ENCRYPT) 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)); if (!STDIN) { diff --git a/lrzip_private.h b/lrzip_private.h index 58d6e6f..6be8dad 100644 --- a/lrzip_private.h +++ b/lrzip_private.h @@ -201,9 +201,9 @@ struct rzip_control { i64 encloops; i64 secs; uchar salt[16]; + uchar *pass_hash; uchar *hash; uchar *hash_iv; - uchar *rehash_iv; aes_context aes_ctx; unsigned char eof; unsigned char magic_written; diff --git a/runzip.c b/runzip.c index 20d7f78..89dc0dc 100644 --- a/runzip.c +++ b/runzip.c @@ -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)) fatal("Failed to read md5 data in runzip_fd\n"); 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++) if (md5_stored[i] != md5_resblock[i]) { print_output("MD5 CHECK FAILED.\nStored:"); diff --git a/rzip.c b/rzip.c index c9e031f..8f6025b 100644 --- a/rzip.c +++ b/rzip.c @@ -978,7 +978,7 @@ retry: } /* When encrypting data, we encrypt the MD5 value as well */ 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)) fatal("Failed to write md5 in rzip_fd\n"); diff --git a/stream.c b/stream.c index d08b005..059cedc 100644 --- a/stream.c +++ b/stream.c @@ -66,6 +66,7 @@ static struct compress_thread{ pthread_mutex_t mutex; /* This thread's mutex */ struct stream_info *sinfo; int streamno; + uchar salt[16]; } *cthread; static struct uncomp_thread{ @@ -1183,8 +1184,11 @@ retry: get_rand(cti->s_buf + cti->c_len, MIN_SIZE - cti->c_len); } - if (!ret && ENCRYPT) - lrz_crypt(control, cti->s_buf, padded_len, 1, 0); + if (!ret && ENCRYPT) { + 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 * for the previous thread to finish, serialising the work to decrease @@ -1254,8 +1258,14 @@ retry: } 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))) - 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; 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]; stream_thread_struct *st; uchar c_type, *s_buf; + uchar salt[16]; if (s->buf) free(s->buf); @@ -1419,6 +1430,14 @@ fill_another: 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); fsync(control->fd_out); @@ -1431,7 +1450,7 @@ fill_another: return -1; 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].c_len = c_len; diff --git a/util.c b/util.c index 2fdce65..a272a74 100644 --- a/util.c +++ b/util.c @@ -160,23 +160,34 @@ static void xor128 (void *pa, const void *pb) 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 * 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; + 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; N = len - M; if (encrypt) { 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); 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); } } 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"); if (M) { 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, ivec, buf, buf); } - /* The carry_iv flag tells us if we want to update the value in - * control->rehash_iv for later encryption */ - if (carry_iv) - memcpy(control->rehash_iv, ivec, CBC_LEN); - memset(ivec, 0, CBC_LEN); - munlock(ivec, CBC_LEN); + + memset(ivec, 0, 80); + memset(key, 0, 80); + munlock(ivec, 80); + munlock(key, 80); } \ No newline at end of file diff --git a/util.h b/util.h index c6c75f3..f74a677 100644 --- a/util.h +++ b/util.h @@ -29,6 +29,6 @@ void fatal(const char *format, ...); void failure(const char *format, ...); void round_to_page(i64 *size); 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