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/encryption.c | 349 ++++++++++++++++++------------------------------------- 1 file changed, 113 insertions(+), 236 deletions(-) (limited to 'src/encryption.c') 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; } -- cgit v1.2.3