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
|
||||
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;
|
||||
FILE *input, *strm;
|
||||
|
@ -575,22 +575,28 @@ get_pw_string(char pw[MAX_PW_LEN], char *prompt)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s (once more): ", prompt);
|
||||
fflush(stderr);
|
||||
s = fgets(pw2, MAX_PW_LEN, input);
|
||||
tcsetattr(fd, TCSANOW, &oldt);
|
||||
fflush(strm);
|
||||
fputs("\n", stderr);
|
||||
if (twice) {
|
||||
fprintf(stderr, "%s (once more): ", prompt);
|
||||
fflush(stderr);
|
||||
s = fgets(pw2, MAX_PW_LEN, input);
|
||||
tcsetattr(fd, TCSANOW, &oldt);
|
||||
fflush(strm);
|
||||
fputs("\n", stderr);
|
||||
|
||||
if (s == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
if (s == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (strcmp(pw1, pw2) != 0) {
|
||||
fprintf(stderr, "Passwords do not match!\n");
|
||||
memset(pw1, 0, MAX_PW_LEN);
|
||||
memset(pw2, 0, MAX_PW_LEN);
|
||||
return (-1);
|
||||
if (strcmp(pw1, pw2) != 0) {
|
||||
fprintf(stderr, "Passwords do not match!\n");
|
||||
memset(pw1, 0, MAX_PW_LEN);
|
||||
memset(pw2, 0, MAX_PW_LEN);
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
tcsetattr(fd, TCSANOW, &oldt);
|
||||
fflush(strm);
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
|
||||
len = strlen(pw1);
|
||||
|
|
|
@ -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);
|
||||
void crypto_clean_pkey(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.
|
||||
|
|
78
main.c
78
main.c
|
@ -292,6 +292,32 @@ redo:
|
|||
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;
|
||||
_chunksize = tdat->chunksize;
|
||||
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) {
|
||||
pw_len = get_pw_string(pw,
|
||||
"Please enter encryption password");
|
||||
"Please enter decryption password", 0);
|
||||
if (pw_len == -1) {
|
||||
memset(salt2, 0, saltlen);
|
||||
free(salt2);
|
||||
|
@ -680,6 +706,7 @@ start_decompress(const char *filename, const char *to_filename)
|
|||
perror(" ");
|
||||
memset(salt2, 0, saltlen);
|
||||
free(salt2);
|
||||
close(uncompfd); unlink(to_filename);
|
||||
err_exit(0, "Failed to get password.\n");
|
||||
}
|
||||
close(fd);
|
||||
|
@ -690,6 +717,7 @@ start_decompress(const char *filename, const char *to_filename)
|
|||
memset(salt2, 0, saltlen);
|
||||
free(salt2);
|
||||
memset(pw, 0, MAX_PW_LEN);
|
||||
close(uncompfd); unlink(to_filename);
|
||||
err_exit(0, "Failed to initialize crypto\n");
|
||||
}
|
||||
memset(salt2, 0, saltlen);
|
||||
|
@ -701,6 +729,7 @@ start_decompress(const char *filename, const char *to_filename)
|
|||
* Verify header HMAC.
|
||||
*/
|
||||
if (hmac_init(&hdr_mac, cksum, &crypto_ctx) == -1) {
|
||||
close(uncompfd); unlink(to_filename);
|
||||
err_exit(0, "Cannot initialize header hmac.\n");
|
||||
}
|
||||
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_cleanup(&hdr_mac);
|
||||
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 {
|
||||
mac_bytes = 0;
|
||||
|
@ -768,6 +798,13 @@ start_decompress(const char *filename, const char *to_filename)
|
|||
} else {
|
||||
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,
|
||||
(void *)tdat) != 0) {
|
||||
perror("Error in thread creation: ");
|
||||
|
@ -776,6 +813,11 @@ start_decompress(const char *filename, const char *to_filename)
|
|||
}
|
||||
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.wfd = uncompfd;
|
||||
w.nprocs = nprocs;
|
||||
|
@ -816,6 +858,7 @@ start_decompress(const char *filename, const char *to_filename)
|
|||
"file corrupt\n", chunk_num);
|
||||
UNCOMP_BAIL;
|
||||
}
|
||||
tdat->len_cmp_be = tdat->len_cmp; // Needed for HMAC
|
||||
tdat->len_cmp = htonll(tdat->len_cmp);
|
||||
|
||||
/*
|
||||
|
@ -1069,7 +1112,7 @@ plain_compress:
|
|||
*/
|
||||
if (encrypt_type) {
|
||||
/*
|
||||
* Encryption algorithm should not change the size and
|
||||
* Encryption algorithm must not change the size and
|
||||
* encryption is in-place.
|
||||
*/
|
||||
rv = crypto_buf(&crypto_ctx, compressed_chunk, compressed_chunk,
|
||||
|
@ -1120,6 +1163,22 @@ plain_compress:
|
|||
*/
|
||||
*(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:
|
||||
sem_post(&tdat->cmp_done_sem);
|
||||
goto redo;
|
||||
|
@ -1232,7 +1291,7 @@ start_compress(const char *filename, uint64_t chunksize, int level)
|
|||
compressed_chunksize += mac_bytes;
|
||||
if (!pwd_file) {
|
||||
pw_len = get_pw_string(pw,
|
||||
"Please enter encryption password");
|
||||
"Please enter encryption password", 1);
|
||||
if (pw_len == -1) {
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
(void *)tdat) != 0) {
|
||||
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_cleanup(&hdr_mac);
|
||||
|
||||
/* Erase encryption key bytes stored as a plain array. No longer reqd. */
|
||||
crypto_clean_pkey(&crypto_ctx);
|
||||
|
||||
pos = cread_buf;
|
||||
*((int *)pos) = htonl(crypto_ctx.saltlen);
|
||||
pos += sizeof (int);
|
||||
|
@ -1631,6 +1699,8 @@ comp_done:
|
|||
sem_post(&tdat->start_sem);
|
||||
sem_post(&tdat->cmp_done_sem);
|
||||
pthread_join(tdat->thr, NULL);
|
||||
if (encrypt_type)
|
||||
hmac_cleanup(&tdat->chunk_hmac);
|
||||
}
|
||||
pthread_join(writer_thr, NULL);
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ struct cmp_data {
|
|||
dedupe_context_t *rctx;
|
||||
ssize_t rbytes;
|
||||
ssize_t chunksize;
|
||||
ssize_t len_cmp;
|
||||
ssize_t len_cmp, len_cmp_be;
|
||||
uchar_t checksum[CKSUM_MAX_BYTES];
|
||||
int level;
|
||||
unsigned int id;
|
||||
|
@ -175,6 +175,7 @@ struct cmp_data {
|
|||
sem_t write_done_sem;
|
||||
void *data;
|
||||
pthread_t thr;
|
||||
mac_ctx_t chunk_hmac;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Reference in a new issue