/* 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" columnar::columnar(){ *cipher = (char) NULL; period=0; maxcollen=0; length = 0; clen = NULL; block = NULL; period_set = FALSE; } int columnar::execute_option(char option){ int valid = TRUE; switch(option){ case UNDO: undo(); break; case MOVE: move_stuff(); break; case ALPHFIT: find_best_fit(); break; case ROTATE: rotate_key(); break; case CHANGEPERIOD: change_period(); break; default: valid = base_exec_option(option); break; } return valid; } void columnar::setup_key(){ int i; key.init(period); for(i = 0; i < period; i++){ key.alter(i+'a', i); } } void columnar::undo(){ setup_key(); fill_block(); } void columnar::change_period(){ int i; for(i = 0; i < period; i++) delete[] block[i]; delete[] block; block = NULL; delete[] clen; clen = NULL; period_set = FALSE; set_period(); init_cipher(); clear_to_prompt(); } void columnar::init_cipher(){ int i; length = strlen(cipher); delete[] clen; delete[] block; /* re-Allocate the block */ maxcollen = (length%period == 0)?length/period:length/period + 1; clen = new int[period]; block = new char *[period]; for(i = 0; i < period; i++) block[i] = new char[maxcollen]; /* Initilize the column lengths */ for(i = 0; i < period; i++){ if(period*(maxcollen-1) + i < length) clen[i] = maxcollen; else clen[i] = maxcollen-1; } /* Now fill in the block. */ fill_block(); } void columnar::fill_block(){ int i, maxlen, position; int *cptr, *tptr; char *cipherptr = cipher; /* Loop through each column */ for(i = 0; i < period; i++){ /* Find out which columns are associated with that rail */ cptr = find_columns(i); maxlen = 0; /* Find the length of the longest column */ for(tptr = cptr; *tptr >= 0; tptr++){ if(clen[*tptr] > maxlen) maxlen = clen[*tptr]; } /* Loop through each column and fill it */ position = 0; while(position < maxlen){ for(tptr = cptr; *tptr >= 0; tptr++){ if(position < clen[*tptr]){ block[*tptr][position] = *cipherptr; cipherptr++; } } position++; } } } int *columnar::find_columns(int index){ int i, position=0; static int *list=NULL; if(list != NULL){ delete[] list; } list = new int[period+1]; /* We are assuming that there is a variable (char *)key that has ** a list of non-negative integers. There is also a variable ** (int)period that gives the number of elements in key. */ for(i = 0; i < period; i++){ if(key.intval(i) == index){ list[position++] = i; } } list[position] = -1; return list; } void columnar::find_best_fit(){ /* FILE *fptr; char temp_str[STRINGLENGTH]; */ int counter = 0; Key maxkey; int i, value, maxval=0; key.duplicate(&maxkey); do{ counter++; fill_block(); for(i=1,value=0; i < period; i++){ value += get_digram_values(block[i-1], block[i]); } if(value > maxval){ show_cipher(); msgerror("%d -> %d", counter, value); maxval = value; key.duplicate(&maxkey); /* fptr = fopen("columnar.output", "a"); for(i = 0; i < period; i++){ sprintf(temp_str+3*i, "%02d,", maxkey[i]); } fprintf(fptr, "%d -> %d (%s)\n", counter, value, temp_str); fclose(fptr); */ } } while(key.advance()); maxkey.duplicate(&key); fill_block(); } /* int columnar::advance_key(){ char *pt1, *pt2, tval; int i; char string[STRINGLENGTH]; key.string(string); for(i = 1; i < period && string[i] < string[i-1]; i++); if(i < period){ pt1 = string+i; for(pt2 = pt1; pt2 != string && *(pt2-1) <= *pt1; pt2--); tval = *pt2; *pt2 = *pt1; *pt1 = tval; qsort((void *) string, (size_t) (pt1-string), sizeof(char), charcmp); } key.restore(string); */ /* This will be zero as soon as we are finished */ /* return period-i; } */ void columnar::show_menu(){ menu(1, "(M)ove columns (C)hange period (A)lphabet fit (U)ndo (W)rite (Q)uit"); } void columnar::show_cipher(){ int i, j, column, row; for(i = 0; i < period; i++){ /* Label the columns */ if((key.intval(i)+1)/10 > 0) put_char((key.intval(i)+1)/10+'0', i+3, 0); else put_char(BLANK, i+3, 0); put_char((key.intval(i)+1)%10+'0', i+3, 1); /* If the columns are too long then we have to continue them ** beside the first one. */ if(maxcollen > 16){ if((key.intval(i)+1)/10 > 0){ put_char((key.intval(i)+1)/10+'0', i+3+period+4, 0); } else{ put_char(BLANK, i+3+period+4, 0); } put_char((key.intval(i)+1)%10+'0', i+3+period+4, 1); } /* Now show the cipher */ for(j = 0; j < clen[i]; j++){ column = i+3; row = j+2; /* Do we have columns that are too long? */ if(row > 17){ row -= 16; column += period+4; } put_char(block[i][j], column, row); } } } void columnar::rotate_key(){ int i, amount; Key tkey; char temp_str[STRINGLENGTH]; prompt("Rotate by how much to the right? "); read_line(temp_str); if(sscanf(temp_str, "%d", &amount) != 1){ msgerror("Bad amount."); } else{ amount %= period; key.duplicate(&tkey); for(i = 0; i < period; i++){ key.alter(tkey.val((i+amount)%period), i); } fill_block(); } } void columnar::move_stuff(){ char temp_str[STRINGLENGTH]; int column1, column2, i; prompt("Interchange which two columns/rows? (ex: 1,2) "); read_line(temp_str); if(sscanf(temp_str, "%d,%d", &column1, &column2) != 2); else if(column1 <= period && column2 <= period && column1 > 0 && column2 > 0){ column1--, column2--; for(i = 0; i < period; i++){ if(key.intval(i) == column2) key.alter(column1+'a', i); else if(key.intval(i) == column1) key.alter(column2+'a', i); } fill_block(); } else{ msgerror("Bad column number."); } } void columnar::decipher(char *string){ int i, j; for(i = 0; i < maxcollen; i++){ for(j = 0; j < period; j++){ if(i < clen[j]) *string++ = block[j][i]; } } *string = (char) NULL; }