diff options
Diffstat (limited to 'src/encryption.c')
| -rw-r--r-- | src/encryption.c | 272 |
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 | ||
| 37 | void 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 | */ | ||
| 44 | static 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 | ||
| 44 | int 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 | */ | ||
| 68 | static 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 | ||
| 71 | void 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 | */ | ||
| 104 | static 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 | |||
| 140 | static void __ucl_close(void *fd) { | ||
| 141 | if(!fd) return; | ||
| 142 | close(*(int*)fd); | ||
| 143 | *(int*)fd = -1; | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | |||
| 147 | static void __ucl_fclose(void *file) { | ||
| 148 | if(!file) return; | ||
| 149 | fclose((FILE*)file); | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | |||
| 106 | int encryptviatmp(const char * const target, const char * const output, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { | 153 | int 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 | ||
| 176 | int encrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { | 289 | int 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 | ||
| 213 | int decrypttofile(FILE *src, FILE *dst, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]) { | 327 | int 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` | ||
| 287 | void* xsodium_malloc(size_t size) { | 400 | void* 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 | |
| 445 | struct __ucl_namelist_vals { | ||
| 446 | struct dirent **namelist; | ||
| 447 | int entries; | ||
| 448 | }; | ||
| 449 | |||
| 450 | static 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 | |||
| 459 | enum VXGG_FLC { | ||
| 460 | VXGG_FLC__INVALID, | ||
| 461 | VXGG_FLC__ENCRYPT, | ||
| 462 | VXGG_FLC__DECRYPT, | ||
| 463 | VXGG_FLC__TOOBIG | ||
| 464 | }; | ||
| 465 | |||
| 466 | ctqueue * 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 | /* |
| 340 | int main(void) { | 500 | int main(void) { |
