//This program is free software: you can redistribute it and/or modify it under the terms #of the GNU General Public License as published by the Free Software Foundation, either #version 3 of the License, or (at your option) any later version. //This program is distributed in the hope that it will be useful, but WITHOUT ANY #WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A #PARTICULAR PURPOSE. See the GNU General Public License for more details. //You should have received a copy of the GNU General Public License along with this #program. If not, see /* otpf.c */ /* XOR with a one time pad file having an offset to start of file. */ /* Copyright 1995 Willis E. Howard, III */ /* Willis E. Howard, III email: WEHoward@aol.com mail: POB 1473 Elkhart, IN 46515 */ /* under MSDOS, NMAKE /F OTPF.MAK all clean */ #include #include #include #include "crypt.h" #include "tempfile.h" #include #include #include #include /* This routine uses the common interface to CRYPT.C. Generally, the name of this module becomes the name of the executable file. */ static int key_defined_otpf = 0; /* Set to 1 after a valid key has been defined */ static int encrypt_or_decrypt_otpf = ENCRYPTION_SELECT; static char key_string_otpf[257]; /* module specific */ FILE *otpfile; static char otp_name[80]; static long offset; static int validate_string (char *); static char key_file_name[80]; void key_update (void); long check_key (char *, long); /* cipher_doc: This array of strings must have two sections: CIPHER that describes the cipher used and KEY that describes how the key is defined and entered. */ static char *cipher_doc[] = { "CIPHER", " This program performs an EXCLUSIVE OR operation between a file and", " the contents of a one time pad (OTP) file. Failure occurs", " if the OTP file is shorter than the input file. The", " cipher does not require the -d option. After each file", " is processed, a line is output with decryption information:", " output file name, OTP name, OTP offset, and next offset.", " It is very important to keep this information for decyrption.", " If the key file exists, it will be updated.", "", "KEY", " The key is an ASCII string, given as \"FILENAME.EXT OFFSET\"", " where the filename identifies the file that you have selected", " to use as a one time pad. The offset is the offset from the", " beginning of the one time pad file, starting at 0. It may be", " omitted, in which case the file is used from the start. If", " an offset is given, enclose the entire phrase within quotes.", "", " If a key file exists, the first line is read, and it is scanned", " for the file name and the optional offset. If you also give a", " filename but no offset for the key on the command line, the key", " file will be searched for an offset. If not found, 0 is used.", " If you give a filename and offset on the command line for the key,", " this overrides any information in the key file. Do not use", " quotes in the key file. If the key file is read-only, it will", " be completely ignored to prevent repeated use of the same pad.", "", " If there is no key or key file, you will be prompted for a key.", NULL }; char ** crypt_help_otpf () { return cipher_doc; /* return a pointer to the help strings */ } /* crypt_key: Get the key from the passed string (that may be a file name in some implementations) or from a key file name. Return 0 on success and non-zero on error. */ int crypt_key_otpf (int key_type, char *key_text) { int i; char *s; FILE *fp; qDebug("crypt_key_otpf:key_defined_otpf=%d", key_defined_otpf); system("pause"); if (key_defined_otpf) /* cleanup before next key */ { fclose(otpfile); key_defined_otpf = 0; key_update (); } for (i = 0; i < 257; i++) /* initialize key string */ key_string_otpf[i] = '\0'; if (key_type == KEY_FILE) /* a file name has been given */ { strcpy (key_file_name, key_text); if ((fp = fopen (key_text, "r+")) == NULL) return 0; s = key_string_otpf; i = 0; for (;;) { *s = fgetc (fp); if ((*s == '\n') || (*s == EOF)) { *s = '\0'; if (i == 0) { key_defined_otpf = 0; break; } else { key_defined_otpf = validate_string (key_string_otpf); qDebug("crypt_key_otpf:validate_string me devuelve=%d",key_defined_otpf ); qDebug("crypt_key_otpf:key_string_otpf=%s",key_string_otpf ); system("pause"); break; } } else if (i == 255) { *++s = '\0'; key_defined_otpf = validate_string (key_string_otpf); break; } s++; i++; } fclose (fp); return 0; } else if (key_type == KEY_IMMEDIATE) /* a key string has been given */ { if (!strcmp (key_text, "?")) /* prompt for key */ { printf ("Key: "); /* input key from stdin */ s = key_string_otpf; i = 0; for (;;) { *s = fgetc (stdin); if ((*s == '\n') || (*s == EOF)) { *s = '\0'; if (i == 0) { key_defined_otpf = 0; break; } else { key_defined_otpf = validate_string (key_string_otpf); break; } } else if (i == 255) { *++s = '\0'; key_defined_otpf = validate_string (key_string_otpf); break; } s++; i++; } } else /* copy string up to 256 characters */ { strncpy (key_string_otpf, key_text, 256); key_string_otpf[256] = '\0'; key_defined_otpf = validate_string (key_string_otpf); } return 0; } fprintf (stderr, "Error getting key\n"); return 1; } /* crypt_key_erase: If a local copy of the key has been made, erase it from memory. This increases security that the key can not be obtained from an examination of memory. */ void crypt_key_erase_otpf () { int i; if (key_defined_otpf) /* cleanup before exit */ { key_update (); key_defined_otpf = 0; fclose (otpfile); } for (i = 0; i < 257; i++) key_string_otpf[i] = '\0'; offset = 0; for (i = 0; i < 80; i++) otp_name[i] = '\0'; key_defined_otpf = 0; return; } /* crypt_select: If encryption and decryption require different ciphers, this routine defines the direction. Valid choices are ENCRYPTION_SELECT and DECRYPTION_SELECT. */ int crypt_select_otpf (int selection) { if (selection == ENCRYPTION_SELECT) encrypt_or_decrypt_otpf = ENCRYPTION_SELECT; if (selection == DECRYPTION_SELECT) encrypt_or_decrypt_otpf = DECRYPTION_SELECT; return encrypt_or_decrypt_otpf; } /* crypt_file: encrypt or decrypt the source to the destination file. Do not exit from this routine. Return 0 on success and return 1 on error. Use an fprintf(stderr, ... ) to report the nature of the error and close any open files. This allows the main routine to do some cleanup before exiting. */ int crypt_file_otpf (char *source, char *dest) { int c; int o; FILE *infile; FILE *outfile; qDebug("crypt_file_otpf:antes de key_defined_otpf=%d", key_defined_otpf); system("pause"); while (!key_defined_otpf) crypt_key_otpf (KEY_IMMEDIATE, "?"); if ((infile = fopen (source, "rb")) == NULL) { fprintf (stderr, "Can not open input file %s for reading.\n", source); return 1; } if ((outfile = fopen (dest, "wb")) == NULL) { fprintf (stderr, "Can not open output file %s for writing.\n", dest); fclose (infile); return 1; } while ((c = fgetc (infile)) != EOF) { if ((o = fgetc (otpfile)) == EOF) { fprintf (stderr, "Premature end of OTP file %s\n", otp_name); fclose (infile); fclose (outfile); crypt_key_erase_otpf(); return 1; } c ^= o; if (fputc (c, outfile) == EOF) { fprintf (stderr, "Could not write to output file %s\n", dest); fclose (infile); fclose (outfile); return 1; } } /* Report output file name, OTP file name, original offset, and next offset. Then update offset for next file so that information within the OTP file is not reused as long as the main program does not exit. */ printf ("%s %s %ld %ld\n", dest, otp_name, offset, ftell (otpfile)); offset = ftell (otpfile); /* close everything and give a good return code */ fclose (infile); fclose (outfile); return 0; } /* strictly syntax check: name and number */ static int validate_string (char *s) /* get otp_name and offset */ { char *p; int i = 0; long l = 0; while ((*s == '\"') || (*s == ' ')) /* strip off leading quotes or spaces */ s++; if (!isgraph (*s)) /* non-printable is an error */ { qDebug("validate_string: No tiene representacion la clave."); otp_name[0] = '\0'; offset = 0; return 0; /* zero is error return */ } while (isgraph (*s)) /* form the file name from printables */ otp_name[i++] = *s++; otp_name[i] = '\0'; while (*s == ' ') /* strip off spaces */ s++; p = s; while (isdigit (*s)) /* make a long number from digits */ l = (l * 10) + (long) (*s++ - '0'); /* zero if none. Ignore rest of line */ if (p == s) offset = check_key (otp_name, l); /* set the offset */ else offset = l; qDebug("*******otp_name=%s",otp_name); if ((otpfile = fopen (otp_name, "rb")) == NULL){ /* Can not open OTP file */ qDebug("No puedo abrir OTPfile"); return 0;} if (fseek (otpfile, offset, SEEK_SET)) /* Error setting offset to OTP file */ return 0; return 1; /* one is good return */ } void key_update (void) { char *s; char *tempname; char buffer[81]; char foundname[81]; long foundlength; FILE *fp; FILE *tfp; qDebug("key_update:antes de key_update"); if ((fp = fopen (key_file_name, "r+")) == NULL) return; tempname = tempfile (key_file_name); if (tempname == NULL) { qDebug("key_update:No a podido crear un fichero temporal para la clave"); fprintf(stderr, "A temporary file for key update could not be created.\n"); return; } if ((tfp = fopen (tempname, "w")) == NULL) { qDebug("key_update:No ha podido crear un key temporary file"); fprintf (stderr, "Can not open temporary key file %s for update\n", tempname); return; } for (s=otp_name; *s!='\0'; s++) if (islower(*s)) *s = toupper(*s); fprintf (tfp, "%s %ld\n", otp_name, offset); while (fgets (buffer, 80, fp) != NULL) { if (sscanf (buffer, "%s %ld\n", foundname, &foundlength) == 2) { for (s=foundname; *s!='\0'; s++) if (islower(*s)) *s = toupper(*s); if (strcmp (otp_name, foundname)) fprintf (tfp, "%s %ld\n", foundname, foundlength); } } fclose (tfp); fclose (fp); remove (key_file_name); rename (tempname, key_file_name); return; } long check_key (char *filename, long start) { char buffer[81]; char foundname[81]; char *cPointer; int i; long foundlength = 0; FILE *fp; qDebug("check_key:key_file_name=%s ", key_file_name); if ((fp = fopen (key_file_name, "r+")) == NULL){ qDebug("check_key:key_file_name=%s no lo ha podido abrir!!!", key_file_name); return start;} while (fgets (buffer, 80, fp) != NULL) { if ((i = sscanf (buffer, "%s %ld\n", foundname, &foundlength)) != 0) { if (!strcmp (filename, foundname)) { fclose (fp); if (i == 2) return foundlength; else return start; } } } fclose (fp); return start; }