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