From 7aab85b35f884344585101aedfbd3a922bdeeb19 Mon Sep 17 00:00:00 2001 From: "@syxhe" Date: Mon, 27 Jan 2025 17:18:01 -0600 Subject: Write encrypttotmp, fuck up decryption again --- src/encryption.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/encryption.h | 2 + src/shared.h | 6 +++ 3 files changed, 159 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/encryption.c b/src/encryption.c index e4fed1f..8b0ac83 100644 --- a/src/encryption.c +++ b/src/encryption.c @@ -83,12 +83,91 @@ int maketmp(const char * const dest) { return open(dest, (O_TMPFILE | O_WRONLY | O_CLOEXEC | O_SYNC), (S_IRUSR | S_IWUSR)); } -int encrypttotmp(const char * const target, const char * const output, const char * const password, int chunksize) { +int encrypttotmp(const char * const target, const char * const output, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { #if defined ___VXGG___ALWAYS_CHECK_LIBSODIUM___ && ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 checksodium(); #endif - + unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; + crypto_secretstream_xchacha20poly1305_state state; + int fd = -1, tfd = -1; + + // Open the target file + if((fd = open(target, O_RDONLY)) < 0) + return -1; + + // Create a temp file for writing + char *targetdir = xdirname(output); + tfd = maketmp(targetdir); + free(targetdir); + if(tfd < 0) + return -2; + + // Initialize crypto stuff + if(crypto_secretstream_xchacha20poly1305_init_push(&state, header, key) < 0) { + close(fd); + close(tfd); + return -3; + } + + ssize_t bytesread = -1; + unsigned char *buf = malloc(CHUNK_SIZE + 1); + unsigned char *cbuf = malloc((CHUNK_SIZE + 1) + crypto_secretstream_xchacha20poly1305_ABYTES); + if(!buf || !cbuf) { + close(fd); + close(tfd); + if(buf) + free(buf); + if(cbuf) + free(cbuf); + + return -4; + } + + // Write the header to the temp file before encrypting anything + if(writewholebuffer(tfd, header, sizeof(header)) < 0) { + close(fd); + close(tfd); + free(buf); + free(cbuf); + return -5; + } + + // Read a chunk at a time, encrypt it, then push it to the temp file + unsigned long long clen = 0; + while((bytesread = read(fd, buf, CHUNK_SIZE)) >= 0) { + crypto_secretstream_xchacha20poly1305_push(&state, cbuf, &clen, buf, bytesread, NULL, 0, (bytesread > 0) ? 0 : crypto_secretstream_xchacha20poly1305_TAG_FINAL); + if(writewholebuffer(tfd, cbuf, clen) < 0) { + close(fd); + close(tfd); + free(buf); + free(cbuf); + return -6; + } + + if(bytesread == 0) + break; + } + free(buf); + free(cbuf); + close(fd); + if(bytesread < 0) { + close(tfd); + return -7; + } + + // Link the temp file into the system + char *path = NULL; + asprintf(&path, "/proc/self/fd/%d", tfd); + if(!path) { + close(tfd); + return -8; + } + remove(output); // Make sure an old version isn't sticking around + linkat(AT_FDCWD, path, AT_FDCWD, output, AT_SYMLINK_FOLLOW); + + free(path); + close(tfd); return 0; } @@ -217,7 +296,7 @@ int main(void) { //*/// - /*// Example code for generating a key from a password and encrypting a test file + //*// Example code for generating a key from a password and encrypting a test file const char *dir = ".", *fname = "toBeEncrypted.test.txt", *pass = "this is a password"; char *path = NULL, *message = NULL, *efname = NULL; @@ -273,9 +352,14 @@ int main(void) { // Read chunks of the file, encrypt them, then write them into the tmp file ssize_t bytesread = -1; - const int CHUNK_SIZE = 4096; + // const int CHUNK_SIZE = 4096; unsigned char *buf = xcalloc(CHUNK_SIZE + 1, sizeof(*buf)); unsigned char *cbuf = xcalloc((CHUNK_SIZE + 1) + crypto_secretstream_xchacha20poly1305_ABYTES, sizeof(*cbuf)); + + // TODO: WRITE HEADER TO FILE SO IT'S A VALID STREAM AND NOT BULLSHIT LIKE IT IS NOW + if(writewholebuffer(tfd, header, sizeof(header)) < 0) + error(1, errno, "Could not write header to file"); + while((bytesread = read(fd, buf, CHUNK_SIZE)) >= 0) { crypto_secretstream_xchacha20poly1305_push(&state, cbuf, NULL, buf, bytesread, NULL, 0, (bytesread > 0) ? 0 : crypto_secretstream_xchacha20poly1305_TAG_FINAL); if(writewholebuffer(tfd, cbuf, bytesread) < 0) @@ -303,6 +387,69 @@ int main(void) { //*/// + //*// Sample code to decrypt a file using a password-generated key + // Hint - Make sure the previous code block is also uncommented, or this will not work + + char *dfname = NULL; + asprintf(&dfname, "%s.dec", efname); + + if((fd = open(efname, O_RDONLY)) < 0) + error(1, errno, "Could not open encrypted file for decrypting"); + if((tfd = maketmp(xdirname(dfname))) < 0) + error(1, errno, "Could not open temp file for holding decrypted data"); + + // Read header in from the file + memset(header, 0, sizeof(header)); + if(read(fd, header, sizeof(header)) < 0) + error(1, errno, "read() error while getting the header"); + + // Make sure the header is correct + crypto_secretstream_xchacha20poly1305_state nstate; + if(crypto_secretstream_xchacha20poly1305_init_pull(&nstate, header, key) != 0) + error(1, errno, "ran into a corrupted header"); + + bytesread = -1; unsigned long long mlen = 0; unsigned char tag = 0; + buf = xcalloc(CHUNK_SIZE + 1, sizeof(*buf)); + cbuf = xcalloc((CHUNK_SIZE + 1) + crypto_secretstream_xchacha20poly1305_ABYTES, sizeof(*cbuf)); + while((bytesread = read(fd, cbuf, (CHUNK_SIZE + 1) + crypto_secretstream_xchacha20poly1305_ABYTES)) >= 0) { + if(crypto_secretstream_xchacha20poly1305_pull(&nstate, buf, &mlen, &tag, cbuf, bytesread, NULL, 0) != 0) { + error(1, errno, "Ran into a corrupted chunk while decrypting"); + } + + // Do some error checking + if(tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && bytesread != 0) + error(1, errno, "Found an end tag before the end of the file"); + if(bytesread == 0 && tag != crypto_secretstream_xchacha20poly1305_TAG_FINAL) + error(1, errno, "Hit the end of the file before the end tag"); + if(writewholebuffer(tfd, buf, mlen) < 0) + error(1, errno, "Ran into a write() error while writing decrypted file contents to the tmp file"); + + + if(bytesread == 0) + break; + } + if(bytesread < 0) + error(1, errno, "read() error while decrypting"); + + // Link the temp file back into the system + asprintf(&path, "/proc/self/fd/%d", tfd); + if(!path) + abort(); + remove(dfname); // Make sure an old version isn't sticking around + linkat(AT_FDCWD, path, AT_FDCWD, dfname, AT_SYMLINK_FOLLOW); + + //*/// + + + /*// Sample code to encrypt a file using encrypttotmp + + unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]; + crypto_secretstream_xchacha20poly1305_keygen(key); + + encrypttotmp("main.c", "main.enc", key); + + //*/// + return 0; } diff --git a/src/encryption.h b/src/encryption.h index c780e2b..1c38141 100644 --- a/src/encryption.h +++ b/src/encryption.h @@ -6,6 +6,8 @@ // manually run `sodium_init()` in some main or init function of your own so that you can deal with a potential error yourself #define ___VXGG___ALWAYS_CHECK_LIBSODIUM___ 0 +#define CHUNK_SIZE ((int)(1 << 12)) + #if defined ___VXGG___ALWAYS_CHECK_LIBSODIUM___ && ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 // Definition for the callback function that fires when a call to checksodium fails diff --git a/src/shared.h b/src/shared.h index 9cdbd33..3c23676 100644 --- a/src/shared.h +++ b/src/shared.h @@ -24,6 +24,12 @@ void* xreallocarray(void *ptr, size_t nmemb, size_t size); // Read the entire contents of a file descriptor into a malloc()'ed buffer int readwholebuffer(char **str, unsigned long int initsize, int fd); +// Write the entire contents of a buffer into a file descriptor int writewholebuffer(int fd, const unsigned char *buf, int len); +// `dirname()` reimplementation that returns a malloc()'ed string. According to the `x___` naming scheme, exits on alloc error. +// `___VXGG___XALLOC_EXIT_ON_ERROR___` influences whether `exit()` or `abort()` is called on error, and `___VXGG___VERBOSE_ERRORS___` +// influences whether diagnostic error messages are printed +char *xdirname(const char * const path); + #endif \ No newline at end of file -- cgit v1.2.3