//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 /* idea128.c */ /* IDEA cipher: 128 bit key, 64 bit block */ /* CBF functions are implemented. */ /* Unless otherwise noted Copyright 1995 Willis E. Howard, III */ /* Willis E. Howard, III email: WEHoward@aol.com mail: POB 1473 Elkhart, IN 46515 */ /* under MSDOS, NMAKE /F IDEA.MAK all clean */ #include #include #include "crypt.h" #include "hex.h" #include "idea.h" #include "nhash.h" //#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. In this case, the name of the EXE file is IDEA.EXE because the module IDEA.C contains the main cipher. */ static int key_defined_idea = 0; /* Set to 1 after a valid key has been defined */ static int encrypt_or_decrypt_idea = ENCRYPTION_SELECT; static char key_string_idea[257]; static char actual_key_idea[16]; /* base key */ static struct IdeaCfbContext cfb; /* actual cfb */ void process_key_idea (char *, char *); /* 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", " The program uses the IDEA cipher (International Data", " Encryption Algorithm) formerly known as IPES.", " A 128 bit key is used to encrypt a 64 bit block.", "", " Because blocks of 8 bytes are processed, files that are not", " a multiple of 8 bytes long may increase slightly in size.", " Decrypted files may have additional spaces at the end.", " Use the -d option for decryption.", "", "KEY", " The key is an ASCII string. If you use more than one", " word in the phrase and give the key with the -k option", " on the command line, place the phrase within quotes.", " At most 256 characters will be used in the phrase.", " If the string evaluates to exactly 16 hex bytes such as", " \"F0AB 457E 006C E4AA 98B3 3A47 BCB5 C222\", but with", " all spaces ignored, then that exact 128 bit key is used.", " Otherwise, the ASCII characters are hashed to form a", " 128 bit key. A zero key will produce a warning message.", "", " If a key file exists, only the first line is read, and", " it is used as the key phrase.", "", " If there is no key phrase, you will be prompted for one.", NULL }; char ** crypt_help_idea () { 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 but exit on error. */ int crypt_key_idea (int key_type, char *key_text) { int i; char *s; FILE *fp; if (key_type == KEY_FILE) /* a file name has been given */ { if ((fp = fopen (key_text, "r")) == NULL) { key_defined_idea = 0; return 0; } s = key_string_idea; i = 0; for (;;) { *s = fgetc (fp); if ((*s == '\n') || (*s == EOF)) { *s = '\0'; if (i == 0) { key_defined_idea = 0; break; } else { process_key_idea (key_string_idea, actual_key_idea); key_defined_idea = 1; break; } } else if (i == 255) { *++s = '\0'; process_key_idea (key_string_idea, actual_key_idea); key_defined_idea = 1; 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_idea; i = 0; for (;;) { *s = fgetc (stdin); if ((*s == '\n') || (*s == EOF)) { *s = '\0'; process_key_idea (key_string_idea, actual_key_idea); key_defined_idea = 1; break; } else if (i == 255) { *++s = '\0'; process_key_idea (key_string_idea, actual_key_idea); key_defined_idea = 1; break; } s++; i++; } } else /* copy string up to 256 characters */ { strncpy (key_string_idea, key_text, 256); key_string_idea[256] = '\0'; process_key_idea (key_string_idea, actual_key_idea); key_defined_idea = 1; } return 0; } fprintf (stderr, "Error getting key\n"); exit (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_idea () { int i; for (i = 0; i < 257; i++) key_string_idea[i] = (char) (i & 0xff); for (i=0; i<16; i++) actual_key_idea[i] = 0; ideaCfbDestroy( &cfb ); key_defined_idea = 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_idea (int selection) { if (selection == ENCRYPTION_SELECT) { if (encrypt_or_decrypt_idea == DECRYPTION_SELECT) { encrypt_or_decrypt_idea = ENCRYPTION_SELECT; if (key_defined_idea) /* if we have a key, recalculate */ process_key_idea (key_string_idea, actual_key_idea); } } if (selection == DECRYPTION_SELECT) { if (encrypt_or_decrypt_idea == ENCRYPTION_SELECT) { encrypt_or_decrypt_idea = DECRYPTION_SELECT; if (key_defined_idea) /* if we have a key, recalculate */ process_key_idea (key_string_idea, actual_key_idea); } } return encrypt_or_decrypt_idea; } /* 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_idea (char *source, char *dest) { int i; int count = 8; /* block size */ char buffer[8]; FILE *infile; FILE *outfile; while (!key_defined_idea) crypt_key_idea (KEY_IMMEDIATE, "?"); if ((infile = fopen (source, "rb")) == NULL) { fprintf (stderr, "Can not open %s for reading.\n", source); return 1; } if ((outfile = fopen (dest, "wb")) == NULL) { fprintf (stderr, "Can not open %s for writing.\n", dest); fclose (infile); return 1; } for (i = 0; i < count; i++) buffer[i] = (char) 0x20; /* text files padded with spaces */ while (fread (buffer, sizeof (char), count, infile)) { if (encrypt_or_decrypt_idea == ENCRYPTION_SELECT) ideaCfbEncrypt(&cfb, (byte*)buffer,(byte*) buffer, 8); else if (encrypt_or_decrypt_idea == DECRYPTION_SELECT) ideaCfbDecrypt(&cfb,(byte*) buffer, (byte*)buffer, 8); if (count != fwrite (buffer, sizeof (char), count, outfile)) { fprintf (stderr, "Could not write to %s\n", source); fclose (infile); fclose (outfile); return 1; } else { for (i = 0; i < count; i++) buffer[i] = (char) 0x20; } } fclose (infile); fclose (outfile); return 0; } /* Convert a string to a key and check for weak keys */ void process_key_idea (char *s, char *key) { char string[257]; int i; int j; int block_count; int shift = 1; int value = 0; int hex_count = 0; int nonhex_count = 0; int white_count = 0; char init[16] = { 0xa1, 0x1f, 0x9d, 0x15, 0x3e, 0xdc, 0xeb, 0x85, 0xd0, 0x18, 0xc4, 0xbf, 0xb6, 0xf7, 0xa4, 0x9a }; for (i=0; i<257; i++) string[i] = '\0'; /* check for a hex number */ for (i = 0; (i < 256) && *s; i++) { string[i] = *s++; if (ishex (string[i])) hex_count++; else if (string[i] == ' ') white_count++; else nonhex_count++; } string[i] = '\0'; if (hex_count == 32 && nonhex_count == 0) { /* convert hex number */ hex_count = 0; for (i = 0; string[i] != '\0'; i++) { if ((value = hextoint (string[i])) != -1) { if (shift) { key[hex_count >> 1] = (unsigned char) value << 4; hex_count++; shift = 0; } else { key[hex_count >> 1] += (unsigned char) value; hex_count++; shift = 1; } } } } else if (!string[0]) { /* default key for no key phrase */ for (i=0; i<16; i++) key[i] = init[i]; } else { /* process ASCII string */ block_count = ( (strlen( string ) - 1 ) / 16 ) + 1; if (block_count > 16) block_count = 16; hash128 (block_count, (unsigned char*)string, (unsigned char*)init,(unsigned char*) key); } /* warn of weak keys */ value = 0; for (j = 0; j < 16; j++) if (!key[j]) value++; if (value == 16) fprintf (stderr, "A zero key has been detected.\n"); /* clear local copy of string */ for (i=0; i<256; i++) string[i] = '\0'; /* select the key for use */ ideaCfbInit( &cfb, (const byte*)key ); }