#include <stdio.h>
#include <string.h>
/* https://www.cryptomuseum.com/crypto/franklin/spellmaster/code.htm */
/* definitions */
#define CODEWORDSIZE 8
#define WORDBUFSIZE 26
void StoreCodeWord(char *);
void InitCodeWord(void);
void init_decode_key(void);
void prepare_input(void);
void EncodeWord(void);
void DecodeWord(void);
void DoCipher(int dir);
/* global variables */
char CodeWord[CODEWORDSIZE + 1];
char WorkWord[WORDBUFSIZE + 1];
char word_buf[WORDBUFSIZE + 1];
char EncodeXlate[28] = {
7, /* 00 (A) */
14, /* 01 (B) */
22, /* 02 (C) */
0, /* 03 (D) */
18, /* 04 (E) */
12, /* 05 (F) */
9, /* 06 (G) */
17, /* 07 (H) */
13, /* 08 (I) */
4, /* 09 (J) */
3, /* 10 (K) */
6, /* 11 (L) */
1, /* 12 (M) */
23, /* 13 (N) */
10, /* 14 (O) */
19, /* 15 (P) */
2, /* 16 (Q) */
16, /* 17 (R) */
15, /* 18 (S) */
20, /* 19 (T) */
8, /* 20 (U) */
24, /* 21 (V) */
5, /* 22 (W) */
25, /* 23 (X) */
11, /* 24 (Y) */
21, /* 25 (Z) */
26, /* 26 ([) */
27, /* 27 (\) */
};
char DecodeXlate[28]; /* set up by init_decode_key */
void
StoreCodeWord(char *word)
{
int i, j = 0, length = strlen(word);
for (i = 0; i < CODEWORDSIZE; i++) {
char letter = word[j];
if (letter >= 'a' && letter <= 'z')
letter -= ('a' - 'A');
if (letter >= 'A' && letter <= 'Z') {
CodeWord[i] = letter;
} else {
i--;
}
j++;
if (j >= length)
j = 0;
}
CodeWord[CODEWORDSIZE] = '\0';
}
void
InitCodeWord(void)
{
StoreCodeWord("FRANKLIN");
}
void
EncodeWord(void)
{
DoCipher(0);
}
void
DecodeWord(void)
{
DoCipher(1);
}
void
prepare_input(void)
{
int i, length = strlen(word_buf);
for (i = 0; i < length; i++) {
if (word_buf[i] == '-' || word_buf[i] == ' ')
word_buf[i] = '[';
else if (word_buf[i] == '?')
word_buf[i] = '\\';
else if (word_buf[i] >= 'a' && word_buf[i] <= 'z')
word_buf[i] -= ('a' - 'A');
if (word_buf[i] > '\\' || word_buf[i] < 'A')
word_buf[i] = '[';
}
}
int
mod(int n, int m)
{
if (n > 0)
return n % m;
while (n < 0)
n += m;
return n;
}
void
DoCipher(int dir)
{
int i, j, length;
char tempcode[CODEWORDSIZE + 1];
length = strlen(word_buf);
/* Convert input text to 0-27 range */
for (i = 0; i < length; i++) {
if (dir == 0) {
word_buf[i] = EncodeXlate[word_buf[i] - 'A'];
} else {
word_buf[i] = word_buf[i] - 'A';
}
}
/* Take copy of the key */
(void) strcpy(tempcode, CodeWord);
/* Encrypt or decrypt the text */
for (i = 0; i < length; i++) {
signed char key = 0;
/* Calculate key */
for (j = 0; j < CODEWORDSIZE; j++) {
key += (tempcode[j] - 'A');
}
key = mod(key, 28);
/* Apply key */
WorkWord[i] = mod(key - word_buf[i], 28);
/* Modify key */
if (dir == 0) {
key = mod(key + word_buf[i], 28);
} else {
key = mod(key + WorkWord[i], 28);
}
for (j = 1; j < CODEWORDSIZE; j++) {
tempcode[j - 1] = tempcode[j];
}
tempcode[CODEWORDSIZE - 1] = key;
}
/* Convert result back to ASCII range */
for (i = 0; i < length; i++) {
if (dir == 0) {
WorkWord[i] += 'A';
} else {
WorkWord[i] = DecodeXlate[(int) WorkWord[i]] + 'A';
}
WorkWord[length] = '\0';
}
for (i = 0; i < length; i++) {
if (WorkWord[i] == '[')
WorkWord[i] = '-';
else if (WorkWord[i] == '\\')
WorkWord[i] = '?';
}
printf("%scoding result: %s\n", !dir ? "En" : "De", WorkWord);
}
void
init_decode_key(void)
{
int i, j;
for (i = 0; i < 28; i++) {
for (j = 0; j < 28; j++) {
if (EncodeXlate[j] == i)
break;
}
DecodeXlate[i] = j;
}
}
int
main(int argc, char **argv)
{
const char *const usage = "usage: %s [DE] [key] [plaintext]\n";
char key[CODEWORDSIZE + 1];
if (argc < 4) {
printf(usage, argv[0]);
return 0;
}
init_decode_key();
(void) strncpy(key, argv[2], CODEWORDSIZE);
StoreCodeWord(key);
(void) strncpy(word_buf, argv[3], WORDBUFSIZE);
prepare_input();
if (*argv[1] == 'D') {
DecodeWord();
} else if (*argv[1] == 'E') {
EncodeWord();
} else {
printf(usage, argv[0]);
return 0;
}
return 0;
|