/* This is one of the cipher files for the cipher interface written ** by wart@ugcs.caltech.edu ** ** Please don't steal my code without my permission. ** */ #include #include #include #include #include "term.h" #include "types.h" #include "ctypes.h" #define DOT '.' #define DASH '-' #define SPC 'x' morse::morse(){ period=0; *cipher = (char) NULL; keylen = 0; } fmorse::fmorse(){ keylen = 26; valid_chars = "abcdefghijklmnopqrstuvwxyz"; key.init(26); } morbit::morbit(){ valid_chars = "123456789"; keylen = 9; key.init(9); } pollux::pollux(){ valid_chars = "1234567890"; keylen = 10; max_value = 0; key.init(10); maxkey.init(10); } int morse::execute_option(char option){ int valid = TRUE; switch(option){ case ALPHFIT: solve(); break; case SUBSTITUTE: substitute(); break; case UNDO: undo(); break; default: valid = base_exec_option(option); break; } return valid; } int morse::period_valid(){ return TRUE; } int pollux::set_period(int newperiod=0){ if(period_set == FALSE){ keylen = 10; period = 1; period_set = TRUE; } return period_set; } int morbit::set_period(int newperiod=0){ if(period_set == FALSE){ keylen = 9; period = 2; period_set = TRUE; } return period_set; } int fmorse::set_period(int newperiod=0){ if(period_set == FALSE){ keylen = 26; period = 3; period_set = TRUE; } return period_set; } void morbit::solve(){ char temp_cipher[CLENGTH*4]; char temp_str[STRINGLENGTH]; int counter=0; Key maxkey; int i, value, maxval=0; key.duplicate(&maxkey); for(i = 0; i < keylen; i++){ do_sub(i+'1', i); } do{ temp_cipher[0] = (char) NULL; for(i = 0; i < length; i++) strcat(temp_cipher, get_morse(cipher[i])); /* Every n combinations print a space so that we can see ** that the computer is still working. */ if(counter % 5180 == 0){ strcpy(temp_str, "Solving."); for(i = 0; i < counter/5180; i++){ strcat(temp_str, "."); } msgerror(temp_str); } counter++; if(is_valid_spc_dist(temp_cipher)){ decipher(temp_cipher); for(i = 0, value=0; i < length-1; i++){ value += get_digram_value(temp_cipher[i], temp_cipher[i+1]); } if(value >= maxval){ show_cipher(); show_key(); maxval = value; key.duplicate(&maxkey); } } } while(key.advance()); maxkey.duplicate(&key); } void pollux::solve(){ char temp_str[CLENGTH], temp_cipher[CLENGTH]; int combo = 0, i; int index; for(index = 0; index < 1023; index++){ key.alter((index & (int) 0x001)?'c':'b', 0); key.alter((index & (int) 0x002)?'c':'b', 1); key.alter((index & (int) 0x004)?'c':'b', 2); key.alter((index & (int) 0x008)?'c':'b', 3); key.alter((index & (int) 0x010)?'c':'b', 4); key.alter((index & (int) 0x020)?'c':'b', 5); key.alter((index & (int) 0x040)?'c':'b', 6); key.alter((index & (int) 0x080)?'c':'b', 7); key.alter((index & (int) 0x100)?'c':'b', 8); key.alter((index & (int) 0x200)?'c':'b', 9); temp_str[0] = temp_cipher[0] = (char) NULL; for(i = 0, temp_cipher[0]=(char) NULL; i < length; i++){ strcat(temp_cipher, get_morse(cipher[i])); } if(is_valid_spc_dist(temp_cipher)){ combo++; for(i = 0; i < 10; i++){ if(key.intval(i) != morse2num("x")){ key.alter((char)morse2num(".")+'a', i); } } key.duplicate(&tkey); /* To solve, find the best digram fit. */ rec_digram_fit(0); } } /* Reset the key to blanks if no valid combo was found. */ maxkey.duplicate(&key); if(combo == 0){ msgerror("No matches found."); key.clearkey(); } } void pollux::rec_digram_fit(int pos){ int i, value; char temp_cipher[CLENGTH]; /* Shall we count the number of valid words? */ if(pos == 10){ /* First, convert this combination of .-x to words. */ for(i = 0, temp_cipher[0] = (char) NULL; i < length; i++){ strcat(temp_cipher, get_morse(cipher[i])); } decipher(temp_cipher); /* Find the digram value for this cipher. */ for(i=0, value=0; i < strlen(temp_cipher); i++){ value += get_digram_value(temp_cipher[i], temp_cipher[i+1]); } if(value > max_value){ show_cipher(); show_key(); max_value = value; key.duplicate(&maxkey); } } /* Otherwise just advance the key */ else{ if(tkey.intval(pos) == (int)morse2num("x")){ rec_digram_fit(pos+1); } else{ for(key.alter('a', pos); key.val(pos) != 'c'; key.alter(key.val(pos)+1, pos)) rec_digram_fit(pos+1); } } } inline int morse::is_valid_spc_dist(const char *message){ int valid = TRUE; char *c, *d; /* Are there three or more x's in a row? */ if(strstr(message, "xxx")) valid = FALSE; /* Are there any sequences that are > 6 characters? */ c = strchr(message, 'x'); if(!c) valid = FALSE; while (c && valid){ d = strchr(c+1, 'x'); if(!d){ if(strlen(message) - (c - message) > 6) valid = FALSE; } else if(d - c > 6) { valid = FALSE; } c = strchr(c+1, 'x'); } return valid; } void morse::substitute(){ char temp_str[STRINGLENGTH]; char letter; int number; prompt("What is the character? "); letter = get_char(); prompt("What is the pattern to replace it? "); read_line(temp_str); /* Enter a number for using a preset pattern */ if(sscanf(temp_str, "%d", &number) != 1){ msgerror("Bad input."); } else{ do_sub(letter, number-1); } } void pollux::substitute(){ char number, symbol[2]; char value; prompt("What is the number? "); number = get_char(); prompt("What is the pattern to replace it? "); symbol[0] = get_char(); symbol[1] = (char) NULL; if(symbol[0] != DOT && symbol[0] != DASH && symbol[0] != SPC) msgerror("Invalid symbol."); else if(number -'0' > keylen || number - '0' < 0) msgerror("Invalid character."); else{ value = (char)morse2num(symbol)+'a'; key.alter(value, key.index(number)); } } void morse::do_sub(char letter, int number){ int i; if(!isdigit(letter)) msgerror("Bad input."); else{ for(i = 0; i < keylen; i++){ if(key.val(i) == number){ key.clearkey(i); } } key.alter((char)number+'a', letter-'1'); } } void fmorse::do_sub(char letter, int number){ int i; if(!isalpha(letter)){ msgerror("Bad input."); } else{ for(i = 0; i < keylen; i++){ if(key.intval(i) == number){ key.clearkey(i); } } key.alter((char)number+'a', key.index(letter)); } } int morse::valid_pattern(char *pattern){ int valid = TRUE; int i; if(strlen(pattern) > period) valid = FALSE; else for(i = 0; i < period; i++){ if(pattern[i] != DASH && pattern[i] != DOT && pattern[i] != SPC && pattern[i] != BLANK) valid = FALSE; } if(strstr(pattern, "xxx")) valid = FALSE; return valid; } void pollux::show_menu(){ menu(1, "(S)ubstitute (A)pply best fit (U)ndo (W)rite (Q)uit"); } void morbit::show_menu(){ menu(1, "(S)ubstitute (A)pply best fit (U)ndo (W)rite (Q)uit"); } void fmorse::show_menu(){ menu(1, "(S)ubstitute (U)ndo (W)rite (Q)uit"); } void morse::show_cipher(){ char temp_cipher[CLENGTH]; char temp_str[CLENGTH]; int npl, i; *temp_cipher = (char) NULL; npl = (int) (SCREENWIDTH * .9) / (period); for(i = 0; i < length; i++){ /* First show the cipher characters */ msgprint((i%npl)*(period), (i/npl)*2+1, "%-*c", period, toupper(cipher[i])); /* Now the morse... */ strcpy(temp_str, get_morse(cipher[i])); if(!empty_string(temp_str)) msgprint((i%npl)*(period), (i/npl)*2+1, "%s", temp_str); /* Keep track of the entire deciphering string so that we can ** decipher it later. */ strcat(temp_cipher, temp_str); } /* Now translate the morse code and print it out */ decrypt(temp_cipher); for(i = 0; temp_cipher[i]; i++) put_char(temp_cipher[i], (i%(npl*period)), (i/(npl*period))*2); } int morse::empty_string(char *string){ return (int) strchr(string, BLANK); } void morse::decrypt(char *message){ char *start, *end, letter; char temp_str[CLENGTH]; int pos; start = end = message; while(*start){ /* Set start to end and look for the next letter. */ start = end; /* Increment end until it points to the next 'x' and copy the ** characters in the middle into a buffer. */ pos = 0; while(*end && *end != SPC){ temp_str[pos++] = *end; *end = BLANK; end++; } if(*end) *end = BLANK; temp_str[pos] = (char) NULL; /* Now translate the buffer into morse code */ letter = morse2roman(temp_str); if(!letter) letter = BLANK; /* Now replace the character at the end position with the roman ** letter. */ *(end-1) = letter; /* if(start != message) start--; while(start < end-1){ *start = BLANK; start++; } */ end++; start = end; } } char morse::morse2roman(char *message){ char value = (char) NULL; int i; static char *morsenum[] = { "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."}; static char *morsealph[] = { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."}; if(! *message) value = '_'; /* Is it a letter? */ for(i = 0; i < 26; i++){ if(strcmp(message, morsealph[i]) == 0){ value = i+'a'; } } /* Is it a number? */ for(i = 0; i < 10; i++){ if(strcmp(message, morsenum[i]) == 0){ value = i+'0'; } } /* Is it some other character? */ if(strcmp(message, ".-.-.-") == 0) value = '.'; else if(strcmp(message, "--..--") == 0) value = ','; else if(strcmp(message, "---...") == 0) value = ':'; else if(strcmp(message, "-.-.-.") == 0) value = ';'; else if(strcmp(message, "-....-") == 0) value = '-'; else if(strcmp(message, ".----.") == 0) value = '\''; else if(strcmp(message, "-..-.") == 0) value = '/'; else if(strcmp(message, "-...-") == 0) value = '='; return value; } void pollux::show_key(){ int i; for(i = 0; i < keylen; i++){ msgprint(i*2, 19, "%d", i); if(key.val(i) != BLANK) put_char(*num2morse(key.intval(i)), i*2, 20); else put_char(BLANK, i*2, 20); } } void morbit::show_key(){ int i, j; char *string; for(i = 0; i < keylen; i++){ msgprint(i*2, 13, "%d", i+1); string = strdup(num2morse(i)); put_char(string[0], i*2, 14); put_char(string[1], i*2, 15); put_char(BLANK, i*2, 16); for(j = 0; j < keylen; j++){ if(key.intval(j) == i){ put_char(j+'1', i*2, 16); } } (void) free(string); } } void fmorse::show_key(){ int i, j; char *string; for(i = 0; i < keylen; i++){ msgprint(i*3, 15, "%2d", i+1); string = strdup(num2morse(i)); put_char(string[0], i*3+1, 16); put_char(string[1], i*3+1, 17); put_char(string[2], i*3+1, 18); put_char(BLANK, i*3+1, 19); for(j = 0; j < keylen; j++){ if(key.intval(j) == i) put_char(j+'a', i*3+1, 19); } (void)free(string); } } char *morse::get_morse(char value){ if(key.val(value) == BLANK) return num2morse(-1); else return num2morse(key.intval(value)); } char *morbit::get_morse(char value){ if(key.val((char) (value-1)) == BLANK) return num2morse(-1); else return num2morse(key.intval((char) (value-1))); } char *morse::num2morse(int index){ char temp_str[10] = " "; int pos=period-1, i; for(i = 0; i < period; i++){ switch(index%3){ case 0: temp_str[pos] = DOT; break; case 1: temp_str[pos] = DASH; break; case 2: temp_str[pos] = SPC; break; } index /= 3; pos--; } temp_str[period] = (char) NULL; return temp_str; } int morse::morse2num(char *string){ int value=0, mult; int pos=0; mult = 1; while(pos < period){ switch(string[period-1-pos]){ case BLANK: break; case DOT: break; case DASH: value += mult*1; break; case SPC: value += mult*2; break; } pos++; mult *= 3; } return value; } void pollux::undo(){ char number; prompt("Undo which character? "); number = get_char(); if(number == '*'){ key.clearkey(); } else if(number < '0' || number > '9') msgerror("Bad value."); else key.clearkey(number); } void morbit::undo(){ int number; prompt("Undo which character? "); number = get_char(); if(number == '*'){ key.clearkey(); } else if(number < '1' || number > keylen+'0') msgerror("Bad value."); else key.clearkey(number - '1'); } void fmorse::undo(){ char letter; prompt("Undo which character? "); letter = get_char(); if(letter == '*'){ key.clearkey(); } else if(!isalpha(letter)){ msgerror("Bad value."); } else{ letter |= ' '; key.clearkey(letter); } } void morse::decipher(char *string){ int i; char temp_str[CLENGTH]; *string = (char) NULL; *temp_str = (char) NULL; for(i = 0; i < length; i++) strcat(temp_str, get_morse(cipher[i])); decrypt(temp_str); /* Now remove all the spaces */ for(i = 0; i < strlen(temp_str); i++){ if(temp_str[i] == '_') *string++ = BLANK; else if(temp_str[i] == '.'){ if(*(string-1) == ' '){ *(string-1) = '.'; *string++ = ' '; } } else if(temp_str[i] != BLANK){ *string++ = temp_str[i]; } } *string = (char) NULL; }