From 833cb417608eb138d3a9b99dc995c5c1aeffd1cd Mon Sep 17 00:00:00 2001 From: "@syxhe" Date: Sun, 30 Mar 2025 23:13:35 -0500 Subject: Create encryption functions that actually work --- src/arena.c | 4 +- src/arena.h | 2 +- src/encryption.c | 349 ++++++++++++++++++------------------------------------- src/encryption.h | 9 +- src/ll.c | 6 +- src/ll.h | 2 +- src/main.c | 20 +--- src/shared.c | 2 +- src/shared.h | 8 +- 9 files changed, 135 insertions(+), 267 deletions(-) diff --git a/src/arena.c b/src/arena.c index 62dbbf8..de3523b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -7,7 +7,7 @@ #include #include -#define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_ARENAS___ > 0) ? xcalloc((nmemb), (size)) : malloc((nmemb) * (size))) +#define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_ARENAS___ > 0) ? xmalloc((nmemb) * (size)) : malloc((nmemb) * (size))) typedef struct an { void *membase; @@ -150,7 +150,7 @@ simplearena * simplearena_init(size_t bytes) { return arena_init(bytes); } -void* simplearena_alloc(simplearena * const a, size_t bytes) { +void * simplearena_alloc(simplearena * const a, size_t bytes) { // The criteria to allocate new memory in arena_alloc is 'bytes > ((a->current)->allocated - (a->current)->used)', so if this // is true, just return NULL & set errno diff --git a/src/arena.h b/src/arena.h index e5be79a..331bbb1 100644 --- a/src/arena.h +++ b/src/arena.h @@ -20,7 +20,7 @@ int arena_free(arena **arena); int arena_clear(arena **arena); simplearena * simplearena_init(size_t bytes); -void* simplearena_alloc(simplearena * const a, size_t bytes); +void * simplearena_alloc(simplearena * const a, size_t bytes); int simplearena_free(simplearena **a); int simplearena_free(simplearena **a); diff --git a/src/encryption.c b/src/encryption.c index b75a119..a01d4ff 100644 --- a/src/encryption.c +++ b/src/encryption.c @@ -15,8 +15,7 @@ #include #include - -#if defined ___VXGG___ALWAYS_CHECK_LIBSODIUM___ && ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 +#if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 void naclfaildefault(void *none) { none = none; // Makes gcc happy if(___VXGG___VERBOSE_ERRORS___) @@ -50,32 +49,17 @@ void checksodium(void) { #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 checksodiumcb(NULL, NULL); #else + if(sodium_init() < 0) { - if(___VXGG___VERBOSE_ERRORS___) - error(1, ENOTSUP, "Couldn't initialize sodium for some reason. Quitting..."); - exit(EXIT_FAILURE); + errno = ENOTSUP; + XALLOC_EXIT("Couldn't initialize sodium for some reason. Quitting..."); } + #endif return; } -// To encrypt: -// 1- Create a temp file with the correct name in the root folder of the partition being encrypted -- - // 1.1- Detect the partition and find the root folder -- DONE || NOT NECESSARY - // 1.2- Create the temp file -- DONE -// 2- Encrypt the file's contents to the temp file -- - // 2.1- Open the file -- - // 2.2- Stream the file's contents into some encryption algo -- - // 2.2.1- Pick which encryption algo to use -- - // 2.2.2- Generate a key -- - // 2.2.2.1- Create a password to derrive a key from -- DONE - // 2.3- Pipe the output of the encryption into the temp file -- -// 3- Once the file has been encrypted, hard link it back to the original location, with the right name -- -// 4- Delete the original file -- -// 5- Delete the temp file -- - - int maketmp(const char * const dest) { return open(dest, (O_TMPFILE | O_WRONLY | O_CLOEXEC | O_SYNC), (S_IRUSR | S_IWUSR)); } @@ -85,8 +69,6 @@ int encrypttotmp(const char * const target, const char * const output, const uns checksodium(); #endif - unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; - crypto_secretstream_xchacha20poly1305_state state; int fd = -1, tfd = -1; // Open the target file @@ -97,74 +79,124 @@ int encrypttotmp(const char * const target, const char * const output, const uns 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) { + if(tfd < 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; + return -1; } - // 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; - } + FILE *src, *dst; + if(!(src = fdopen(fd, "rb"))) + ERROR(1, errno, "Couldn't open \"%s\"", , target); + if(!(dst = fdopen(tfd, "wb"))) + ERROR(1, errno, "Couldn't open \"%s\"", , output); + if(encryptToFile(src, dst, key) < 0) + ERROR(1, ENOTRECOVERABLE, "I don't even have a way to cause an error here. How did you do it?",); // Link the temp file into the system char *path = NULL; asprintf(&path, "/proc/self/fd/%d", tfd); - if(!path) { - close(tfd); - return -8; - } + if(!path) + return -1; + 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); + fclose(dst); + fclose(src); + // fclose alco closes fd and tfd, as fdopen does not dup the file descriptors + + return 0; +} + +int encrypttofile(FILE *dst, FILE *src, unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { + unsigned char buf[CHUNKSIZE], cbuf[CHUNKSIZE + crypto_secretstream_xchacha20poly1305_ABYTES]; + unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; + crypto_secretstream_xchacha20poly1305_state state; + unsigned long long cbuflen; + unsigned char tag; + size_t bytesread; + FILE *dst, *src; + int eof; + + #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 + checksodium(); + #endif + + if(!src) + RETURNWERR(EINVAL, -1); + if(!dst) + RETURNWERR(EINVAL, -1); + if(!key) + RETURNWERR(EINVAL, -1); + + // Write the header + crypto_secretstream_xchacha20poly1305_init_push(&state, header, key); + if(fwrite(header, 1, sizeof(header), dst) < sizeof(header)) + if(ferror(dst)) + ERROR(1, errno, "Could not write header to \"%s\"",); + + // Encrypt each chunk + do { + if((bytesread = fread(buf, 1, sizeof(buf), src)) < sizeof(buf)) + if(ferror(src)) + ERROR(1, errno, "Could not read from source \"%s\"",); + eof = feof(src); + tag = eof ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0; + + crypto_secretstream_xchacha20poly1305_push(&state, cbuf, &cbuflen, buf, bytesread, NULL, 0, tag); + if(fwrite(cbuf, 1, (size_t)cbuflen, dst) < (size_t)cbuflen) + if(ferror(dst)) + ERROR(1, errno, "Could not write to target \"%s\"",); + } while (!eof); + + return 0; +} + +int decrypttofile(FILE *dst, FILE *src, unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { + unsigned char cbuf[CHUNKSIZE + crypto_secretstream_xchacha20poly1305_ABYTES], buf[CHUNKSIZE]; + unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; + crypto_secretstream_xchacha20poly1305_state state; + unsigned long long buflen; + unsigned char tag; + size_t bytesread; + FILE *dst, *src; + int eof; + + + if(!src) + RETURNWERR(EINVAL, -1); + if(!dst) + RETURNWERR(EINVAL, -1); + if(!key) + RETURNWERR(EINVAL, -1); + + // Read the header + if(fread(header, 1, sizeof(header), src) < sizeof(header)) + if(ferror(src)) + ERROR(1, errno, "Couldn't read header", ); + + // Make sure the header isn't fuckey + if(crypto_secretstream_xchacha20poly1305_init_pull(&state, header, key) != 0) + ERROR(1, errno, "Incomplete header", ); + + // Decrypt each chunk + do { + if((bytesread = fread(cbuf, 1, sizeof(cbuf), src)) < sizeof(cbuf)) + if(ferror(src)) + ERROR(1, errno, "Ran into problem reading for decryption", ); + eof = feof(src); + + if (crypto_secretstream_xchacha20poly1305_pull(&state, buf, &buflen, &tag, cbuf, bytesread, NULL, 0) != 0) + ERROR(1, errno, "Corrupted chunk", ); + + if(tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !eof) + ERROR(1, errno, "End of stream before end of file", ); + if(eof && tag != crypto_secretstream_xchacha20poly1305_TAG_FINAL) + ERROR(1, errno, "End of file before end of stream", ); + + fwrite(buf, 1, (size_t)buflen, dst); + } while(! eof); return 0; } @@ -211,9 +243,8 @@ void* xsodium_malloc(size_t size) { return mem; } -#define TESTING -#ifdef TESTING +#ifdef TESTING int main(void) { /*// Example code for creating a temp file, writing to it, then linking it back into the fs const char *dir = ".", *testmsg = "we do a little testing\n"; @@ -284,160 +315,6 @@ int main(void) { //*/// - //*// 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; - int fd = -1; - - // Message is just going to be a bunch of words from the dictionary - checksodium(); - if(genpassword(&message, 1000) < 0) - error(1, errno, "Could not generate message to be encrypted"); - if(!message) - abort(); - - // Get the temp file and write the message into it - if((fd = maketmp(dir)) < 0) - error(1, errno, "Could not make temp file to write to"); - - // Write to the file and link it into the system - remove(fname); // Make sure the new file can be linked into - write(fd, message, strlen(message)); - asprintf(&path, "/proc/self/fd/%d", fd); - if(!path) - abort(); - linkat(AT_FDCWD, path, AT_FDCWD, fname, AT_SYMLINK_FOLLOW); - - free(path); - free(message); - close(fd); - - - // Time for encryption - unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; - unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]; - crypto_secretstream_xchacha20poly1305_state state; - unsigned char salt[crypto_pwhash_SALTBYTES]; - - // Generate a salt for derriving the key - randombytes_buf(salt, sizeof(salt)); - - // Derrive the key from the password - if(crypto_pwhash(key, sizeof(key), pass, strlen(pass), salt, crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE, crypto_pwhash_ALG_DEFAULT) != 0) - error(1, ENOMEM, "Not enough memory to generate a key"); - - // Initialize the encryption stream's state - crypto_secretstream_xchacha20poly1305_init_push(&state, header, key); - - - // Deal with getting the file - if((fd = open(fname, O_RDONLY)) < 0) - error(1, errno, "Could not open test file to encrypt"); - int tfd = -1; - if((tfd = maketmp(dir)) < 0) // Only because linking temp files is being annoying - error(1, errno, "Could not open temp file for encryption"); - - // Read chunks of the file, encrypt them, then write them into the tmp file - ssize_t bytesread = -1; - // 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) - error(1, errno, "write() error"); - - if(bytesread == 0) - break; - } - if(bytesread < 0) - error(1, errno, "read() error"); - - close(fd); - - asprintf(&efname, "%s.enc", fname); - asprintf(&path, "/proc/self/fd/%d", tfd); - if(!path || !efname) - abort(); - remove(efname); // Make sure an old version isn't sticking around - linkat(AT_FDCWD, path, AT_FDCWD, efname, AT_SYMLINK_FOLLOW); - - close(tfd); - free(path); - free(buf); - free(cbuf); - - //*/// - - //*// 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 418e7f6..1bdd2b9 100644 --- a/src/encryption.h +++ b/src/encryption.h @@ -1,12 +1,14 @@ #ifndef __VXGG_REWRITE___ENCRYPTION_H___1481879318188___ #define __VXGG_REWRITE___ENCRYPTION_H___1481879318188___ +#include + // Determines whether any function that calls libsodium functions also checks to make sure libsodium is actually initialized. May // cause unexpected issues with early exiting due to libsodium failing to initialize properly. It's recommended that you just // 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)) +#define CHUNKSIZE (1 << 9) // TODO: What the fuck was I thinking when I did any of this callback shit? Make this a different macro and decouple it from ALWAYS_CHECK #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 @@ -82,4 +84,9 @@ void checksodium(void); // open() with the flags O_TMPFILE, O_WRONLY, O_CLOEXEC, and O_SYNC. Opened with mode S_IRUSR, S_IWUSR int maketmp(const char * const dest); +int encrypttofile(FILE *dst, FILE *src, unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]); +int decrypttofile(FILE *dst, FILE *src, unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +int encrypttotmp(const char * const target, const char * const output, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + #endif \ No newline at end of file diff --git a/src/ll.c b/src/ll.c index b02c275..5e67244 100644 --- a/src/ll.c +++ b/src/ll.c @@ -22,7 +22,7 @@ typedef struct dlinked { } dlinkedlist; -dllnode* dllnode_init(void *data, dll_freecb fcb) { +dllnode * dllnode_init(void *data, dll_freecb fcb) { dllnode *n = xcalloc(1, sizeof(*n)); n->data = data; n->freecb = fcb; @@ -46,7 +46,7 @@ int dllnode_free(dllnode **n) { return 0; } -dlinkedlist* dlinkedlist_init(void) { +dlinkedlist * dlinkedlist_init(void) { dlinkedlist *ll = xcalloc(1, sizeof(*ll)); ll->end = NULL; ll->start = NULL; @@ -135,7 +135,7 @@ int dlinkedlist_prepend(dlinkedlist * const ll, void *data, dll_freecb fcb) { return dlinkedlist_xxxend(ll, data, fcb, 'p'); } -dllnode* dlinkedlist_getnode(const dlinkedlist * const ll, int index) { +dllnode * dlinkedlist_getnode(const dlinkedlist * const ll, int index) { if(!ll) RETURNWERR(EINVAL, NULL); if(index < 0 || index >= ll->size) diff --git a/src/ll.h b/src/ll.h index 3d8ecc1..497d47b 100644 --- a/src/ll.h +++ b/src/ll.h @@ -24,7 +24,7 @@ typedef int (*dll_freecb)(void*); typedef struct dlinked dlinkedlist; -dlinkedlist* dlinkedlist_init(void); +dlinkedlist * dlinkedlist_init(void); int dlinkedlist_free(dlinkedlist **ll); int dlinkedlist_append(dlinkedlist * const ll, void *data, dll_freecb fcb); int dlinkedlist_prepend(dlinkedlist * const ll, void *data, dll_freecb fcb); diff --git a/src/main.c b/src/main.c index d76e20d..fc1044a 100644 --- a/src/main.c +++ b/src/main.c @@ -10,25 +10,7 @@ #include #include int main() { - // error(1, ENOTSUP, "No main file lol"); - - // Testing Arena changes - const int DATA[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - arena *arena = arena_init(sizeof(DATA)); - if(!arena) - error(1, errno, "Could not initialize arena"); - - int *nums = arena_alloc(arena, sizeof(DATA)); - if(!nums) - error(1, errno, "Could not allocate memory"); - - memmove(nums, DATA, sizeof(DATA)); - for(unsigned int i = 0; i < STATIC_ARRAY_LEN(DATA); i++) - printf("%d ", nums[i]); - printf("\n"); - - arena_free(&arena); + error(1, ENOTSUP, "No main file lol"); return 0; } \ No newline at end of file diff --git a/src/shared.c b/src/shared.c index 771c44f..093e766 100644 --- a/src/shared.c +++ b/src/shared.c @@ -137,7 +137,7 @@ int wwbuf(int fd, const unsigned char *buf, int len) { // Thanks Beej! // dirname but less retarded hopefully -char *xdirname(const char * const path) { +char * xdirname(const char * const path) { char *tmp = NULL; if(!path) { // Path being null is a special case which should return super early, before anything else tmp = strdup("."); diff --git a/src/shared.h b/src/shared.h index 718bbf2..7d2db27 100644 --- a/src/shared.h +++ b/src/shared.h @@ -29,14 +29,16 @@ exit(EXIT_FAILURE); /* Makes gcc happy */\ } while (0) +#define ERROR(status, errnum, format, ...) do {error((status), (errnum), (format)__VA_ARGS__); exit((status));} while (0) + // `malloc()` with error checking. Calls `exit()` or `abort()` on error, depending on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___` void * xmalloc(size_t size); // `calloc()` with error checking. Calls `exit()` or `abort()` on error, depending on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___` -void* xcalloc(size_t nmemb, size_t size); +void * xcalloc(size_t nmemb, size_t size); // `reallocarray()` with error checking. Calls `exit()` or `abort()` on error, depending on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___` -void* xreallocarray(void *ptr, size_t nmemb, size_t size); +void * xreallocarray(void *ptr, size_t nmemb, size_t size); // Read the entire contents of a file descriptor into a malloc()'ed buffer int rwbuf(char **str, unsigned long int initsize, int fd); @@ -45,6 +47,6 @@ int rwbuf(char **str, unsigned long int initsize, int fd); int wwbuf(int fd, const unsigned char *buf, int len); // `dirname()` reimplementation that returns a malloc()'ed string. According to the `x___` naming scheme, exits/aborts on alloc error. -char *xdirname(const char * const path); +char * xdirname(const char * const path); #endif \ No newline at end of file -- cgit v1.2.3