#include #include #include #include #include #include #include #include void xor (int ed, char* mess, char* keyf, char* outp); /* operates the bitwise XOR between mess and keyf and puts the output to outp */ void keyrand (int nb, char* outp); /* generates random numbers using RAND_bytes from openssl and puts them into outp */ void bluh (int c, char* mess, char* outp, char* ch); /* 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[]) { int opt = 1; int command = 0; int comm = 0; int tear = 0; char* chars = "01"; char* message = NULL; char* keyfile = NULL; char* output = NULL; int nbytes = -1; // must be resolved temporary workaround (ho sonno) /* 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", required_argument, 0, 'b'}, {"char", required_argument, 0, 'c'}, {"decrypt", required_argument, 0, 'd'}, {"encrypt", required_argument, 0, 'e'}, {"key-file", required_argument, 0, 'k'}, {"gen-key", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"nbytes", required_argument, 0, 'n'}, {"output", required_argument, 0, 'o'}, {"tear-page", no_argument, 0, 't'}, {"uhbluh", required_argument, 0, 'u'}, {0, 0, 0, 0}, }; if ((opt = getopt_long (argc, argv, "b:c:d:e:ghk:n:o:tu:", options, &option_index)) == -1) break; switch (opt) { case 'b': message = argv[optind-1]; if (access (message, F_OK) == -1) { /* look at next comment */ error (errno, errno, message); } command ++; comm = 'b'; break; case 'c': if (strlen (argv[optind - 1]) != 2){ printf ("Too much or too many characters inserted!"); exit (EXIT_FAILURE); } chars = argv[optind - 1]; break; case 'd': message = argv[optind-1]; command ++; comm = 'r'; break; case 'e': message = argv[optind-1]; if (access (message, F_OK) == -1) { /* checks the existence of the file and eventually exits */ error (errno, errno, message); } command ++; comm = 'e'; break; case 'g': command++; comm = 'g'; break; case 'h': help (argv); command ++; break; case 'k': keyfile = argv[optind-1]; if (access (keyfile, F_OK) == -1) { /* look at the previous comment */ error (errno, errno, keyfile); } break; case 'n': nbytes = atoi (argv[optind-1]); break; case 'o': output = argv[optind-1]; break; case 't': tear = 1; break; case 'u': message = argv[optind-1]; if (access (message, F_OK) == -1) { /* just guess */ error (errno, errno, message); } command ++; comm = 'u'; break; case '?': break; default: printf ("carachter code returned 0%o \n", opt); } } /* Next section performs some input checks */ if (command == 0) { printf ("%s: No command called\n", argv[0]); exit (EXIT_FAILURE); } else if (command > 1) { printf ("Multiple commands called\n"); printf ("%s [COMMAND] [OPTIONS] ...\n", argv[0]); exit (EXIT_FAILURE); } if (optind < argc) { printf ("%s: Too many arguments\n", argv[0]); exit (EXIT_FAILURE); } /* Next section detects the functions to call */ if (comm == 'e' || comm == 'r') { if (keyfile == NULL) { printf ("%s: No key specified: exit!\n", argv[0]); exit (EXIT_FAILURE); } if (tear == 1) { comm++; } xor (comm, message, keyfile, output); } else if (comm == 'g') { keyrand (nbytes, output); } else if (comm == 'b' || comm == 'u') { bluh (comm, message, output, chars); } exit (EXIT_SUCCESS); } void xor (int ed, char* mess, char* keyf, char* outp) { char* defenoutp = "critt"; char* defdeoutp = "decritt"; /* In absence of input by users next block sets the default values */ if (outp == NULL) { if (ed == 'e' || ed == 'f') { printf ("WARNING no output name specified using default value 'critt' \n"); outp = defenoutp; } else if (ed == 'r' || ed == 's') { printf ("WARNING no output name specified usign default value 'decritt' \n"); outp = defdeoutp; } } FILE* mex = fopen (mess, "r"); FILE* keyx = fopen (keyf, "r+"); FILE* critt = fopen (outp, "w"); long mess_size; long pad_size; fseek (mex, 0L, SEEK_END); mess_size = ftell (mex); rewind (mex); fseek (keyx, 0L, SEEK_END); pad_size = ftell (keyx); fseek (keyx, (pad_size - mess_size), SEEK_SET); char* bytes = malloc (mess_size); long i; char a, b; for (i = 0; i < mess_size; i ++) { fscanf (mex, "%c", &a); fscanf (keyx, "%c", &b); bytes[i] = a ^ b; } fwrite (bytes, sizeof(char), mess_size, critt); if (ed == 'f' || ed == 's') { ftruncate (fileno (keyx), (pad_size - mess_size)); fseek (keyx, 0L, SEEK_END); long new_pad_size = ftell (keyx); printf ("Your pad is now %li bytes shorter \n", mess_size); printf ("You now have %li bytes left \n", new_pad_size); } free (bytes); fclose (mex); fclose (keyx); fclose (critt); if (ed == 'e' || ed == 'f') { printf ("Message successfully encrypted \n"); } else if (ed == 'r' || ed == 's') { printf ("Message successfully decrypted \n"); } return; } void keyrand (int nb, char* outp) { char* defoutp = "default.key"; /* Next block controls the inputs and eventually sets the default values */ if((nb == -1) && (outp == NULL)) { printf ("WARNING no option specified usign default values... \n"); nb = 1048576; outp = defoutp; } if (nb < -1) { // orribile printf ("Negative byte value inserted! \n"); printf ("Exiting... \n"); exit (EXIT_FAILURE); } else if (nb != 0) { if(nb == -1) { printf ("No byte number specified... using default value: 1MB \n"); nb = 1048576; } unsigned char* key = malloc (nb); RAND_bytes (key, nb); if (outp == NULL) { outp = defoutp; printf ("No output name specified... using default value: default.key \n"); } FILE* file = fopen (outp, "w"); fwrite (key, sizeof(char), nb, file); fclose (file); free (key); printf ("Created key file %s of %d bytes \n", outp, nb); } else { printf ("Byte number specified is 0. \n"); printf ("Doing nothing! \n"); } return; } void bluh (int c, char* mess, char* outp, char* ch) { char* defbluh = "bluhed"; char* defunbluh = "unbluhed"; char a = ch[0]; char b = ch[1]; /* In absence of input by users next block sets the default values */ if (outp == NULL) { if (c == 'b') { printf ("WARNING no output name specified using default value 'bluhed' \n"); outp = defbluh; } else if (c == 'u') { printf ("WARNING no output name specified usign default value 'unbluhed' \n"); outp = defunbluh; } } FILE* mex = fopen (mess, "r"); FILE* bluh = fopen (outp, "w"); long len; fseek (mex, 0L, SEEK_END); len = ftell (mex); rewind (mex); if (c == 'b') { char* bytes = malloc (len); char* bits = malloc (8 * len); fread (bytes, sizeof(char), len, mex); int 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; } } fwrite (bits, sizeof(char), (8 * len), bluh); free (bytes); free (bits); printf ("Message successfully bluhed!\n"); } else if (c == 'u') { char* comp = malloc ((len / 8) + 1); char* bits = malloc (len); fread (bits, sizeof(char), len, mex); memset (comp, 0, ((len / 8) + 1)); int 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); } } } fwrite (comp, sizeof(char), (len / 8), bluh); free (comp); free (bits); printf ("Message successfully unbluhed!\n"); } fclose (mex); fclose (bluh); return; } void help (char* av[]) { fprintf (stdout,"ONETIMEBLUH USAGE:\n" "%s [COMMAND] [OPTIONS]\n\n" "COMMANDS:\n\n" "-b, --bluh=FILE bluhes your message or in other words performs a binary dump\n" "-d, --decrypt=FILE decrypt message (input) same ad --encrypt, just for the feeling\n" "-e, --encrypt=FILE encrypt message (input)\n" "-g, --gen-key create key file\n" "-h, --help print this help\n" "-u, --unbluh=FILE 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" "-n, --nbytes=NUM number of bytes\n" "-o, --output=FILE output name\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; }