/* 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" aristocrat::aristocrat(){ ocipher = NULL; length = 0; num_lines = 0; key.init(26); valid_chars = "abcdefghijklmnopqrstuvwxyz -',.;"; } int aristocrat::execute_option(char option){ int valid = TRUE; switch(option){ case LOCATE: locate_tip(); break; case GROUPSUB: group_substitute(); break; case SUBSTITUTE: substitute(); break; case UNDO: undo(); break; default: valid = base_exec_option(option); break; } return valid; } void aristocrat::init_cipher(){ int pos=0, line = 0; int i, line_length; char *start, *end; line_length = (int) (.9*COLS); start = end = cipher; num_lines = (int) (length*2/line_length+1); ocipher = new char*[num_lines]; for(i = 0; i <= num_lines; i++){ ocipher[i] = new char[line_length+1]; } while(start - cipher < length){ while(*start == ' ') start++; end = start; while( (end - start < line_length) && (end < cipher+length) ) end++; if(end - start >= line_length){ while(*end-- != ' '); } for(pos = 0; start <= end;pos++, start++){ ocipher[line][pos] = *start; } ocipher[line][pos] = (char) NULL; line++; } for(i = line; i < num_lines; i++){ delete[] ocipher[i]; } ocipher[line] = NULL; num_lines = line; } int aristocrat::set_period(int newperiod){ return TRUE; } void aristocrat::show_menu(){ menu(1, "(S)ubstitute (G)roup sub (U)ndo (L)ocate tip (W)rite (Q)uit"); } void aristocrat::locate_tip(){ char temp_str[STRINGLENGTH], tip[STRINGLENGTH]; char *c; char tcipher[CLENGTH]; int startpos, i, j, valid = TRUE, tlen=0; Key tkey; key.duplicate(&tkey); for(i = 0; cipher[i]; i++){ if(isalpha(cipher[i])) tcipher[tlen++] = cipher[i]; } tcipher[tlen++] = (char) NULL; /* Get the start position from the user */ prompt("At which group would you like to start the search? "); read_line(temp_str); if( (c = strstr(tcipher, temp_str)) == NULL){ msgerror("Group %s does not exist.", temp_str); valid = FALSE; } /* Now get the tip */ else{ startpos = (int) (c - tcipher); prompt("What is the tip? "); read_line(temp_str); strcpy(tip, temp_str); if(strlen(tip) > tlen - startpos){ msgerror("Tip too long for that starting position."); valid = FALSE; } else{ /* Ok, we have a valid tip. Try to match it to every position ** until we find one that works. Start off with valid being FALSE ** so that the loop doesn't terminate right away. */ valid = BAD_SUB; for(i = startpos; i + strlen(tip) < tlen && valid != NEW_SUB; i++){ valid = NEW_SUB; /* See if the letter pattern in the tip matches the letter ** pattern being pointed to */ key.clearkey(); for(j = 0; tip[j] && valid == NEW_SUB; j++){ valid = key.alter(tcipher[i+j], key.index(tip[j])); } tkey.duplicate(&key); for(j = 0; tip[j] && valid == NEW_SUB; j++){ valid = key.alter(tip[j], key.index(tcipher[i+j])); } if(valid == NEW_SUB) msgerror("Location found!"); } if(valid != NEW_SUB){ tkey.duplicate(&key); } } } } void aristocrat::group_substitute(){ char word[STRINGLENGTH]; char dword[STRINGLENGTH]; Key tkey; int i, valid=TRUE; key.duplicate(&tkey); prompt("What is the ciphertext? "); read_line(dword); prompt("What is the plaintext? "); read_line(word); /* Are the strings the same length? */ if(strlen(word) != strlen(dword)){ valid = FALSE; } /* Convert the letters to lowercase and check for non-alphabetic ** characters */ for(i = 0; i < strlen(word); i++){ if(!isalpha(word[i]) || !isalpha(dword[i])){ valid = FALSE; } else{ word[i] |= ' '; dword[i] |= ' '; } } for(i = 0; i < strlen(word) && valid == TRUE; i++){ if(key.alter(word[i], key.index(dword[i])) != NEW_SUB) valid = FALSE; } if(valid == FALSE){ msgerror("Bad substitution."); tkey.duplicate(&key); } } void aristocrat::substitute(){ char ct_letter, pt_letter, c; int valid = TRUE; /* Get the encoded letter */ prompt("What is the encoded letter? "); ct_letter = get_char(); prompt("What is the decoded letter? "); pt_letter = get_char(); if(!isalpha(ct_letter) || !isalpha(pt_letter)){ msgerror("Bad letter."); } else { for(c = 'a'; c <= 'z' && valid; c++){ if(key.val(c) == pt_letter && ct_letter != c){ msgerror("'%c' already stands for '%c'.", c, pt_letter); valid = FALSE; } } if(valid){ if(key.alter(pt_letter, key.index(ct_letter)) == BAD_SUB){ msgerror("Caution: possible invalid substitution."); } } } } void aristocrat::undo(){ char ct_letter; prompt("What is the encoded letter? "); ct_letter = get_char(); if(ct_letter == '*'){ key.clearkey(); } else key.clearkey(ct_letter); } void aristocrat::show_cipher(){ char c; int line, i; for(line = 0; line < num_lines; line++){ for(i = 0; i < strlen(ocipher[line]); i++){ c = ocipher[line][i]; put_char(toupper(c), i, line*2+4); if(isalpha(c)){ put_char(key.val(c), i, line*2+3); } else{ put_char(c, i, line*2+3); } } } } void aristocrat::decipher(char *string){ int i=0; while(cipher[i]){ if(isalpha(cipher[i])) *string++ = key.val(cipher[i++]); else *string++ = cipher[i++]; } *string++ = (char) NULL; } void aristocrat::show_key(){ int i, j; int match_found = FALSE; msgprint(60, num_lines*2+5, "(K1)"); msgprint(60, num_lines*2+7, "(K2)"); msgprint(0, num_lines*2+5, "Pt: "); msgprint(0, num_lines*2+7, "Ct: "); /* Since most ACA arist/patris ciphers use K2 keyed alphabets we ** will save ourselves some work in keyword recovery if we ** print out both plaintext and ciphertext alphabets in normal order. ** Watch this: */ for(i = 0; i < 26; i++){ put_char(key.val(i), i*2+5, num_lines*2+5); put_char(i+'A', i*2+5, num_lines*2+6); match_found = FALSE; for(j = 0; j < 26; j++){ if(key.val(j) != BLANK && key.val(j) - 'a' == i){ put_char(j+'a', i*2+5, num_lines*2+7); match_found = TRUE; } } if(!match_found) put_char(BLANK, i*2+5, num_lines*2+7); } }