summaryrefslogtreecommitdiff
path: root/src/encryption.c
diff options
context:
space:
mode:
author@syxhe <https://t.me/syxhe>2025-06-11 19:39:52 -0500
committer@syxhe <https://t.me/syxhe>2025-06-11 19:39:52 -0500
commit1536f1e0287b8281014200ef6911b294272c4773 (patch)
tree4ba6faa9e7c30b8a6641189e98423a7a927f6d32 /src/encryption.c
parent28487272fdad654b72c843e04384953e6fbb806f (diff)
Start fixing the encryption scheme
Diffstat (limited to 'src/encryption.c')
-rw-r--r--src/encryption.c272
1 files changed, 216 insertions, 56 deletions
diff --git a/src/encryption.c b/src/encryption.c
index fd42929..a3f75d1 100644
--- a/src/encryption.c
+++ b/src/encryption.c
@@ -16,13 +16,15 @@
16 16
17#define _GNU_SOURCE 17#define _GNU_SOURCE
18 18
19#include "encryption.h"
20#include "shared.h" 19#include "shared.h"
20#include "encryption.h"
21#include "threadpool.h"
21 22
22#include <sodium.h> 23#include <sodium.h>
23 24
24#include <sys/types.h> 25#include <sys/types.h>
25#include <sys/stat.h> 26#include <sys/stat.h>
27#include <dirent.h>
26#include <stdarg.h> 28#include <stdarg.h>
27#include <string.h> 29#include <string.h>
28#include <unistd.h> 30#include <unistd.h>
@@ -34,19 +36,42 @@
34#if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 36#if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0
35#if ___VXGG___USE_CLS_CALLBACK___ > 0 37#if ___VXGG___USE_CLS_CALLBACK___ > 0
36 38
37void naclfaildefault(void *none) { 39/**
40 * @brief Default sodium init fail callback for use in `checksodiumcb()`
41 *
42 * @param none Unused param to fit callback spec
43 */
44static void naclfaildefault(void *none) {
38 none = none; // Makes gcc happy 45 none = none; // Makes gcc happy
39 if(___VXGG___VERBOSE_ERRORS___) 46 if(___VXGG___VERBOSE_ERRORS___)
40 error(1, ENOTSUP, "<naclfaildefault> Couldn't initialize sodium for some reason. Quitting..."); 47 error(1, ENOTSUP, "<naclfaildefault> Couldn't initialize sodium for some reason. Quitting...");
41 exit(EXIT_FAILURE); 48 exit(EXIT_FAILURE);
42} 49}
43 50
44int checksodiumcb(vxgg_naclfailcb const callback, void *data, unsigned char set) { 51/**
52 * @brief Internal function to deal with the `___VXGG___USE_CLS_CALLBACK___` macro
53 *
54 * `checksodiumcb()` runs the sodium function `sodium_init()` and on error calls the provided callback with the provided data. The
55 * callback and data default to `naclfaildefault` and `NULL`, but can be changed when the `set` parameter is non-zero. When `set`
56 * is zero, the sodium init check is preformed
57 *
58 * @note `checksodiumcb()` is ran when these conditions are true - 1: The `___VXGG___ALWAYS_CHECK_LIBSODIUM___` and `___VXGG___USE_CLS_CALLBACK___`
59 * macros are both greater than 0 when compiling, and 2: a function in `encryption.c` calls a function originating from sodium. This
60 * function exists as a way to deal with sodium failing yourself, instead of instantly calling `exit()`. If you don't care to handle
61 * it, or are initializing sodium yourself, this is unnecessary
62 *
63 * @param callback A callback to be ran when sodium fails to initialize itself. Ignored if `set` is zero. Must be non-null when `set` is non-zero
64 * @param data Data to be passed to the callback when it is fired. Ignored if `set` is zero. May be null
65 * @param set Flag on whether to check sodium or to set a new callback and data pair. Checks sodium when zero, sets callback & data when non-zero
66 * @retval int
67 */
68static int checksodiumcb(vxgg_naclfailcb const callback, void *data, unsigned char set) {
45 static vxgg_naclfailcb cb = naclfaildefault; 69 static vxgg_naclfailcb cb = naclfaildefault;
46 static void *usr = NULL; 70 static void *usr = NULL;
47 int ret; 71 int ret;
48 72
49 if(set) { 73 if(set) {
74 if(cb == NULL) ERRRET(EINVAL, -1);
50 cb = callback; 75 cb = callback;
51 usr = data; 76 usr = data;
52 return 2; // libsodium normally returns 1 if the library is already initialized, so this is to signal that the callback has been updated 77 return 2; // libsodium normally returns 1 if the library is already initialized, so this is to signal that the callback has been updated
@@ -68,7 +93,15 @@ void vxgg_setsodiumfailcb(vxgg_naclfailcb cb, void *data) {
68 93
69#endif 94#endif
70 95
71void checksodium(void) { 96/**
97 * @brief Simple function to check if sodium has been properly initialized
98 *
99 * `checksodium()` will run in functions located in `encryption.h` only when the macro `___VXGG___ALWAYS_CHECK_LIBSODIUM___` is greater
100 * than zero when compiling. It will call the `checksodiumcb()` function if compiled with the `___VXGG___USE_CLS_CALLBACK___` macro.
101 * When called, checksodium will run `sodium_init()`, and will either run the user-defined callback or `XALLOC_EXIT`.
102 *
103 */
104static void checksodium(void) {
72 #if ___VXGG___USE_CLS_CALLBACK___ > 0 105 #if ___VXGG___USE_CLS_CALLBACK___ > 0
73 checksodiumcb(NULL, NULL, 0); 106 checksodiumcb(NULL, NULL, 0);
74 #else 107 #else
@@ -103,42 +136,89 @@ int linkto(const char * const target, int tgfd) {
103 return res; 136 return res;
104} 137}
105 138
139
140static void __ucl_close(void *fd) {
141 if(!fd) return;
142 close(*(int*)fd);
143 *(int*)fd = -1;
144 return;
145}
146
147static void __ucl_fclose(void *file) {
148 if(!file) return;
149 fclose((FILE*)file);
150 return;
151}
152
106int encryptviatmp(const char * const target, const char * const output, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { 153int encryptviatmp(const char * const target, const char * const output, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) {
107 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 154 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0
108 checksodium(); 155 checksodium();
109 #endif 156 #endif
110 157
158 cleanup_CREATE(10);
111 int fd = -1, tfd = -1; 159 int fd = -1, tfd = -1;
160 FILE *src, *dst;
161 char *targetdir;
112 162
113 // Open the target file 163 // Open the target file
114 if((fd = open(target, O_RDONLY)) < 0) 164 if((fd = open(target, O_RDONLY)) < 0)
115 return -1; 165 return -1;
166 cleanup_REGISTER(__ucl_close, (void*)&fd);
116 167
117 // Create a temp file for writing 168 // Create a temp file for writing
118 char *targetdir = xdirname(output); 169 targetdir = vxdirname(output);
119 tfd = maketmp(targetdir); 170 if(!targetdir)
120 free(targetdir); 171 cleanup_MARK();
121 if(tfd < 0) { 172 cleanup_CNDREGISTER(free, targetdir);
122 close(fd); 173
123 return -1; 174 // Actually get the file descriptor for the temp file
124 } 175 cleanup_CNDEXEC(
125 176 tfd = maketmp(targetdir);
126 FILE *src, *dst; 177 if(tfd < 0)
127 if(!(src = fdopen(fd, "rb"))) 178 cleanup_MARK();
128 ERROR(1, errno, "<encryptviatmp> Couldn't open \"%s\"", , target); 179 cleanup_CNDREGISTER(__ucl_close, (void*)&tfd);
129 if(!(dst = fdopen(tfd, "wb"))) 180 );
130 ERROR(1, errno, "<encryptviatmp> Couldn't open \"%s\"", , output); 181
131 if(encrypttofile(src, dst, key) < 0) 182 // Create a FILE* version of the source fd
132 ERROR(1, ENOTRECOVERABLE, "<encryptviatmp> I don't even have a way to cause an error here. How did you do it?",); 183 cleanup_CNDEXEC(
133 184 if(!(src = fdopen(fd, "rb"))) {
134 // Link the temp file into the system 185 WARN(errno, "<encryptviatmp> Couldn't open \"%s\"", , target);
135 if(linkto(output, tfd) < 0) 186 cleanup_MARK();
136 ERROR(1, errno, "<encryptviatmp> Could not link \"%s\" into system after encryption", , output); 187 }
137 188 cleanup_CNDREGISTER(__ucl_fclose, (void*)&src);
138 fclose(dst); 189 )
139 fclose(src); 190
140 // fclose alco closes fd and tfd, as fdopen does not dup the file descriptors 191 // Create a FILE* version of the target fd
192 cleanup_CNDEXEC(
193 if(!(dst = fdopen(tfd, "wb"))) {
194 WARN(errno, "<encryptviatmp> Couldn't open \"%s\"", , output);
195 cleanup_MARK();
196 }
197 cleanup_CNDREGISTER(__ucl_fclose, (void*)dst);
198 );
199
200
201 // Do the encryption now that everything has been set up
202 cleanup_CNDEXEC(
203 // Not going to bother changing this, it probably is catastrophic if an error happens when it shouldn't
204 if(encrypttofile(src, dst, key) < 0)
205 ERROR(1, ENOTRECOVERABLE, "<encryptviatmp> I don't even have a way to cause an error here. How did you do it?",);
206
207 // Link the temp file into the system
208 if(linkto(output, tfd) < 0)
209 WARN(errno, "<encryptviatmp> Could not link \"%s\" into system after encryption", , output);
210
211 free(targetdir);
212 fclose(dst);
213 fclose(src);
214 // fclose alco closes fd and tfd, as fdopen does not dup the file descriptors
215 );
216
141 217
218 cleanup_CNDFIRE();
219 if(cleanup_ERRORFLAGGED)
220 return -1;
221
142 return 0; 222 return 0;
143} 223}
144 224
@@ -148,31 +228,64 @@ int decryptto(const char * const encrypted, const char * const target, const uns
148 checksodium(); 228 checksodium();
149 #endif 229 #endif
150 230
231 cleanup_CREATE(10);
151 FILE *src, *dst; 232 FILE *src, *dst;
152 if(!(src = fopen(encrypted, "rb"))) 233 int fdst;
153 ERROR(1, errno, "<decryptto> Could not open \"%s\" for decryption", , encrypted);
154
155 int fdst = maketmp(target);
156 if(!fdst)
157 ERROR(1, errno, "<decryptto> Could not get temp file for decryption", );
158 if(!(dst = fdopen(fdst, "wb")))
159 ERROR(1, errno, "<decryptto> Could not open \"%s\" for writing decrypted data", , target);
160
161 if(decrypttofile(src, dst, key) < 0)
162 ERROR(1, errno, "<decryptto> How did you even cause an error?",);
163
164 // Link temp into system
165 if(linkto(target, fdst) < 0)
166 ERROR(1, errno, "<decryptto> Could not link \"%s\" into system", , target);
167 234
168 fclose(dst); 235 // Open the source file
169 fclose(src); 236 if(!(src = fopen(encrypted, "rb"))) {
170 // fclose alco closes fd and tfd, as fdopen does not dup the file descriptors 237 WARN(errno, "<decryptto> Could not open \"%s\" for decryption", , encrypted);
238 return -1;
239 }
240 cleanup_REGISTER(__ucl_fclose, src);
241
242 // Get a temp descriptor for the temp file
243 cleanup_CNDEXEC(
244 fdst = maketmp(target);
245 if(!fdst) {
246 WARN(errno, "<decryptto> Could not get temp file for decryption", );
247 cleanup_MARK();
248 }
249 cleanup_CNDREGISTER(__ucl_close, (void*)&fdst);
250 );
251
252 // Open a FILE* version of the temp file
253 cleanup_CNDEXEC(
254 if(!(dst = fdopen(fdst, "wb"))) {
255 WARN(errno, "<decryptto> Could not open \"%s\" for writing decrypted data", , target);
256 cleanup_MARK();
257 }
258 cleanup_CNDREGISTER(__ucl_fclose, dst);
259 );
260
261 // Follow through with the rest of the decryption
262 cleanup_CNDEXEC(
263 if(decrypttofile(src, dst, key) < 0)
264 ERROR(1, errno, "<decryptto> How did you even cause an error?",);
265
266 // Link temp into system
267 if(linkto(target, fdst) < 0)
268 WARN(errno, "<decryptto> Could not link \"%s\" into system", , target);
269
270 fclose(dst);
271 fclose(src);
272 // fclose alco closes fd and tfd, as fdopen does not dup the file descriptors
273 );
274
275 cleanup_CNDFIRE();
276 if(cleanup_ERRORFLAGGED)
277 return -1;
171 278
279 // Note: If an error were to theoretically occur, which shouldn't be possible but I'm covering my bases here, after the
280 // `dst = fdopen` line, a double close on the temp file descriptor would occur. I've been told that this is not catastrophic,
281 // and considering how my multithreading works it *should* be fine, but it very well could cause problems. The easy solution is
282 // to man up and just write another cleanup function to pop the last thing off the stack, but again this is an error I can't
283 // actually trigger so it's fine for now
172 284
173 return 0; 285 return 0;
174} 286}
175 287
288// TODO: Fix this mess
176int encrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { 289int encrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) {
177 if(!src || !dst || !key) ERRRET(EINVAL, -1); 290 if(!src || !dst || !key) ERRRET(EINVAL, -1);
178 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 291 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0
@@ -210,6 +323,7 @@ int encrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstr
210 return 0; 323 return 0;
211} 324}
212 325
326// TODO: Fix this as well
213int decrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { 327int decrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) {
214 if(!src || !dst || !key) ERRRET(EINVAL, -1); 328 if(!src || !dst || !key) ERRRET(EINVAL, -1);
215 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 329 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0
@@ -283,7 +397,6 @@ int genpassword(char **str, unsigned int words) {
283 return words; 397 return words;
284} 398}
285 399
286// sodium_malloc wrapper. Calls `error()` or `abort()` depnding on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___`. Will make sure libsodium is initialized if `___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0`
287void* xsodium_malloc(size_t size) { 400void* xsodium_malloc(size_t size) {
288 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0 401 #if ___VXGG___ALWAYS_CHECK_LIBSODIUM___ > 0
289 checksodium(); 402 checksodium();
@@ -298,15 +411,9 @@ void* xsodium_malloc(size_t size) {
298 411
299 412
300 413
301/* 414// TODO: Rewrite this to use the threadpool. Each newly scanned file should be pushed onto the threadpool as an encryption task
302
303#include "threadpool.h"
304 415
305// #include <stdlib.h>
306// #include <dirent.h> 416// #include <dirent.h>
307// #include <string.h>
308// #include <errno.h>
309// #include <error.h>
310 417
311// dlinkedlist * scandirlist(const char * const dir, int (*selector)(const struct dirent *), int (*cmp)(const struct dirent **, const struct dirent **)) { 418// dlinkedlist * scandirlist(const char * const dir, int (*selector)(const struct dirent *), int (*cmp)(const struct dirent **, const struct dirent **)) {
312// if(!dir || selector == NULL || cmp == NULL) ERRRET(EINVAL, NULL); 419// if(!dir || selector == NULL || cmp == NULL) ERRRET(EINVAL, NULL);
@@ -333,8 +440,61 @@ void* xsodium_malloc(size_t size) {
333// return list; 440// return list;
334// } 441// }
335 442
336// TODO: Rewrite this to use the threadpool. Each newly scanned file should be pushed onto the threadpool as an encryption task 443
337*/ 444
445struct __ucl_namelist_vals {
446 struct dirent **namelist;
447 int entries;
448};
449
450static void __ucl_namelist(void *namelist) {
451 if(!namelist) return;
452 struct __ucl_namelist_vals *real = namelist;
453 for(int i = 0; i > real->entries; i++)
454 free(real->namelist[i]);
455 free(real->namelist);
456 return;
457}
458
459enum VXGG_FLC {
460 VXGG_FLC__INVALID,
461 VXGG_FLC__ENCRYPT,
462 VXGG_FLC__DECRYPT,
463 VXGG_FLC__TOOBIG
464};
465
466ctqueue * getfilelist(enum VXGG_FLC mode, const char * const dir, int threads, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) {
467 if(mode <= VXGG_FLC__INVALID || mode >= VXGG_FLC__TOOBIG || !dir || threads <= 0 || !filter || !compar) ERRRET(EINVAL, NULL);
468
469 cleanup_CREATE(10);
470 ctqueue *ctq = NULL;
471 int files = -1;
472
473 // Create the ctqueue for later
474 ctq = ctqueue_init(threads);
475 if(!ctq)
476 return NULL;
477 cleanup_REGISTER(ctqueue_free, ctq);
478
479 // Get the scandir list
480 struct dirent **namelist;
481 if((files = scandir(dir, &namelist, filter, compar)) < 0)
482 cleanup_MARK();
483 cleanup_CNDREGISTER(__ucl_namelist, (void*)(&(struct __ucl_namelist_vals){.namelist = namelist, .entries = files}));
484
485 // Push everything onto the ctqueue
486 // TODO: Write task* compatible callbacks for encryption and decryption, then populate the ctqueue based on the specified mode
487
488 cleanup_CNDFIRE();
489 if(cleanup_ERRORFLAGGED)
490 return NULL;
491
492 return ctq;
493}
494
495
496
497
338 498
339/* 499/*
340int main(void) { 500int main(void) {