#include #include #include #include #include #include #include #include typedef struct opts { int64_t comm; int64_t nbytes; int64_t quiet; int64_t tear; char* chars; char* keyfile; char* input; char* output; } Opts; char* readInput (FILE* input, uint64_t size); void xor (Opts* opzioni); /* operates the bitwise XOR between mess and keyf and puts the output to outp */ void keyrand (Opts* opzioni); /* generates random numbers using RAND_bytes from openssl and puts them into outp */ void bluh (Opts* opzioni); /* performs the binary dump of the input file and prints that to outp */ void help (char* av[]); /* prints the help message */ int main (int argc, char* argv[]) { uint64_t opt = 1; int64_t command = 0; char* sip = NULL; Opts opzioni; opzioni.comm = 0; opzioni.nbytes = -1; // must be resolved temporary workaround (ho sonno) opzioni.quiet = 0; opzioni.tear = 0; opzioni.chars = "01"; opzioni.keyfile = NULL; opzioni.input = NULL; opzioni.output = NULL; /* The following while cycle parses the argv vector to find commands, options and relative arguments using the function getopt_long */ while (opt) { int option_index = 0; static struct option options[] = { {"bluh", no_argument, 0, 'b'}, {"char", required_argument, 0, 'c'}, {"decrypt", no_argument, 0, 'd'}, {"encrypt", no_argument, 0, 'e'}, {"key-file", required_argument, 0, 'k'}, {"input", required_argument, 0, 'i'}, {"gen-key", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"nbytes", required_argument, 0, 'n'}, {"output", required_argument, 0, 'o'}, {"quiet", no_argument, 0, 'q'}, {"tear-page", no_argument, 0, 't'}, {"uhbluh", no_argument, 0, 'u'}, {0, 0, 0, 0}, }; if ((opt = getopt_long (argc, argv, "bc:deghk:i:n:o:qtu", options, &option_index)) == -1) break; switch (opt) { case 'b': command ++; opzioni.comm = 'b'; break; case 'c': if (strlen (argv[optind - 1]) != 2){ printf ("ERROR: too much or too many characters inserted! You must insert exactly two characters."); exit (EXIT_FAILURE); } opzioni.chars = argv[optind - 1]; break; case 'd': command ++; opzioni.comm = 'd'; break; case 'e': command ++; opzioni.comm = 'e'; break; case 'g': command++; opzioni.comm = 'g'; break; case 'h': help (argv); command ++; break; case 'k': opzioni.keyfile = argv[optind-1]; if (access (opzioni.keyfile, F_OK) == -1) { error (errno, errno, opzioni.keyfile); } break; case 'i': opzioni.input = argv[optind-1]; if (access (opzioni.input, F_OK) == -1) { error (errno, errno, opzioni.input); } break; case 'n': opzioni.nbytes = strtol (argv[optind-1], &sip, 10); if (sip[0] == 'K') { opzioni.nbytes = opzioni.nbytes*1024; } else if (sip[0] == 'M') { opzioni.nbytes = opzioni.nbytes*1024*1024; } else if (sip[0] == 'G') { opzioni.nbytes = opzioni.nbytes*1024*1024*1024; } else if (sip[0] == 'T') { opzioni.nbytes = opzioni.nbytes*1024*1024*1024*1024; } else if (sip[0] != '\0') { printf ("ERROR: you must specify the size in KiB, MiB, GiB or TiB, respectively using K, M, G or T, or nothing for just bytes."); exit (EXIT_FAILURE); } break; case 'o': opzioni.output = argv[optind-1]; if (!access (opzioni.output, F_OK)) { if (!opzioni.quiet) { printf ("WARNING: %s file exists in filesystem and will be overwritten!", opzioni.output); } } break; case 'q': opzioni.quiet = 1; break; case 't': opzioni.tear = 1; break; case 'u': command ++; opzioni.comm = 'u'; break; case '?': break; default: printf ("carachter code returned 0%lo \n", opt); } } /* Next section performs some input checks */ if (!command) { printf ("ERROR: no command called\n"); exit (EXIT_FAILURE); } else if (command > 1) { printf ("ERROR: multiple commands called\n"); printf ("%s [COMMAND] [OPTIONS] ...\n", argv[0]); exit (EXIT_FAILURE); } if (optind < argc) { printf ("ERROR: too many arguments\n"); exit (EXIT_FAILURE); } /* Next section detects the functions to call */ if (opzioni.comm == 'e' || opzioni.comm == 'd') { if (!opzioni.keyfile) { printf ("ERROR: no key specified\n"); exit (EXIT_FAILURE); } xor (&opzioni); } else if (opzioni.comm == 'g') { keyrand (&opzioni); } else if (opzioni.comm == 'b' || opzioni.comm == 'u') { bluh (&opzioni); } exit (EXIT_SUCCESS); } char* readInput (FILE* stdinput, uint64_t size) { int64_t character; uint64_t length; char* input; input = malloc (sizeof (char) * size); while (EOF != (character = fgetc (stdinput))) { input[length++] = character; if (length == size) { input = realloc (input, sizeof (char) * (size += 8)); } } input[length++] = '\0'; return realloc (input, sizeof (char) * length); } void xor (Opts* opzioni) { char* input; FILE* critt; FILE* mex; FILE* keyx = fopen (opzioni->keyfile, "r+"); if (opzioni->input) { mex = fopen (opzioni->input, "r"); } else if (!opzioni->input) { printf("INFO: Reading from standard input (press ^D to insert the EOF character when you are finished):\n"); input = readInput (stdin, 8); } if (opzioni->output) { critt = fopen (opzioni->output, "w"); } int64_t mess_size; int64_t pad_size; if (opzioni->input) { fseek (mex, 0L, SEEK_END); mess_size = ftell (mex); rewind (mex); } else if (!opzioni->input) { mess_size = strlen (input); } fseek (keyx, 0L, SEEK_END); pad_size = ftell (keyx); fseek (keyx, (pad_size - mess_size), SEEK_SET); char* bytes = malloc (mess_size); int64_t i; char a, b; if (opzioni->input) { for (i = 0; i < mess_size; i ++) { fscanf (mex, "%c", &a); fscanf (keyx, "%c", &b); bytes[i] = a ^ b; } } else if (!opzioni->input) { for (i = 0; i < mess_size; i ++) { a = input[i]; fscanf (keyx, "%c", &b); bytes[i] = a ^ b; } } if (opzioni->output) { fwrite (bytes, sizeof(char), mess_size, critt); } else if (!opzioni->output) { if (!opzioni->quiet) { printf ("WARNING: output not specified, printing to standard output\n"); } fprintf (stdout, "%s", bytes); if (!opzioni->quiet) { printf ("\n"); } } if (opzioni->tear) { ftruncate (fileno (keyx), (pad_size - mess_size)); fseek (keyx, 0L, SEEK_END); int64_t new_pad_size = ftell (keyx); if (!opzioni->quiet) { printf ("INFO: your pad is now %li bytes shorter\n", mess_size); printf ("INFO: you now have %li bytes left\n", new_pad_size); } } free (bytes); fclose (keyx); if (opzioni->input) { fclose (mex); } if (opzioni->output) { fclose (critt); } if (opzioni->comm == 'e') { if (!opzioni->quiet) { printf ("INFO: message successfully encrypted\n"); } } else if (opzioni->comm == 'd') { if (!opzioni->quiet) { printf ("INFO: message successfully decrypted\n"); } } return; } void keyrand (Opts* opzioni) { if (opzioni->nbytes < -1) { // orribile printf ("ERROR: negative byte value inserted!\n"); exit (EXIT_FAILURE); } else if (opzioni->nbytes) { if(opzioni->nbytes == -1) { if (!opzioni->quiet) { printf ("WARNING: no byte number specified, using default value: 1MB\n"); } opzioni->nbytes = 1048576; } if (!opzioni->quiet) { printf ("INFO: generating pad...\n"); } unsigned char* key = malloc (opzioni->nbytes); RAND_bytes (key, opzioni->nbytes); FILE* file; if (opzioni->output) { file = fopen (opzioni->output, "w"); fwrite (key, sizeof(char), opzioni->nbytes, file); fclose (file); free (key); if (!opzioni->quiet) { printf ("INFO: created key file %s of %ld bytes\n", opzioni->output, opzioni->nbytes); } } else if (!opzioni->output) { if (!opzioni->quiet) { printf ("WARNING: output not specified, printing to standard output\n"); } fprintf (stdout, "%s", key); if (!opzioni->quiet) { printf ("\n"); } } } else { printf ("WARNING: byte number specified is 0.\n"); printf ("WARNING: doing nothing!\n"); } return; } void bluh (Opts* opzioni) { char a = opzioni->chars[0]; char b = opzioni->chars[1]; char* input; FILE* bluh; FILE* mex; if (opzioni->input) { mex = fopen (opzioni->input, "r"); } else if (!opzioni->input) { printf("INFO: Reading from standard input (press ^D to insert the EOF character when you are finished):\n"); input = readInput (stdin, 8); } if (opzioni->output) { bluh = fopen (opzioni->output, "w"); } int64_t len; if (opzioni->input) { fseek (mex, 0L, SEEK_END); len = ftell (mex); rewind (mex); } else if (!opzioni->input) { len = strlen (input); } if (opzioni->comm == 'b') { char* bytes; if (opzioni->input) { bytes = malloc (len); fread (bytes, sizeof(char), len, mex); } else if (!opzioni->input) { bytes = input; } char* bits = malloc (8 * len); int64_t i,j; for (i = 0; i < len; i ++) { for (j = 0; j < 8; j ++) { bits[8 * i + j] = (bytes[i] & (1 << (7 -j))) ? b : a; } } if (opzioni->output) { fwrite (bits, sizeof(char), (8 * len), bluh); } else if (!opzioni->output) { if (!opzioni->quiet) { printf ("WARNING: output not specified, printing to standard output\n"); } fprintf (stdout, "%s", bits); if (!opzioni->quiet) { printf ("\n"); } } if (opzioni->input) { free (bytes); } free (bits); if (!opzioni->quiet) { printf ("INFO: message successfully bluhed!\n"); } } else if (opzioni->comm == 'u') { char* bits; if (opzioni->input) { bits = malloc (len); fread (bits, sizeof(char), len, mex); } else if (!opzioni->input) { bits = input; } char* comp = malloc ((len / 8) + 1); memset (comp, 0, ((len / 8) + 1)); int64_t i, j; for (i = 0; i < (len / 8); i ++) { for (j = 0; j < 8; j ++) { if (bits[8 * i + j] == b) { comp[i] |= 1 << (7 - j); } } } if (opzioni->output) { fwrite (comp, sizeof(char), (len / 8), bluh); } else if (!opzioni->output) { if (!opzioni->quiet) { printf ("WARNING: output not specified, printing to standard output\n"); } fprintf (stdout, "%s", comp); if (!opzioni->quiet) { printf ("\n"); } } if (opzioni->input) { free (bits); } free (comp); if (!opzioni->quiet) { printf ("INFO: message successfully unbluhed!\n"); } } if (opzioni->input) { fclose (mex); } if (opzioni->output) { fclose (bluh); } return; } void help (char* av[]) { fprintf (stdout,"Onetimebluh usage:\n" "%s [COMMAND] [OPTIONS]\n\n" "Commands:\n\n" " -b, --bluh bluhes your message or in other words performs a binary dump\n" " -d, --decrypt decrypt message (input) same ad --encrypt, just for the feeling\n" " -e, --encrypt encrypt message (input)\n" " -g, --gen-key create key file\n" " -h, --help print this help\n" " -u, --unbluh unbluhes your message (gets the orginal message from the binary dump)\n\n" "Options:\n\n" " -c, --char=CAHRS reads two cahracters as argument and uses them to bluh your message\n" " -k, --key-file=KEY_FILE use key (input)\n" " -i, --input=FILE input file\n" " -n, --nbytes=NUM{K,M,G,T} number of bytes, you can specify K for KiB, M for MiB, etc... \n" " -o, --output=FILE output file\n" " -q, --quiet suppresses all messages, except from error releated ones\n" " -t, --tear-page deletes from the pad file the bytes used to encrypt/decrypt\n\n" "Onetimebluh project repository at https://git.eigenlab.org/seppia/onetimebluh\n", av[0]); return; }