From 5d3068832c6094cf3b3ffce89d2398134e939b1f Mon Sep 17 00:00:00 2001 From: "@syxhe" Date: Tue, 21 Jan 2025 17:01:03 -0600 Subject: Write some sample code to encrypt a file via password --- src/Makefile | 2 +- src/encryption.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/shared.c | 22 ++++++++++++- src/shared.h | 2 ++ 4 files changed, 116 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 03f2f05..bcb4670 100644 --- a/src/Makefile +++ b/src/Makefile @@ -28,4 +28,4 @@ shared.o: shared.c shared.h encryption: encryption.c encryption.h shared.o shared.h c clean: - rm -rvf $(BINARIES) $(wildcard *.o) \ No newline at end of file + rm -rvf $(BINARIES) $(wildcard *.o) $(wildcard *.test*) \ No newline at end of file diff --git a/src/encryption.c b/src/encryption.c index 692b46a..100b50f 100644 --- a/src/encryption.c +++ b/src/encryption.c @@ -179,7 +179,7 @@ int main(void) { free(password); //*/// - //*// Example code for generating a password, derriving a secret key from it, and storing things properly + /*// Example code for generating a password, derriving a secret key from it, and storing things properly // Initialization checksodium(); @@ -195,9 +195,9 @@ int main(void) { // Store the password if(crypto_pwhash_str(hpass, pass, strlen(pass) + 1, crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE) != 0) error(1, errno, "Couldn't generate password, quitting..."); - /* Don't know if I want to use MODERATE or SENSITIVE for this. SENSITIVE takes a little bit on my laptop, which honestly + // Don't know if I want to use MODERATE or SENSITIVE for this. SENSITIVE takes a little bit on my laptop, which honestly // shouldn't be a problem, but it annoys me. MODERATE is quick and snappy, or at least quick enough that the slowdown is - // barely noticable. I might do MODERATE for testing and SENSITIVE for release */ + // barely noticable. I might do MODERATE for testing and SENSITIVE for release sodium_munlock(pass, strlen(pass) + 1); free(pass); @@ -206,7 +206,7 @@ int main(void) { // Check if the password from the user is correct char *uin = NULL; int size = -1; - if((size = readwholebuffer(&uin, 20, STDIN_FILENO)) < 0) + if((size = readwholebuffer(&uin, 1, STDIN_FILENO)) < 0) error(1, errno, "Could not read from stdin"); sodium_mlock(uin, size); @@ -218,6 +218,94 @@ 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"); + + struct stat sb; + if(fstat(fd, &sb) < 0) + error(1, errno, "stat() error"); + + // Read chunks of the file, encrypt them, then write them into the tmp file + ssize_t bytesread = -1; + unsigned char *buf = xcalloc(sb.st_blksize + 1, sizeof(*buf)); + unsigned char *cbuf = xcalloc((sb.st_blksize + 1) + crypto_secretstream_xchacha20poly1305_ABYTES, sizeof(*buf)); + while((bytesread = read(fd, buf, sb.st_blksize)) >= 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(efname); + + //*/// + return 0; } diff --git a/src/shared.c b/src/shared.c index f3e98ee..40240d5 100644 --- a/src/shared.c +++ b/src/shared.c @@ -81,10 +81,30 @@ int readwholebuffer(char **str, unsigned long int initsize, int fd) { lstr = tmp; } - if(lstr) { + if(lstr && fd == STDIN_FILENO) { lstr[csize - ccap - 1] = '\0'; // Don't include the newline } *str = lstr; return ((bytesread == 0) ? (csize - ccap) : -1); } + + +int writewholebuffer(int fd, const unsigned char *buf, int len) { + int total = 0; + int left = len; + int n; + + while(total < len) { + if((n = write(fd, buf + total, left)) < 0) + break; + + total += n; + left -= n; + } + + return (n < 0) ? -1 : 0; +} +// Adapted from Beej's `sendall()` function +// https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#sendall + // Thanks Beej! \ No newline at end of file diff --git a/src/shared.h b/src/shared.h index dce02fc..3602a4e 100644 --- a/src/shared.h +++ b/src/shared.h @@ -20,4 +20,6 @@ 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); +int writewholebuffer(int fd, const unsigned char *buf, int len); + #endif \ No newline at end of file -- cgit v1.2.3