salty/salty.c
2024-04-01 20:59:58 -03:00

455 lines
11 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sodium.h>
#include <pawstd.h>
#define KEY_SIZE crypto_secretbox_KEYBYTES
#define SALT_SIZE crypto_pwhash_SALTBYTES
#define BUF_SIZE 1024
bool stdinput = false;
size_t fileSize(FILE *file) {
fseek(file,0,SEEK_END);
size_t size = ftell(file);
fseek(file,0,SEEK_SET);
return size;
}
bool keyGen(const unsigned char* salt, const char* password, unsigned char* key) {
fprintf(stderr,NOR"Beginning key generation...\n");
if (crypto_pwhash(
key,KEY_SIZE,
password,strlen(password),
salt,crypto_pwhash_OPSLIMIT_INTERACTIVE,
crypto_pwhash_MEMLIMIT_INTERACTIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
fprintf(stderr,ERR"Out of memory! Key could not be generated.\n");
return false;
}
fprintf(stderr,OK"Key generation successful!\n");
return true;
}
int encryptMessage(const char* inputFile, const char* outputFile, const char* password) {
// Generate salt
unsigned char salt[SALT_SIZE];
randombytes_buf(salt, SALT_SIZE);
// Key generation from password
unsigned char key[KEY_SIZE];
if (!keyGen(salt,password,key)) {
return 1;
}
fprintf(stderr,NOR"Reading file...\n");
FILE *outFile = fopen(outputFile,"wb");
if (outFile == NULL) {
fprintf(stderr,ERR"Could not open output file!\n");
return 1;
}
unsigned char* decrypted;
size_t decLen;
// Check if input is stdin, and read the input
if (stdinput) {
// Begin reading into buffer
unsigned char buffer[BUF_SIZE];
size_t inputSize = 0;
unsigned char c;
unsigned char* input = malloc(BUF_SIZE);
if (input == NULL) {
fprintf(stderr,ERR"Memory allocation error.");
fclose(outFile);
return 1;
}
int i = 0;
c = fgetc(stdin);
while (feof(stdin) == 0) {
inputSize++;
if (i < BUF_SIZE) {
buffer[i] = c;
i++;
} else {
char *old = input;
input = realloc(input, inputSize);
if (input == NULL) {
fprintf(stderr,ERR"Memory allocation error.");
fclose(outFile);
free(old);
return 1;
}
memcpy(input + inputSize - BUF_SIZE,buffer,BUF_SIZE);
i = 0;
}
c = fgetc(stdin);
}
if (i > 0) {
char *old = input;
input = realloc(input, inputSize);
if (input == NULL) {
fprintf(stderr,ERR"Memory allocation error.");
fclose(outFile);
free(old);
return 1;
}
memcpy(input + inputSize - i,buffer,i);
}
decrypted = input;
decLen = inputSize;
} else {
// Open input file
FILE *inFile = fopen(inputFile,"rb");
if (inFile == NULL || outFile == NULL) {
fprintf(stderr,ERR"Could not open input file!\n");
return 1;
}
// Read input file
fprintf(stderr,NOR"Reading input filesize...\n");
decLen = fileSize(inFile);
decrypted = malloc(decLen);
if (fread(decrypted,1,decLen,inFile) != decLen) {
fprintf(stderr,ERR"Error reading from file.\n");
fclose(inFile);
fclose(outFile);
free(decrypted);
return 1;
}
fclose(inFile);
}
size_t encLen = decLen + crypto_secretbox_MACBYTES;
fprintf(stderr,OK"File is %d bytes.\n",decLen);
fprintf(stderr,OK"Encoding file to %d bytes.\n", encLen);
fprintf(stderr,NOR"Beginning encryption...\n");
// Generate a nonce, write headers and encrypted message
unsigned char nonce[crypto_secretbox_NONCEBYTES];
randombytes_buf(nonce,sizeof(nonce));
// Encrypt the data
unsigned char encrypted[encLen];
crypto_secretbox_easy(encrypted, decrypted, decLen, nonce, key);
// Patchy but correct-ish attempt to solve annoying stdout issue
size_t totalSize = strlen("gneurshk") + sizeof(salt) + sizeof(nonce) + encLen;
size_t offset = 0;
unsigned char* outputBuffer = malloc(totalSize);
if (outputBuffer == NULL) {
fprintf(stderr,ERR"Memory allocation error.\n");
free(decrypted);
fclose(outFile);
return 1;
}
memcpy(outputBuffer + offset, "gneurshk", strlen("gneurshk"));
offset += strlen("gneurshk");
memcpy(outputBuffer + offset, salt, sizeof(salt));
offset += sizeof(salt);
memcpy(outputBuffer + offset, nonce, sizeof(nonce));
offset += sizeof(nonce);
memcpy(outputBuffer + offset, encrypted, sizeof(encrypted));
fprintf(stderr,NOR"Writing encrypted data...\n");
if(fwrite(outputBuffer, 1, totalSize, outFile) != totalSize) {
fprintf(stderr,ERR"Error writing encrypted data to file.\n");
fclose(outFile);
return 1;
}
fclose(outFile);
free(decrypted);
free(outputBuffer);
fprintf(stderr,"\n"OK"File encrypted!\n");
return 0;
}
int decryptMessage(const char* inputFile, const char* outputFile, const char* password) {
// Open output file
FILE *outFile = fopen(outputFile,"wb");
if (outFile == NULL) {
fprintf(stderr,ERR"Could not open output file!\n");
return 1;
}
// Variables
unsigned char salt[SALT_SIZE];
unsigned char nonce[crypto_secretbox_NONCEBYTES];
unsigned char* fullInput;
size_t inLen;
// Check if input is stdin, and read the input
if (stdinput) {
// Begin reading into buffer
unsigned char buffer[BUF_SIZE];
size_t inputSize = 0;
unsigned char c;
unsigned char* input = malloc(BUF_SIZE);
if (input == NULL) {
fprintf(stderr,ERR"Memory allocation error.");
fclose(outFile);
return 1;
}
int i = 0;
c = fgetc(stdin);
while (feof(stdin) == 0) {
inputSize++;
if (i < BUF_SIZE) {
buffer[i] = c;
i++;
} else {
char *old = input;
input = realloc(input, inputSize);
if (input == NULL) {
fprintf(stderr,ERR"Memory allocation error.");
fclose(outFile);
free(old);
return 1;
}
memcpy(input + inputSize - BUF_SIZE,buffer,BUF_SIZE);
i = 0;
}
c = fgetc(stdin);
}
if (i > 0) {
char *old = input;
input = realloc(input, inputSize);
if (input == NULL) {
fprintf(stderr,ERR"Memory allocation error.");
fclose(outFile);
free(old);
return 1;
}
memcpy(input + inputSize - i,buffer,i);
}
fullInput = input;
inLen = inputSize;
} else {
FILE *inFile = fopen(inputFile,"rb");
// Get the size of the file and read it
size_t inputSize = fileSize(inFile);
unsigned char* input = malloc(inputSize);
if (fread(input,1,inputSize,inFile) != inputSize) {
fprintf(stderr,ERR"Error reading from input file.\n");
fclose(inFile);
fclose(outFile);
return 1;
}
fclose(inFile);
fullInput = input;
inLen = inputSize;
}
size_t encLen = inLen - sizeof(salt) - sizeof(nonce) - 8;
if (inLen == 0) {
fprintf(stderr,ERR"File size is 0. No data.");
fclose(outFile);
return 1;
}
fprintf(stderr,DBG"Size of encrypted file: %d bytes.\n",inLen);
fprintf(stderr,DBG"This means the encrypted content is %d bytes.\n",encLen);
unsigned char encrypted[encLen];
// Verify file
size_t offset = 0;
if (memcmp(fullInput,"gneurshk",strlen("gneurshk")) != 0) {
fprintf(stderr,ERR"Invalid header.\n");
fprintf(stderr,ERR"Make sure the input file was signed by this program!\n");
free(fullInput);
fclose(outFile);
return 1;
}
fprintf(stderr,OK"Valid header! Reading the rest...\n");
offset += strlen("gneurshk");
// Read salt and nonce
memcpy(salt, fullInput + offset, sizeof(salt));
offset += sizeof(salt);
memcpy(nonce, fullInput + offset, sizeof(nonce));
offset += sizeof(nonce);
memcpy(encrypted, fullInput + offset, sizeof(encrypted));
fprintf(stderr,OK"Data retrieved.\n");
// Key
unsigned char key[KEY_SIZE];
if (!keyGen(salt,password,key)) {
free(fullInput);
fclose(outFile);
return 1;
}
fprintf(stderr,OK"Proceeding to decrypt file...\n");
size_t decLen = encLen - crypto_secretbox_MACBYTES;
unsigned char decrypted[decLen];
if (crypto_secretbox_open_easy(decrypted,encrypted,encLen,nonce,key) < 0) {
fprintf(stderr,ERR"Error decrypting file.\n");
free(fullInput);
fclose(outFile);
return 1;
}
if (fwrite(decrypted,1,decLen,outFile) != decLen) {
fprintf(stderr,ERR"Error writing data to file.\n");
free(fullInput);
fclose(outFile);
return 1;
}
fclose(outFile);
free(fullInput);
fprintf(stderr,"\n"OK"File decrypted!\n");
return 0;
}
bool isFile(const char* filename) {
struct stat buffer;
return (stat(filename, &buffer) == 0);
}
int main(int argc, char *argv[]) {
fprintf(stderr,"\n- NetPaws Salty - File Encryption Program\n");
fprintf(stderr,"- 2024 Ignacio Rivero\n");
fprintf(stderr,"- FOR INTERNAL USE ONLY\n\n");
// Initialize libsodium
if (sodium_init() < 0) {
fprintf(stderr,ERR"libsodium initialization failed! It is not safe to proceed.\n");
return 1;
}
// Handle input, output and password arguments
int in = -1, out = -1, pass = -1;
bool decrypt = false;
int i = 1, exit = 0;
while (i < argc && exit == 0) {
if (strcmp (argv[i],"-in") == 0) {
if (i+1 >= argc) {
fprintf(stderr,ERR"Argument -in requires a file.\n");
exit = 1;
} else if (strcmp(argv[i+1],"-") == 0) {
in = -2;
i++;
} else if (!isFile(argv[i+1])) {
fprintf(stderr,ERR"File not found error: %s\n",argv[i+1]);
exit = 1;
} else if (in == -1) {
in = ++i;
} else {
fprintf(stderr,ERR"Too many arguments.\n");
exit = 1;
}
} else if (strcmp(argv[i],"-out") == 0) {
if (i+1 >= argc) {
fprintf(stderr,ERR"Argument -out requires a file.\n");
exit = 1;
} else if (strcmp(argv[i+1],"-") == 0) {
out = -2;
i++;
} else if (out == -1) {
out = ++i;
} else {
fprintf(stderr,ERR"Too many arguments.\n");
exit = 1;
}
} else if (strcmp (argv[i],"-key") == 0) {
if (i+1 >= argc) {
fprintf(stderr,ERR"Argument -key requires a password.\n");
exit = 1;
} else if (pass == -1) {
if (strlen(argv[i+1]) > 128) {
fprintf(stderr,ERR"Password too long.");
exit = 1;
} else {
pass = ++i;
}
} else {
fprintf(stderr,ERR"Too many arguments.\n");
exit = 1;
}
} else if (strcmp (argv[i],"-d") == 0) {
decrypt = true;
} else {
fprintf(stderr,ERR"Invalid argument: %s\n",argv[i]);
exit = 1;
}
i++;
}
if (exit != 0)
return exit;
// Set input and output filenames, or go to standard I/O if none
char input[FILENAME_MAX];
char output[FILENAME_MAX];
char psw[129];
if (in == -1) {
fprintf(stderr,NOR"No input file, reading from stdin.\n");
stdinput = true;
} else if (in == -2) {
fprintf(stderr,NOR"Reading from stdin.\n");
stdinput = true;
} else {
snprintf(input,sizeof(input),argv[in]);
}
if (out == -1) {
fprintf(stderr,NOR"No output file, writing to stdout.\n");
snprintf(output,sizeof(output),"/dev/stdout");
} else if (out == -2) {
fprintf(stderr,NOR"Writing to stdout.\n");
snprintf(output,sizeof(output),"/dev/stdout");
} else {
snprintf(output,sizeof(output),argv[out]);
}
char* password;
// Set password and run!
if (pass > 0) {
password = argv[pass];
} else if (in < 0) {
fprintf(stderr,ERR"Cannot read from stdin without a password.\n");
return 1;
} else {
password = getpass("Enter your encryption password: ");
}
if (decrypt) {
return decryptMessage(input,output,password);
} else {
return encryptMessage(input,output,password);
}
}