Implement HMAC verification for chunk data and header.
Do not ask for decryption passwd twice.
This commit is contained in:
parent
d13aad830e
commit
1eb8c94fed
4 changed files with 98 additions and 21 deletions
|
@ -541,7 +541,7 @@ err0:
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
get_pw_string(char pw[MAX_PW_LEN], char *prompt)
|
get_pw_string(char pw[MAX_PW_LEN], char *prompt, int twice)
|
||||||
{
|
{
|
||||||
int fd, len;
|
int fd, len;
|
||||||
FILE *input, *strm;
|
FILE *input, *strm;
|
||||||
|
@ -575,6 +575,7 @@ get_pw_string(char pw[MAX_PW_LEN], char *prompt)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (twice) {
|
||||||
fprintf(stderr, "%s (once more): ", prompt);
|
fprintf(stderr, "%s (once more): ", prompt);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
s = fgets(pw2, MAX_PW_LEN, input);
|
s = fgets(pw2, MAX_PW_LEN, input);
|
||||||
|
@ -592,6 +593,11 @@ get_pw_string(char pw[MAX_PW_LEN], char *prompt)
|
||||||
memset(pw2, 0, MAX_PW_LEN);
|
memset(pw2, 0, MAX_PW_LEN);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
tcsetattr(fd, TCSANOW, &oldt);
|
||||||
|
fflush(strm);
|
||||||
|
fputs("\n", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
len = strlen(pw1);
|
len = strlen(pw1);
|
||||||
pw1[len-1] = '\0';
|
pw1[len-1] = '\0';
|
||||||
|
|
|
@ -85,7 +85,7 @@ int crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, ssize_t bytes, ui
|
||||||
uint64_t crypto_nonce(crypto_ctx_t *cctx);
|
uint64_t crypto_nonce(crypto_ctx_t *cctx);
|
||||||
void crypto_clean_pkey(crypto_ctx_t *cctx);
|
void crypto_clean_pkey(crypto_ctx_t *cctx);
|
||||||
void cleanup_crypto(crypto_ctx_t *cctx);
|
void cleanup_crypto(crypto_ctx_t *cctx);
|
||||||
int get_pw_string(char pw[MAX_PW_LEN], char *prompt);
|
int get_pw_string(char pw[MAX_PW_LEN], char *prompt, int twice);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HMAC functions.
|
* HMAC functions.
|
||||||
|
|
78
main.c
78
main.c
|
@ -292,6 +292,32 @@ redo:
|
||||||
goto cont;
|
goto cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify HMAC first before anything else.
|
||||||
|
*/
|
||||||
|
if (encrypt_type) {
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
len = mac_bytes;
|
||||||
|
deserialize_checksum(checksum, tdat->compressed_chunk + cksum_bytes, mac_bytes);
|
||||||
|
memset(tdat->compressed_chunk + cksum_bytes, 0, mac_bytes);
|
||||||
|
hmac_reinit(&tdat->chunk_hmac);
|
||||||
|
hmac_update(&tdat->chunk_hmac, (uchar_t *)&tdat->len_cmp_be, sizeof (tdat->len_cmp_be));
|
||||||
|
hmac_update(&tdat->chunk_hmac, tdat->compressed_chunk,
|
||||||
|
tdat->len_cmp + cksum_bytes + mac_bytes + CHUNK_FLAG_SZ);
|
||||||
|
hmac_final(&tdat->chunk_hmac, tdat->checksum, &len);
|
||||||
|
if (memcmp(checksum, tdat->checksum, len) != 0) {
|
||||||
|
/*
|
||||||
|
* HMAC verification failure is fatal.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "Chunk %d, HMAC verification failed\n", tdat->id);
|
||||||
|
main_cancel = 1;
|
||||||
|
tdat->len_cmp = 0;
|
||||||
|
sem_post(&tdat->cmp_done_sem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cseg = tdat->compressed_chunk + cksum_bytes + mac_bytes;
|
cseg = tdat->compressed_chunk + cksum_bytes + mac_bytes;
|
||||||
_chunksize = tdat->chunksize;
|
_chunksize = tdat->chunksize;
|
||||||
deserialize_checksum(tdat->checksum, tdat->compressed_chunk, cksum_bytes);
|
deserialize_checksum(tdat->checksum, tdat->compressed_chunk, cksum_bytes);
|
||||||
|
@ -644,7 +670,7 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
|
|
||||||
if (!pwd_file) {
|
if (!pwd_file) {
|
||||||
pw_len = get_pw_string(pw,
|
pw_len = get_pw_string(pw,
|
||||||
"Please enter encryption password");
|
"Please enter decryption password", 0);
|
||||||
if (pw_len == -1) {
|
if (pw_len == -1) {
|
||||||
memset(salt2, 0, saltlen);
|
memset(salt2, 0, saltlen);
|
||||||
free(salt2);
|
free(salt2);
|
||||||
|
@ -680,6 +706,7 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
perror(" ");
|
perror(" ");
|
||||||
memset(salt2, 0, saltlen);
|
memset(salt2, 0, saltlen);
|
||||||
free(salt2);
|
free(salt2);
|
||||||
|
close(uncompfd); unlink(to_filename);
|
||||||
err_exit(0, "Failed to get password.\n");
|
err_exit(0, "Failed to get password.\n");
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -690,6 +717,7 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
memset(salt2, 0, saltlen);
|
memset(salt2, 0, saltlen);
|
||||||
free(salt2);
|
free(salt2);
|
||||||
memset(pw, 0, MAX_PW_LEN);
|
memset(pw, 0, MAX_PW_LEN);
|
||||||
|
close(uncompfd); unlink(to_filename);
|
||||||
err_exit(0, "Failed to initialize crypto\n");
|
err_exit(0, "Failed to initialize crypto\n");
|
||||||
}
|
}
|
||||||
memset(salt2, 0, saltlen);
|
memset(salt2, 0, saltlen);
|
||||||
|
@ -701,6 +729,7 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
* Verify header HMAC.
|
* Verify header HMAC.
|
||||||
*/
|
*/
|
||||||
if (hmac_init(&hdr_mac, cksum, &crypto_ctx) == -1) {
|
if (hmac_init(&hdr_mac, cksum, &crypto_ctx) == -1) {
|
||||||
|
close(uncompfd); unlink(to_filename);
|
||||||
err_exit(0, "Cannot initialize header hmac.\n");
|
err_exit(0, "Cannot initialize header hmac.\n");
|
||||||
}
|
}
|
||||||
hmac_update(&hdr_mac, (uchar_t *)algo, ALGO_SZ);
|
hmac_update(&hdr_mac, (uchar_t *)algo, ALGO_SZ);
|
||||||
|
@ -715,7 +744,8 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
hmac_final(&hdr_mac, hdr_hash1, &hlen);
|
hmac_final(&hdr_mac, hdr_hash1, &hlen);
|
||||||
hmac_cleanup(&hdr_mac);
|
hmac_cleanup(&hdr_mac);
|
||||||
if (memcmp(hdr_hash2, hdr_hash1, mac_bytes) != 0) {
|
if (memcmp(hdr_hash2, hdr_hash1, mac_bytes) != 0) {
|
||||||
err_exit(0, "Header verification failed! File tampered.\n");
|
close(uncompfd); unlink(to_filename);
|
||||||
|
err_exit(0, "Header verification failed! File tampered or wrong password.\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mac_bytes = 0;
|
mac_bytes = 0;
|
||||||
|
@ -768,6 +798,13 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
} else {
|
} else {
|
||||||
tdat->rctx = NULL;
|
tdat->rctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (encrypt_type) {
|
||||||
|
if (hmac_init(&tdat->chunk_hmac, cksum, &crypto_ctx) == -1) {
|
||||||
|
fprintf(stderr, "Cannot initialize chunk hmac.\n");
|
||||||
|
UNCOMP_BAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (pthread_create(&(tdat->thr), NULL, perform_decompress,
|
if (pthread_create(&(tdat->thr), NULL, perform_decompress,
|
||||||
(void *)tdat) != 0) {
|
(void *)tdat) != 0) {
|
||||||
perror("Error in thread creation: ");
|
perror("Error in thread creation: ");
|
||||||
|
@ -776,6 +813,11 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
}
|
}
|
||||||
thread = 1;
|
thread = 1;
|
||||||
|
|
||||||
|
if (encrypt_type) {
|
||||||
|
/* Erase encryption key bytes stored as a plain array. No longer reqd. */
|
||||||
|
crypto_clean_pkey(&crypto_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
w.dary = dary;
|
w.dary = dary;
|
||||||
w.wfd = uncompfd;
|
w.wfd = uncompfd;
|
||||||
w.nprocs = nprocs;
|
w.nprocs = nprocs;
|
||||||
|
@ -816,6 +858,7 @@ start_decompress(const char *filename, const char *to_filename)
|
||||||
"file corrupt\n", chunk_num);
|
"file corrupt\n", chunk_num);
|
||||||
UNCOMP_BAIL;
|
UNCOMP_BAIL;
|
||||||
}
|
}
|
||||||
|
tdat->len_cmp_be = tdat->len_cmp; // Needed for HMAC
|
||||||
tdat->len_cmp = htonll(tdat->len_cmp);
|
tdat->len_cmp = htonll(tdat->len_cmp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1069,7 +1112,7 @@ plain_compress:
|
||||||
*/
|
*/
|
||||||
if (encrypt_type) {
|
if (encrypt_type) {
|
||||||
/*
|
/*
|
||||||
* Encryption algorithm should not change the size and
|
* Encryption algorithm must not change the size and
|
||||||
* encryption is in-place.
|
* encryption is in-place.
|
||||||
*/
|
*/
|
||||||
rv = crypto_buf(&crypto_ctx, compressed_chunk, compressed_chunk,
|
rv = crypto_buf(&crypto_ctx, compressed_chunk, compressed_chunk,
|
||||||
|
@ -1120,6 +1163,22 @@ plain_compress:
|
||||||
*/
|
*/
|
||||||
*(tdat->compressed_chunk) = type;
|
*(tdat->compressed_chunk) = type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If encrypting, compute HMAC for entire chunk (hdr + data)
|
||||||
|
*/
|
||||||
|
if (encrypt_type) {
|
||||||
|
uchar_t *mac_ptr;
|
||||||
|
unsigned int hlen;
|
||||||
|
uchar_t chash[mac_bytes];
|
||||||
|
|
||||||
|
/* Clean out mac_bytes to 0 for stable hash. */
|
||||||
|
mac_ptr = tdat->cmp_seg + sizeof (tdat->len_cmp) + cksum_bytes;
|
||||||
|
memset(mac_ptr, 0, mac_bytes);
|
||||||
|
hmac_reinit(&tdat->chunk_hmac);
|
||||||
|
hmac_update(&tdat->chunk_hmac, tdat->cmp_seg, tdat->len_cmp);
|
||||||
|
hmac_final(&tdat->chunk_hmac, chash, &hlen);
|
||||||
|
serialize_checksum(chash, mac_ptr, hlen);
|
||||||
|
}
|
||||||
cont:
|
cont:
|
||||||
sem_post(&tdat->cmp_done_sem);
|
sem_post(&tdat->cmp_done_sem);
|
||||||
goto redo;
|
goto redo;
|
||||||
|
@ -1232,7 +1291,7 @@ start_compress(const char *filename, uint64_t chunksize, int level)
|
||||||
compressed_chunksize += mac_bytes;
|
compressed_chunksize += mac_bytes;
|
||||||
if (!pwd_file) {
|
if (!pwd_file) {
|
||||||
pw_len = get_pw_string(pw,
|
pw_len = get_pw_string(pw,
|
||||||
"Please enter encryption password");
|
"Please enter encryption password", 1);
|
||||||
if (pw_len == -1) {
|
if (pw_len == -1) {
|
||||||
err_exit(1, "Failed to get password.\n");
|
err_exit(1, "Failed to get password.\n");
|
||||||
}
|
}
|
||||||
|
@ -1408,6 +1467,12 @@ start_compress(const char *filename, uint64_t chunksize, int level)
|
||||||
tdat->rctx = NULL;
|
tdat->rctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (encrypt_type) {
|
||||||
|
if (hmac_init(&tdat->chunk_hmac, cksum, &crypto_ctx) == -1) {
|
||||||
|
fprintf(stderr, "Cannot initialize chunk hmac.\n");
|
||||||
|
COMP_BAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (pthread_create(&(tdat->thr), NULL, perform_compress,
|
if (pthread_create(&(tdat->thr), NULL, perform_compress,
|
||||||
(void *)tdat) != 0) {
|
(void *)tdat) != 0) {
|
||||||
perror("Error in thread creation: ");
|
perror("Error in thread creation: ");
|
||||||
|
@ -1466,6 +1531,9 @@ start_compress(const char *filename, uint64_t chunksize, int level)
|
||||||
hmac_final(&hdr_mac, hdr_hash, &hlen);
|
hmac_final(&hdr_mac, hdr_hash, &hlen);
|
||||||
hmac_cleanup(&hdr_mac);
|
hmac_cleanup(&hdr_mac);
|
||||||
|
|
||||||
|
/* Erase encryption key bytes stored as a plain array. No longer reqd. */
|
||||||
|
crypto_clean_pkey(&crypto_ctx);
|
||||||
|
|
||||||
pos = cread_buf;
|
pos = cread_buf;
|
||||||
*((int *)pos) = htonl(crypto_ctx.saltlen);
|
*((int *)pos) = htonl(crypto_ctx.saltlen);
|
||||||
pos += sizeof (int);
|
pos += sizeof (int);
|
||||||
|
@ -1631,6 +1699,8 @@ comp_done:
|
||||||
sem_post(&tdat->start_sem);
|
sem_post(&tdat->start_sem);
|
||||||
sem_post(&tdat->cmp_done_sem);
|
sem_post(&tdat->cmp_done_sem);
|
||||||
pthread_join(tdat->thr, NULL);
|
pthread_join(tdat->thr, NULL);
|
||||||
|
if (encrypt_type)
|
||||||
|
hmac_cleanup(&tdat->chunk_hmac);
|
||||||
}
|
}
|
||||||
pthread_join(writer_thr, NULL);
|
pthread_join(writer_thr, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ struct cmp_data {
|
||||||
dedupe_context_t *rctx;
|
dedupe_context_t *rctx;
|
||||||
ssize_t rbytes;
|
ssize_t rbytes;
|
||||||
ssize_t chunksize;
|
ssize_t chunksize;
|
||||||
ssize_t len_cmp;
|
ssize_t len_cmp, len_cmp_be;
|
||||||
uchar_t checksum[CKSUM_MAX_BYTES];
|
uchar_t checksum[CKSUM_MAX_BYTES];
|
||||||
int level;
|
int level;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
@ -175,6 +175,7 @@ struct cmp_data {
|
||||||
sem_t write_done_sem;
|
sem_t write_done_sem;
|
||||||
void *data;
|
void *data;
|
||||||
pthread_t thr;
|
pthread_t thr;
|
||||||
|
mac_ctx_t chunk_hmac;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
Loading…
Reference in a new issue