/* Author: Pate Williams (c) 1997 Exercise 1.1 "Below are given four examples of cipehertext, one obtained from a Substitution Cipher, one from a Vigenere Cipher, one from an Affine Cipher, and one unspecified. In each case, the task is to determine the plaintext." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 40. */ #include #include #include #include struct code {double rfreq; long alpha, count;}; struct digram {double rfreq; long alpha1, alpha2, count;}; int main(void) { char cipher[11][24] = {"EMGLOSUDCGDNCUSWYSFHNSF", "CYKDPUMLWGYICOXYSIPJCK", "QPKUGKMGOLICGINCGACKSNI", "SACYKZSCKXECJCKSHYSXCG", "OIDPKZCNKSHICGIWYGKKGKG", "OLDSILKGOIUSIGLEDSPWZU", "GFZCCNDGYYSFUSZCNXEOJNC", "GYEOWEUPXEZGACGNFGLKNS", "ACIGOIYCKXCJUCIUZCFZCCN", "DGYYSFEUEKUZCSOCFZCCNC", "IACZEJNCSHFZEJZEGMXCYHC"}; char ch, ciphertext[500], lt_ch, rt_ch; char c_a, c_e, c_o, c_r, c_s, c_w; char answer[256], plaintext[500]; long frequency[26] = {0}, count = 0, i, j, k = 0, l; long di_freq[26][26] = {{0}}, d_count = 0, line; struct code t, c[26]; struct digram *d, dt; for (i = 0; i < 11; i++) { for (j = 0; j < strlen(cipher[i]); j++) { ch = ciphertext[count++] = cipher[i][j]; frequency[ch - 'A']++; } } for (i = 0; i < 26; i++) { c[i].alpha = i + 'A'; c[i].count = frequency[i]; } for (i = 0; i < 25; i++) for (j = i + 1; j < 26; j++) if (c[i].count < c[j].count) t = c[i], c[i] = c[j], c[j] = t; for (i = 0; i < 26; i++) { c[i].rfreq = c[i].count / (double) count; if (c[i].rfreq != 0.0) printf("%c %lf\n", c[i].alpha, c[i].rfreq); } lt_ch = ciphertext[0]; for (i = 1; i < count - 1; i++) { rt_ch = ciphertext[i]; di_freq[lt_ch - 'A'][rt_ch - 'A']++; lt_ch = rt_ch; } for (i = 0; i < 26; i++) for (j = 0; j < 26; j++) if (di_freq[i][j] != 0) d_count++; d = calloc(d_count, sizeof(struct digram)); for (i = 0; i < 26; i++) { for (j = 0; j < 26; j++) { if (di_freq[i][j] != 0) { d[k].alpha1 = i + 'A'; d[k].alpha2 = j + 'A'; d[k++].count = di_freq[i][j]; } } } for (i = 0; i < d_count - 1; i++) for (j = i + 1; j < d_count; j++) if (d[i].count < d[j].count) dt = d[i], d[i] = d[j], d[j] = dt; for (i = 0; i < d_count; i++) if (d[i].count != 0) printf("%3ld %c %c %ld\n", i, d[i].alpha1, d[i].alpha2, d[i].count); c_e = (char) c[0].alpha; c_a = (char) c[1].alpha; c_o = (char) c[2].alpha; c_r = (char) c[5].alpha; c_s = (char) c[3].alpha; c_w = 'F'; for (i = 0; i < count; i++) { ch = ciphertext[i]; if (ch == c_a) plaintext[i] = 'A'; else if (ch == c_e) plaintext[i] = 'E'; else if (ch == c_o) plaintext[i] = 'O'; else if (ch == c_r) plaintext[i] = 'R'; else if (ch == c_s) plaintext[i] = 'S'; else if (ch == c_w) plaintext[i] = 'W'; else plaintext[i] = '-'; } line = count / 25; if (line % 25 != 0) line++; do { i = j = 0; for (k = 0; k < line; k++) { printf("P: "); for (l = 0; l < 25; l++) if (i < count) printf("%c", plaintext[i++]); printf("\nC: "); for (l = 0; l < 25; l++) if (j < count) printf("%c", ciphertext[j++]); printf("\n"); } do { printf("Command: M(ap) Q(uit) U(nmap)? "); scanf("%s", answer); ch = (char) tolower(answer[0]); } while (ch != 'm' && ch != 'q' && ch != 'u'); if (ch != 'q') { if (ch == 'm') { printf("Ciphertext character: "); scanf("%s", answer); c_a = (char) toupper(answer[0]); printf("Plaintext character: "); scanf("%s", answer); c_e = (char) toupper(answer[0]); for (i = 0; i < count; i++) if (c_a == ciphertext[i]) plaintext[i] = c_e; } if (ch == 'u') { printf("Plaintext character: "); scanf("%s", answer); c_a = (char) toupper(answer[0]); for (i = 0; i < count; i++) if (c_a == plaintext[i]) plaintext[i] = '-'; } } } while (ch != 'q'); return 0; }